Skip to content

Commit 017ed6c

Browse files
authored
Merge pull request #708 from graphql-java-kickstart/bugfix/695
Bugfix/695 - Old-style directives get lost
2 parents b832167 + a7c1452 commit 017ed6c

File tree

4 files changed

+174
-103
lines changed

4 files changed

+174
-103
lines changed

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

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

33
import graphql.introspection.Introspection
4+
import graphql.introspection.Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION
45
import graphql.kickstart.tools.directive.DirectiveWiringHelper
56
import graphql.kickstart.tools.util.getDocumentation
67
import graphql.kickstart.tools.util.getExtendedFieldDefinitions
@@ -122,28 +123,31 @@ class SchemaParser internal constructor(
122123
.definition(objectDefinition)
123124
.description(getDocumentation(objectDefinition, options))
124125
.withAppliedDirectives(*buildAppliedDirectives(objectDefinition.directives))
125-
126-
objectDefinition.implements.forEach { implementsDefinition ->
127-
val interfaceName = (implementsDefinition as TypeName).name
128-
builder.withInterface(interfaces.find { it.name == interfaceName }
129-
?: throw SchemaError("Expected interface type with name '$interfaceName' but found none!"))
130-
}
131-
132-
objectDefinition.getExtendedFieldDefinitions(extensionDefinitions).forEach { fieldDefinition ->
133-
builder.field { field ->
134-
createField(field, fieldDefinition, inputObjects)
135-
codeRegistryBuilder.dataFetcher(
136-
FieldCoordinates.coordinates(objectDefinition.name, fieldDefinition.name),
137-
fieldResolversByType[objectDefinition]?.get(fieldDefinition)?.createDataFetcher()
138-
?: throw SchemaError("No resolver method found for object type '${objectDefinition.name}' and field '${fieldDefinition.name}', this is most likely a bug with graphql-java-tools")
139-
)
140-
141-
val wiredField = field.build()
142-
GraphQLFieldDefinition.Builder(wiredField)
143-
.clearArguments()
144-
.arguments(wiredField.arguments)
126+
.withDirectives(*buildDirectives(objectDefinition.directives, Introspection.DirectiveLocation.OBJECT))
127+
.apply {
128+
objectDefinition.implements.forEach { implementsDefinition ->
129+
val interfaceName = (implementsDefinition as TypeName).name
130+
withInterface(interfaces.find { it.name == interfaceName }
131+
?: throw SchemaError("Expected interface type with name '$interfaceName' but found none!"))
132+
}
133+
}
134+
.apply {
135+
objectDefinition.getExtendedFieldDefinitions(extensionDefinitions).forEach { fieldDefinition ->
136+
field { field ->
137+
createField(field, fieldDefinition, inputObjects)
138+
codeRegistryBuilder.dataFetcher(
139+
FieldCoordinates.coordinates(objectDefinition.name, fieldDefinition.name),
140+
fieldResolversByType[objectDefinition]?.get(fieldDefinition)?.createDataFetcher()
141+
?: throw SchemaError("No resolver method found for object type '${objectDefinition.name}' and field '${fieldDefinition.name}', this is most likely a bug with graphql-java-tools")
142+
)
143+
144+
val wiredField = field.build()
145+
GraphQLFieldDefinition.Builder(wiredField)
146+
.clearArguments()
147+
.arguments(wiredField.arguments)
148+
}
149+
}
145150
}
146-
}
147151

148152
return directiveWiringHelper.wireObject(builder.build())
149153
}
@@ -152,28 +156,33 @@ class SchemaParser internal constructor(
152156
referencingInputObjects: MutableSet<String>): GraphQLInputObjectType {
153157
val extensionDefinitions = inputExtensionDefinitions.filter { it.name == definition.name }
154158

159+
referencingInputObjects.add(definition.name)
160+
155161
val builder = GraphQLInputObjectType.newInputObject()
156162
.name(definition.name)
157163
.definition(definition)
158164
.extensionDefinitions(extensionDefinitions)
159165
.description(getDocumentation(definition, options))
160166
.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
161-
162-
referencingInputObjects.add(definition.name)
163-
164-
(extensionDefinitions + definition).forEach {
165-
it.inputValueDefinitions.forEach { inputDefinition ->
166-
val fieldBuilder = GraphQLInputObjectField.newInputObjectField()
167-
.name(inputDefinition.name)
168-
.definition(inputDefinition)
169-
.description(getDocumentation(inputDefinition, options))
170-
.apply { inputDefinition.defaultValue?.let { v -> defaultValueLiteral(v) } }
171-
.apply { getDeprecated(inputDefinition.directives)?.let { deprecate(it) } }
172-
.type(determineInputType(inputDefinition.type, inputObjects, referencingInputObjects))
173-
.withAppliedDirectives(*buildAppliedDirectives(inputDefinition.directives))
174-
builder.field(fieldBuilder.build())
167+
.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.INPUT_OBJECT))
168+
.apply {
169+
(extensionDefinitions + definition).forEach { typeDefinition ->
170+
typeDefinition.inputValueDefinitions.forEach { fieldDefinition ->
171+
field(
172+
GraphQLInputObjectField.newInputObjectField()
173+
.name(fieldDefinition.name)
174+
.definition(fieldDefinition)
175+
.description(getDocumentation(fieldDefinition, options))
176+
.apply { fieldDefinition.defaultValue?.let { v -> defaultValueLiteral(v) } }
177+
.apply { getDeprecated(fieldDefinition.directives)?.let { deprecate(it) } }
178+
.type(determineInputType(fieldDefinition.type, inputObjects, referencingInputObjects))
179+
.withAppliedDirectives(*buildAppliedDirectives(fieldDefinition.directives))
180+
.withDirectives(*buildDirectives(definition.directives, INPUT_FIELD_DEFINITION))
181+
.build()
182+
)
183+
}
184+
}
175185
}
176-
}
177186

178187
return directiveWiringHelper.wireInputObject(builder.build())
179188
}
@@ -189,57 +198,63 @@ class SchemaParser internal constructor(
189198
.definition(definition)
190199
.description(getDocumentation(definition, options))
191200
.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
192-
193-
definition.enumValueDefinitions.forEach { enumDefinition ->
194-
val enumName = enumDefinition.name
195-
val enumValue = type.unwrap().enumConstants.find { (it as Enum<*>).name == enumName }
196-
?: throw SchemaError("Expected value for name '$enumName' in enum '${type.unwrap().simpleName}' but found none!")
197-
198-
val enumValueAppliedDirectives = buildAppliedDirectives(enumDefinition.directives)
199-
val enumValueDefinition = GraphQLEnumValueDefinition.newEnumValueDefinition()
200-
.name(enumName)
201-
.description(getDocumentation(enumDefinition, options))
202-
.value(enumValue)
203-
.apply { getDeprecated(enumDefinition.directives)?.let { deprecationReason(it) } }
204-
.withAppliedDirectives(*enumValueAppliedDirectives)
205-
.definition(enumDefinition)
206-
.build()
207-
208-
builder.value(enumValueDefinition)
209-
}
201+
.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.ENUM))
202+
.apply {
203+
definition.enumValueDefinitions.forEach { valueDefinition ->
204+
val enumName = valueDefinition.name
205+
val enumValue = type.unwrap().enumConstants.find { (it as Enum<*>).name == enumName }
206+
?: throw SchemaError("Expected value for name '$enumName' in enum '${type.unwrap().simpleName}' but found none!")
207+
208+
value(
209+
GraphQLEnumValueDefinition.newEnumValueDefinition()
210+
.name(enumName)
211+
.description(getDocumentation(valueDefinition, options))
212+
.value(enumValue)
213+
.apply { getDeprecated(valueDefinition.directives)?.let { deprecationReason(it) } }
214+
.withAppliedDirectives(*buildAppliedDirectives(valueDefinition.directives))
215+
.withDirectives(*buildDirectives(valueDefinition.directives, Introspection.DirectiveLocation.ENUM_VALUE))
216+
.definition(valueDefinition)
217+
.build()
218+
)
219+
}
220+
}
210221

211222
return directiveWiringHelper.wireEnum(builder.build())
212223
}
213224

214225
private fun createInterfaceObject(interfaceDefinition: InterfaceTypeDefinition, inputObjects: List<GraphQLInputObjectType>): GraphQLInterfaceType {
215-
val name = interfaceDefinition.name
216226
val builder = GraphQLInterfaceType.newInterface()
217-
.name(name)
227+
.name(interfaceDefinition.name)
218228
.definition(interfaceDefinition)
219229
.description(getDocumentation(interfaceDefinition, options))
220230
.withAppliedDirectives(*buildAppliedDirectives(interfaceDefinition.directives))
221-
222-
interfaceDefinition.fieldDefinitions.forEach { fieldDefinition ->
223-
builder.field { field -> createField(field, fieldDefinition, inputObjects) }
224-
}
225-
226-
interfaceDefinition.implements.forEach { implementsDefinition ->
227-
val interfaceName = (implementsDefinition as TypeName).name
228-
builder.withInterface(GraphQLTypeReference(interfaceName))
229-
}
231+
.withDirectives(*buildDirectives(interfaceDefinition.directives, Introspection.DirectiveLocation.INTERFACE))
232+
.apply {
233+
interfaceDefinition.fieldDefinitions.forEach { fieldDefinition ->
234+
field { field -> createField(field, fieldDefinition, inputObjects) }
235+
}
236+
}
237+
.apply {
238+
interfaceDefinition.implements.forEach { implementsDefinition ->
239+
val interfaceName = (implementsDefinition as TypeName).name
240+
withInterface(GraphQLTypeReference(interfaceName))
241+
}
242+
}
230243

231244
return directiveWiringHelper.wireInterFace(builder.build())
232245
}
233246

234247
private fun createUnionObject(definition: UnionTypeDefinition, types: List<GraphQLObjectType>): GraphQLUnionType {
235-
val name = definition.name
236248
val builder = GraphQLUnionType.newUnionType()
237-
.name(name)
249+
.name(definition.name)
238250
.definition(definition)
239251
.description(getDocumentation(definition, options))
240252
.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
253+
.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.UNION))
254+
.apply {
255+
getLeafUnionObjects(definition, types).forEach { possibleType(it) }
256+
}
241257

242-
getLeafUnionObjects(definition, types).forEach { builder.possibleType(it) }
243258
return directiveWiringHelper.wireUnion(builder.build())
244259
}
245260

@@ -264,56 +279,50 @@ class SchemaParser internal constructor(
264279
}
265280

266281
private fun createField(field: GraphQLFieldDefinition.Builder, fieldDefinition: FieldDefinition, inputObjects: List<GraphQLInputObjectType>): GraphQLFieldDefinition.Builder {
267-
field
282+
return field
268283
.name(fieldDefinition.name)
269284
.description(getDocumentation(fieldDefinition, options))
270285
.definition(fieldDefinition)
271286
.apply { getDeprecated(fieldDefinition.directives)?.let { deprecate(it) } }
272287
.type(determineOutputType(fieldDefinition.type, inputObjects))
273288
.withAppliedDirectives(*buildAppliedDirectives(fieldDefinition.directives))
289+
.withDirectives(*buildDirectives(fieldDefinition.directives, Introspection.DirectiveLocation.FIELD_DEFINITION))
290+
.apply {
291+
fieldDefinition.inputValueDefinitions.forEach { argumentDefinition ->
292+
argument(createArgument(argumentDefinition, inputObjects))
293+
}
294+
}
295+
}
274296

275-
fieldDefinition.inputValueDefinitions.forEach { argumentDefinition ->
276-
val argumentBuilder = GraphQLArgument.newArgument()
277-
.name(argumentDefinition.name)
278-
.definition(argumentDefinition)
279-
.description(getDocumentation(argumentDefinition, options))
280-
.type(determineInputType(argumentDefinition.type, inputObjects, setOf()))
281-
.apply { getDeprecated(argumentDefinition.directives)?.let { deprecate(it) } }
282-
.apply { argumentDefinition.defaultValue?.let { defaultValueLiteral(it) } }
283-
.withAppliedDirectives(*buildAppliedDirectives(argumentDefinition.directives))
284-
285-
field.argument(argumentBuilder.build())
286-
}
287-
288-
return field
297+
private fun createArgument(definition: InputValueDefinition, inputObjects: List<GraphQLInputObjectType>): GraphQLArgument {
298+
return GraphQLArgument.newArgument()
299+
.name(definition.name)
300+
.definition(definition)
301+
.description(getDocumentation(definition, options))
302+
.type(determineInputType(definition.type, inputObjects, setOf()))
303+
.apply { getDeprecated(definition.directives)?.let { deprecate(it) } }
304+
.apply { definition.defaultValue?.let { defaultValueLiteral(it) } }
305+
.withAppliedDirectives(*buildAppliedDirectives(definition.directives))
306+
.withDirectives(*buildDirectives(definition.directives, Introspection.DirectiveLocation.ARGUMENT_DEFINITION))
307+
.build()
289308
}
290309

291310
private fun createDirective(definition: DirectiveDefinition, inputObjects: List<GraphQLInputObjectType>): GraphQLDirective {
292311
val locations = definition.directiveLocations.map { Introspection.DirectiveLocation.valueOf(it.name) }.toTypedArray()
293312

294-
val graphQLDirective = GraphQLDirective.newDirective()
313+
return GraphQLDirective.newDirective()
295314
.name(definition.name)
296315
.description(getDocumentation(definition, options))
297316
.definition(definition)
298317
.comparatorRegistry(runtimeWiring.comparatorRegistry)
299318
.validLocations(*locations)
300319
.repeatable(definition.isRepeatable)
301320
.apply {
302-
definition.inputValueDefinitions.forEach { arg ->
303-
argument(GraphQLArgument.newArgument()
304-
.name(arg.name)
305-
.definition(arg)
306-
.description(getDocumentation(arg, options))
307-
.type(determineInputType(arg.type, inputObjects, setOf()))
308-
.apply { getDeprecated(arg.directives)?.let { deprecate(it) } }
309-
.apply { arg.defaultValue?.let { defaultValueLiteral(it) } }
310-
.withAppliedDirectives(*buildAppliedDirectives(arg.directives))
311-
.build())
321+
definition.inputValueDefinitions.forEach { argumentDefinition ->
322+
argument(createArgument(argumentDefinition, inputObjects))
312323
}
313324
}
314325
.build()
315-
316-
return graphQLDirective
317326
}
318327

319328
private fun buildAppliedDirectives(directives: List<Directive>): Array<GraphQLAppliedDirective> {
@@ -328,17 +337,31 @@ class SchemaParser internal constructor(
328337
.name(arg.name)
329338
.type(directiveWiringHelper.buildDirectiveInputType(arg.value))
330339
.valueLiteral(arg.value)
331-
.build())
340+
.build()
341+
)
332342
}
333343
}
334344
.build()
335345
}.toTypedArray()
336346
}
337347

348+
// TODO remove this once directives are fully replaced with applied directives
349+
private fun buildDirectives(
350+
directives: List<Directive>,
351+
directiveLocation: Introspection.DirectiveLocation
352+
): Array<GraphQLDirective> {
353+
return directiveWiringHelper.buildDirectives(directives, directiveLocation).toTypedArray()
354+
}
355+
338356
private fun determineOutputType(typeDefinition: Type<*>, inputObjects: List<GraphQLInputObjectType>) =
339357
determineType(GraphQLOutputType::class, typeDefinition, permittedTypesForObject, inputObjects) as GraphQLOutputType
340358

341-
private fun <T : Any> determineType(expectedType: KClass<T>, typeDefinition: Type<*>, allowedTypeReferences: Set<String>, inputObjects: List<GraphQLInputObjectType>): GraphQLType =
359+
private fun <T : Any> determineType(
360+
expectedType: KClass<T>,
361+
typeDefinition: Type<*>,
362+
allowedTypeReferences: Set<String>,
363+
inputObjects: List<GraphQLInputObjectType>
364+
): GraphQLType =
342365
when (typeDefinition) {
343366
is ListType -> GraphQLList(determineType(expectedType, typeDefinition.type, allowedTypeReferences, inputObjects))
344367
is NonNullType -> GraphQLNonNull(determineType(expectedType, typeDefinition.type, allowedTypeReferences, inputObjects))

src/main/kotlin/graphql/kickstart/tools/directive/DirectiveWiringHelper.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,18 @@ class DirectiveWiringHelper(
100100
return output
101101
}
102102

103-
private fun buildDirectives(directives: List<Directive>, directiveLocation: Introspection.DirectiveLocation): List<GraphQLDirective> {
103+
fun buildDirectives(directives: List<Directive>, directiveLocation: Introspection.DirectiveLocation): List<GraphQLDirective> {
104104
val names = mutableSetOf<String>()
105105
val output = mutableListOf<GraphQLDirective>()
106106

107107
for (directive in directives) {
108108
val repeatable = directiveDefinitions.find { it.name.equals(directive.name) }?.isRepeatable ?: false
109109
if (repeatable || !names.contains(directive.name)) {
110110
names.add(directive.name)
111-
output.add(GraphQLDirective.newDirective()
112-
.name(directive.name)
113-
.description(getDocumentation(directive, options))
111+
output.add(
112+
GraphQLDirective.newDirective()
113+
.name(directive.name)
114+
.description(getDocumentation(directive, options))
114115
.comparatorRegistry(runtimeWiring.comparatorRegistry)
115116
.validLocation(directiveLocation)
116117
.repeatable(repeatable)

0 commit comments

Comments
 (0)