Skip to content

Commit f1d12cc

Browse files
authored
Merge pull request #819 from graphql-java-kickstart/bugfix/468
Support generic input types
2 parents 13806f8 + cbfe0a9 commit f1d12cc

3 files changed

Lines changed: 111 additions & 3 deletions

File tree

‎src/main/kotlin/graphql/kickstart/tools/GenericType.kt‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,13 @@ internal open class GenericType(protected val mostSpecificType: JavaType, protec
151151
}
152152
}
153153
is TypeVariable<*> -> {
154-
if (declaringType is ParameterizedType) {
155-
TypeUtils.getRawType(type, declaringType)
154+
val genericDeclaration = type.genericDeclaration
155+
if (declaringType is ParameterizedType && genericDeclaration is Class<*>) {
156+
// keep the full type argument (e.g. List<Foo>) rather than its raw class so nested generics aren't lost
157+
TypeUtils.getTypeArguments(declaringType, genericDeclaration)?.get(type)
158+
?.takeIf { it != type }
159+
?.let { replaceTypeVariable(it) }
160+
?: type
156161
} else {
157162
type
158163
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ internal class SchemaClassScanner(
368368
handleFoundType(typeClassMatcher.match(TypeClassMatcher.PotentialMatch.parameterType(
369369
inputValueDefinition.type,
370370
inputValueJavaType,
371-
GenericType(javaType, options).relativeToType(inputValueJavaType),
371+
GenericType(javaType, options).relativeToType(javaType),
372372
InputObjectReference(inputValueDefinition)
373373
)))
374374
} else {
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package graphql.kickstart.tools
2+
3+
import graphql.GraphQL
4+
import org.junit.Test
5+
6+
class GenericInputTypesTest {
7+
8+
@Test
9+
fun `generic input types are parsed`() {
10+
val schema = SchemaParser.newParser()
11+
.schemaString(
12+
"""
13+
type Query {
14+
audit(input: LanguageAudit!): String!
15+
audits(input: LanguageAudits!): String!
16+
}
17+
18+
input LanguageAudit {
19+
content: LanguageInput!
20+
operator: String!
21+
}
22+
23+
input LanguageAudits {
24+
content: [LanguageInput!]!
25+
operator: String!
26+
}
27+
28+
input LanguageInput {
29+
id: ID!
30+
}
31+
""")
32+
.resolvers(QueryResolver())
33+
.build()
34+
.makeExecutableSchema()
35+
val gql = GraphQL.newGraphQL(schema).build()
36+
37+
val data = assertNoGraphQlErrors(gql) {
38+
"""
39+
query {
40+
audit(input: { content: { id: "1" }, operator: "op" })
41+
audits(input: { content: [{ id: "2" }, { id: "3" }], operator: "op" })
42+
}
43+
"""
44+
}
45+
46+
assertEquals(data["audit"], "op:1")
47+
assertEquals(data["audits"], "op:2,3")
48+
}
49+
50+
@Test
51+
fun `generic input types inherited from a parameterized superclass are parsed`() {
52+
val schema = SchemaParser.newParser()
53+
.schemaString(
54+
"""
55+
type Query {
56+
audit(input: LanguageAudit!): String!
57+
}
58+
59+
input LanguageAudit {
60+
content: LanguageInput!
61+
operator: String!
62+
}
63+
64+
input LanguageInput {
65+
id: ID!
66+
}
67+
""")
68+
.resolvers(InheritedQueryResolver())
69+
.build()
70+
.makeExecutableSchema()
71+
val gql = GraphQL.newGraphQL(schema).build()
72+
73+
val data = assertNoGraphQlErrors(gql) {
74+
"""
75+
query {
76+
audit(input: { content: { id: "1" }, operator: "op" })
77+
}
78+
"""
79+
}
80+
81+
assertEquals(data["audit"], "op:1")
82+
}
83+
84+
class QueryResolver : GraphQLQueryResolver {
85+
fun audit(input: AuditWrapper<LanguageInput>): String = "${input.operator}:${input.content?.id}"
86+
fun audits(input: AuditWrapper<List<LanguageInput>>): String = "${input.operator}:${input.content?.joinToString(",") { it.id.orEmpty() }}"
87+
}
88+
89+
class InheritedQueryResolver : GraphQLQueryResolver {
90+
fun audit(input: LanguageAuditWrapper): String = "${input.operator}:${input.content?.id}"
91+
}
92+
93+
open class AuditWrapper<T> {
94+
var content: T? = null
95+
var operator: String? = null
96+
}
97+
98+
class LanguageAuditWrapper : AuditWrapper<LanguageInput>()
99+
100+
class LanguageInput {
101+
var id: String? = null
102+
}
103+
}

0 commit comments

Comments
 (0)