diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt index b45ada00..b6f7d34e 100644 --- a/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt +++ b/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt @@ -333,26 +333,29 @@ internal class SchemaClassScanner( } is InputObjectTypeDefinition -> { - graphQLType.inputValueDefinitions.forEach { inputValueDefinition -> - val inputGraphQLType = inputValueDefinition.type.unwrap() - if (inputGraphQLType is TypeName && !ScalarInfo.GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.containsKey(inputGraphQLType.name)) { - val inputValueJavaType = findInputValueType(inputValueDefinition.name, inputGraphQLType, javaType.unwrap()) - if (inputValueJavaType != null) { - handleFoundType(typeClassMatcher.match(TypeClassMatcher.PotentialMatch.parameterType( - inputValueDefinition.type, - inputValueJavaType, - GenericType(javaType, options).relativeToType(inputValueJavaType), - InputObjectReference(inputValueDefinition) - ))) - } else { - var mappingAdvice = "Try adding it manually to the dictionary" - if (javaType.unwrap().name.contains("Map")) { - mappingAdvice = " or add a class to represent your input type instead of a Map." + val inputObjectTypes = listOf(graphQLType) + inputExtensionDefinitions.filter { it.name == graphQLType.name } + inputObjectTypes + .flatMap { it.inputValueDefinitions } + .forEach { inputValueDefinition -> + val inputGraphQLType = inputValueDefinition.type.unwrap() + if (inputGraphQLType is TypeName && !ScalarInfo.GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.containsKey(inputGraphQLType.name)) { + val inputValueJavaType = findInputValueType(inputValueDefinition.name, inputGraphQLType, javaType.unwrap()) + if (inputValueJavaType != null) { + handleFoundType(typeClassMatcher.match(TypeClassMatcher.PotentialMatch.parameterType( + inputValueDefinition.type, + inputValueJavaType, + GenericType(javaType, options).relativeToType(inputValueJavaType), + InputObjectReference(inputValueDefinition) + ))) + } else { + var mappingAdvice = "Try adding it manually to the dictionary" + if (javaType.unwrap().name.contains("Map")) { + mappingAdvice = " or add a class to represent your input type instead of a Map." + } + log.warn("Cannot find definition for field '${inputValueDefinition.name}: ${inputGraphQLType.name}' on input type '${graphQLType.name}' -> ${javaType.unwrap().name}. $mappingAdvice") } - log.warn("Cannot find definition for field '${inputValueDefinition.name}: ${inputGraphQLType.name}' on input type '${graphQLType.name}' -> ${javaType.unwrap().name}. $mappingAdvice") } } - } } } } diff --git a/src/test/groovy/graphql/kickstart/tools/NestedInputTypesSpec.groovy b/src/test/groovy/graphql/kickstart/tools/NestedInputTypesSpec.groovy index 54be3706..d0ce1a68 100644 --- a/src/test/groovy/graphql/kickstart/tools/NestedInputTypesSpec.groovy +++ b/src/test/groovy/graphql/kickstart/tools/NestedInputTypesSpec.groovy @@ -53,6 +53,55 @@ class NestedInputTypesSpec extends Specification { data.materials == [] } + def "nested input in extensions are parsed"() { + when: + GraphQLSchema schema = SchemaParser.newParser().schemaString('''\ + type Query { + materials(filter: MaterialFilter): [Material!]! + } + + input MaterialFilter { + title: String + } + + extend input MaterialFilter { + requestFilter: RequestFilter + } + + input RequestFilter { + and: [RequestFilter!] + or: [RequestFilter!] + discountTypeFilter: DiscountTypeFilter + } + + input DiscountTypeFilter { + name: String + } + + type Material { + id: ID! + } + ''').resolvers(new QueryResolver()) + .build() + .makeExecutableSchema() + GraphQL gql = GraphQL.newGraphQL(schema) + .queryExecutionStrategy(new AsyncExecutionStrategy()) + .build() + def data = Utils.assertNoGraphQlErrors(gql, [filter: [title: "title", requestFilter: [discountTypeFilter: [name: "discount"]]]]) { + ''' + query materials($filter: MaterialFilter!) { + materials(filter: $filter) { + id + } + } + ''' + } + + then: + noExceptionThrown() + data.materials == [] + } + class QueryResolver implements GraphQLQueryResolver { List materials(MaterialFilter filter) { Collections.emptyList() } }