Skip to content

Commit 92deae1

Browse files
authored
Merge pull request #413 from graphql-java-kickstart/405-upgrade-to-graphql-java-15
405 upgrade to graphql java 15
2 parents 313afc5 + 78edf92 commit 92deae1

File tree

10 files changed

+330
-222
lines changed

10 files changed

+330
-222
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<groupId>com.graphql-java-kickstart</groupId>
66
<artifactId>graphql-java-tools</artifactId>
7-
<version>6.1.1-SNAPSHOT</version>
7+
<version>6.2.0-SNAPSHOT</version>
88
<packaging>jar</packaging>
99

1010
<name>GraphQL Java Tools</name>
@@ -17,7 +17,7 @@
1717
<kotlin.version>1.3.70</kotlin.version>
1818
<kotlin-coroutines.version>1.2.1</kotlin-coroutines.version>
1919
<jackson.version>2.10.3</jackson.version>
20-
<graphql-java.version>14.1</graphql-java.version>
20+
<graphql-java.version>15.0</graphql-java.version>
2121

2222
<maven.compiler.source>${java.version}</maven.compiler.source>
2323
<maven.compiler.target>${java.version}</maven.compiler.target>

src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ internal class SchemaClassScanner(
147147
val scalars = scalarDefinitions
148148
.filter {
149149
// Filter for any defined scalars OR scalars that aren't defined but also aren't standard
150-
scalars.containsKey(it.name) || !ScalarInfo.STANDARD_SCALAR_DEFINITIONS.containsKey(it.name)
150+
scalars.containsKey(it.name) || !ScalarInfo.GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.containsKey(it.name)
151151
}.map { definition ->
152152
val provided = scalars[definition.name]
153153
?: throw SchemaClassScannerError("Expected a user-defined GraphQL scalar type with name '${definition.name}' but found none!")
@@ -322,7 +322,7 @@ internal class SchemaClassScanner(
322322
is InputObjectTypeDefinition -> {
323323
graphQLType.inputValueDefinitions.forEach { inputValueDefinition ->
324324
val inputGraphQLType = inputValueDefinition.type.unwrap()
325-
if (inputGraphQLType is TypeName && !ScalarInfo.STANDARD_SCALAR_DEFINITIONS.containsKey(inputGraphQLType.name)) {
325+
if (inputGraphQLType is TypeName && !ScalarInfo.GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.containsKey(inputGraphQLType.name)) {
326326
val inputValueJavaType = findInputValueType(inputValueDefinition.name, inputGraphQLType, javaType.unwrap())
327327
if (inputValueJavaType != null) {
328328
handleFoundType(typeClassMatcher.match(TypeClassMatcher.PotentialMatch.parameterType(

src/main/kotlin/graphql/kickstart/tools/SchemaParser.kt

Lines changed: 92 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package graphql.kickstart.tools
22

3+
import graphql.Scalars
34
import graphql.introspection.Introspection
45
import graphql.kickstart.tools.directive.SchemaGeneratorDirectiveHelper
56
import graphql.kickstart.tools.util.getExtendedFieldDefinitions
@@ -11,7 +12,6 @@ import graphql.schema.idl.ScalarInfo
1112
import graphql.schema.idl.SchemaGeneratorHelper
1213
import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility
1314
import org.slf4j.LoggerFactory
14-
import java.util.*
1515
import kotlin.reflect.KClass
1616

1717
/**
@@ -129,7 +129,7 @@ class SchemaParser internal constructor(
129129
.definition(objectDefinition)
130130
.description(if (objectDefinition.description != null) objectDefinition.description.content else getDocumentation(objectDefinition))
131131

132-
builder.withDirectives(*buildDirectives(objectDefinition.directives, setOf(), Introspection.DirectiveLocation.OBJECT))
132+
builder.withDirectives(*buildDirectives(objectDefinition.directives, Introspection.DirectiveLocation.OBJECT))
133133

134134
objectDefinition.implements.forEach { implementsDefinition ->
135135
val interfaceName = (implementsDefinition as TypeName).name
@@ -160,19 +160,6 @@ class SchemaParser internal constructor(
160160
return schemaGeneratorDirectiveHelper.onObject(objectType, directiveHelperParameters)
161161
}
162162

163-
private fun buildDirectives(directives: List<Directive>, directiveDefinitions: Set<GraphQLDirective>, directiveLocation: Introspection.DirectiveLocation): Array<GraphQLDirective> {
164-
val names = HashSet<String>()
165-
166-
val output = ArrayList<GraphQLDirective>()
167-
for (directive in directives) {
168-
if (!names.contains(directive.name)) {
169-
names.add(directive.name)
170-
output.add(schemaGeneratorHelper.buildDirective(directive, directiveDefinitions, directiveLocation, runtimeWiring.comparatorRegistry))
171-
}
172-
}
173-
return output.toTypedArray()
174-
}
175-
176163
private fun createInputObject(definition: InputObjectTypeDefinition, inputObjects: List<GraphQLInputObjectType>): GraphQLInputObjectType {
177164
val extensionDefinitions = inputExtensionDefinitions.filter { it.name == definition.name }
178165

@@ -182,17 +169,17 @@ class SchemaParser internal constructor(
182169
.extensionDefinitions(extensionDefinitions)
183170
.description(if (definition.description != null) definition.description.content else getDocumentation(definition))
184171

185-
builder.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.INPUT_OBJECT))
172+
builder.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.INPUT_OBJECT))
186173

187174
(extensionDefinitions + definition).forEach {
188175
it.inputValueDefinitions.forEach { inputDefinition ->
189176
val fieldBuilder = GraphQLInputObjectField.newInputObjectField()
190-
.name(inputDefinition.name)
191-
.definition(inputDefinition)
192-
.description(if (inputDefinition.description != null) inputDefinition.description.content else getDocumentation(inputDefinition))
193-
.defaultValue(buildDefaultValue(inputDefinition.defaultValue))
194-
.type(determineInputType(inputDefinition.type, inputObjects))
195-
.withDirectives(*buildDirectives(inputDefinition.directives, setOf(), Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION))
177+
.name(inputDefinition.name)
178+
.definition(inputDefinition)
179+
.description(if (inputDefinition.description != null) inputDefinition.description.content else getDocumentation(inputDefinition))
180+
.defaultValue(buildDefaultValue(inputDefinition.defaultValue))
181+
.type(determineInputType(inputDefinition.type, inputObjects))
182+
.withDirectives(*buildDirectives(inputDefinition.directives, Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION))
196183
builder.field(fieldBuilder.build())
197184
}
198185
}
@@ -211,14 +198,14 @@ class SchemaParser internal constructor(
211198
.definition(definition)
212199
.description(if (definition.description != null) definition.description.content else getDocumentation(definition))
213200

214-
builder.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.ENUM))
201+
builder.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.ENUM))
215202

216203
definition.enumValueDefinitions.forEach { enumDefinition ->
217204
val enumName = enumDefinition.name
218205
val enumValue = type.unwrap().enumConstants.find { (it as Enum<*>).name == enumName }
219206
?: throw SchemaError("Expected value for name '$enumName' in enum '${type.unwrap().simpleName}' but found none!")
220207

221-
val enumValueDirectives = buildDirectives(enumDefinition.directives, setOf(), Introspection.DirectiveLocation.ENUM_VALUE)
208+
val enumValueDirectives = buildDirectives(enumDefinition.directives, Introspection.DirectiveLocation.ENUM_VALUE)
222209
getDeprecated(enumDefinition.directives).let {
223210
val enumValueDefinition = GraphQLEnumValueDefinition.newEnumValueDefinition()
224211
.name(enumName)
@@ -243,7 +230,7 @@ class SchemaParser internal constructor(
243230
.definition(interfaceDefinition)
244231
.description(if (interfaceDefinition.description != null) interfaceDefinition.description.content else getDocumentation(interfaceDefinition))
245232

246-
builder.withDirectives(*buildDirectives(interfaceDefinition.directives, setOf(), Introspection.DirectiveLocation.INTERFACE))
233+
builder.withDirectives(*buildDirectives(interfaceDefinition.directives, Introspection.DirectiveLocation.INTERFACE))
247234

248235
interfaceDefinition.fieldDefinitions.forEach { fieldDefinition ->
249236
builder.field { field -> createField(field, fieldDefinition, inputObjects) }
@@ -259,7 +246,7 @@ class SchemaParser internal constructor(
259246
.definition(definition)
260247
.description(if (definition.description != null) definition.description.content else getDocumentation(definition))
261248

262-
builder.withDirectives(*buildDirectives(definition.directives, setOf(), Introspection.DirectiveLocation.UNION))
249+
builder.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.UNION))
263250

264251
getLeafUnionObjects(definition, types).forEach { builder.possibleType(it) }
265252
return schemaGeneratorDirectiveHelper.onUnion(builder.build(), schemaDirectiveParameters)
@@ -286,25 +273,95 @@ class SchemaParser internal constructor(
286273
}
287274

288275
private fun createField(field: GraphQLFieldDefinition.Builder, fieldDefinition: FieldDefinition, inputObjects: List<GraphQLInputObjectType>): GraphQLFieldDefinition.Builder {
289-
field.name(fieldDefinition.name)
290-
field.description(if (fieldDefinition.description != null) fieldDefinition.description.content else getDocumentation(fieldDefinition))
291-
field.definition(fieldDefinition)
292-
getDeprecated(fieldDefinition.directives)?.let { field.deprecate(it) }
293-
field.type(determineOutputType(fieldDefinition.type, inputObjects))
276+
field
277+
.name(fieldDefinition.name)
278+
.description(fieldDefinition.description?.content ?: getDocumentation(fieldDefinition))
279+
.definition(fieldDefinition)
280+
.apply { getDeprecated(fieldDefinition.directives)?.let { deprecate(it) } }
281+
.type(determineOutputType(fieldDefinition.type, inputObjects))
282+
294283
fieldDefinition.inputValueDefinitions.forEach { argumentDefinition ->
295284
val argumentBuilder = GraphQLArgument.newArgument()
296285
.name(argumentDefinition.name)
297286
.definition(argumentDefinition)
298287
.description(if (argumentDefinition.description != null) argumentDefinition.description.content else getDocumentation(argumentDefinition))
299-
.defaultValue(buildDefaultValue(argumentDefinition.defaultValue))
300288
.type(determineInputType(argumentDefinition.type, inputObjects))
301-
.withDirectives(*buildDirectives(argumentDefinition.directives, setOf(), Introspection.DirectiveLocation.ARGUMENT_DEFINITION))
289+
.apply { buildDefaultValue(argumentDefinition.defaultValue)?.let { defaultValue(it) } }
290+
.withDirectives(*buildDirectives(argumentDefinition.directives, Introspection.DirectiveLocation.ARGUMENT_DEFINITION))
291+
302292
field.argument(argumentBuilder.build())
303293
}
304-
field.withDirectives(*buildDirectives(fieldDefinition.directives, setOf(), Introspection.DirectiveLocation.FIELD_DEFINITION))
294+
field.withDirectives(*buildDirectives(fieldDefinition.directives, Introspection.DirectiveLocation.FIELD_DEFINITION))
295+
305296
return field
306297
}
307298

299+
private fun buildDirectives(directives: List<Directive>, directiveLocation: Introspection.DirectiveLocation): Array<GraphQLDirective> {
300+
val names = mutableSetOf<String>()
301+
302+
val output = mutableListOf<GraphQLDirective>()
303+
for (directive in directives) {
304+
if (!names.contains(directive.name)) {
305+
names.add(directive.name)
306+
val graphQLDirective = GraphQLDirective.newDirective()
307+
.name(directive.name)
308+
.apply {
309+
directive.arguments.forEach { arg ->
310+
argument(GraphQLArgument.newArgument()
311+
.name(arg.name)
312+
.type(buildDirectiveInputType(arg.value))
313+
.build())
314+
}
315+
}
316+
.build()
317+
318+
319+
output.add(schemaGeneratorHelper.buildDirective(directive, setOf(graphQLDirective), directiveLocation, runtimeWiring.comparatorRegistry))
320+
}
321+
}
322+
323+
return output.toTypedArray()
324+
}
325+
326+
private fun buildDirectiveInputType(value: Value<*>): GraphQLInputType? {
327+
when (value) {
328+
is NullValue -> return Scalars.GraphQLString
329+
is FloatValue -> return Scalars.GraphQLFloat
330+
is StringValue -> return Scalars.GraphQLString
331+
is IntValue -> return Scalars.GraphQLInt
332+
is BooleanValue -> return Scalars.GraphQLBoolean
333+
is ArrayValue -> return GraphQLList.list(buildDirectiveInputType(getArrayValueWrappedType(value)))
334+
else -> throw SchemaError("Directive values of type '${value::class.simpleName}' are not supported yet.")
335+
}
336+
}
337+
338+
private fun getArrayValueWrappedType(value: ArrayValue): Value<*> {
339+
// empty array [] is equivalent to [null]
340+
if (value.values.isEmpty()) {
341+
return NullValue.newNullValue().build()
342+
}
343+
344+
// get rid of null values
345+
val nonNullValueList = value.values.filter { v -> v !is NullValue }
346+
347+
// [null, null, ...] unwrapped is null
348+
if (nonNullValueList.isEmpty()) {
349+
return NullValue.newNullValue().build()
350+
}
351+
352+
// make sure the array isn't polymorphic
353+
val distinctTypes = nonNullValueList
354+
.map { it::class.java }
355+
.distinct()
356+
357+
if (distinctTypes.size > 1) {
358+
throw SchemaError("Arrays containing multiple types of values are not supported yet.")
359+
}
360+
361+
// peek at first value, value exists and is assured to be non-null
362+
return nonNullValueList[0]
363+
}
364+
308365
private fun buildDefaultValue(value: Value<*>?): Any? {
309366
return when (value) {
310367
null -> null
@@ -406,4 +463,4 @@ class SchemaParser internal constructor(
406463

407464
class SchemaError(message: String, cause: Throwable? = null) : RuntimeException(message, cause)
408465

409-
val graphQLScalars = ScalarInfo.STANDARD_SCALARS.associateBy { it.name }
466+
val graphQLScalars = ScalarInfo.GRAPHQL_SPECIFICATION_SCALARS.associateBy { it.name }

src/main/kotlin/graphql/kickstart/tools/SchemaParserBuilder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class SchemaParserBuilder {
169169
files.forEach { documents.add(parser.parseDocument(readFile(it), it)) }
170170

171171
if (schemaString.isNotEmpty()) {
172-
documents.add(parser.parseDocument(this.schemaString.toString()))
172+
documents.add(parser.parseDocument(schemaString.toString()))
173173
}
174174
} catch (pce: ParseCancellationException) {
175175
val cause = pce.cause

src/main/kotlin/graphql/kickstart/tools/TypeClassMatcher.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ internal class TypeClassMatcher(private val definitionsByName: Map<String, TypeD
8080
}
8181

8282
is TypeName -> {
83-
val typeDefinition = ScalarInfo.STANDARD_SCALAR_DEFINITIONS[graphQLType.name]
83+
val typeDefinition = ScalarInfo.GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS[graphQLType.name]
8484
?: definitionsByName[graphQLType.name]
8585
?: throw error(potentialMatch, "No ${TypeDefinition::class.java.simpleName} for type name ${graphQLType.name}")
8686
if (typeDefinition is ScalarTypeDefinition) {

src/main/kotlin/graphql/kickstart/tools/directive/SchemaDirectiveWiringEnvironmentImpl.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
/*
1818
* DO NOT EDIT THIS FILE!
1919
*
20-
* File copied from com.graphql-java.graphql-java:14.0 without changes.
20+
* File copied from com.graphql-java.graphql-java:15.0 without any changes.
2121
*/
2222
@Internal
2323
public class SchemaDirectiveWiringEnvironmentImpl<T extends GraphQLDirectiveContainer> implements SchemaDirectiveWiringEnvironment<T> {
@@ -113,15 +113,15 @@ public GraphQLFieldDefinition getFieldDefinition() {
113113

114114
@Override
115115
public DataFetcher getFieldDataFetcher() {
116-
assertNotNull(fieldDefinition, "An output field must be in context to call this method");
117-
assertNotNull(fieldsContainer, "An output field container must be in context to call this method");
116+
assertNotNull(fieldDefinition, () -> "An output field must be in context to call this method");
117+
assertNotNull(fieldsContainer, () -> "An output field container must be in context to call this method");
118118
return codeRegistry.getDataFetcher(fieldsContainer, fieldDefinition);
119119
}
120120

121121
@Override
122122
public GraphQLFieldDefinition setFieldDataFetcher(DataFetcher newDataFetcher) {
123-
assertNotNull(fieldDefinition, "An output field must be in context to call this method");
124-
assertNotNull(fieldsContainer, "An output field container must be in context to call this method");
123+
assertNotNull(fieldDefinition, () -> "An output field must be in context to call this method");
124+
assertNotNull(fieldsContainer, () -> "An output field container must be in context to call this method");
125125

126126
FieldCoordinates coordinates = FieldCoordinates.coordinates(fieldsContainer, fieldDefinition);
127127
codeRegistry.dataFetcher(coordinates, newDataFetcher);

0 commit comments

Comments
 (0)