Skip to content

Commit 924ad5a

Browse files
authored
Merge pull request #829 from graphql-java-kickstart/bugfix/295
Allow list fields on map-backed types
2 parents 62c5146 + 652c630 commit 924ad5a

2 files changed

Lines changed: 136 additions & 5 deletions

File tree

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,16 @@ internal class TypeClassMatcher(private val definitionsByName: Map<String, TypeD
6565
match(potentialMatch, graphQLType.type, realType)
6666
}
6767

68-
is ListType -> {
69-
if (realType is ParameterizedType && isListType(realType, potentialMatch)) {
68+
is ListType -> when {
69+
realType is ParameterizedType && isListType(realType, potentialMatch) ->
7070
match(potentialMatch, graphQLType.type, realType.actualTypeArguments.first())
71-
} else if (realType is Class<*> && realType.isArray) {
71+
realType is Class<*> && realType.isArray ->
7272
match(potentialMatch, graphQLType.type, realType.componentType)
73-
} else {
73+
// e.g. a property map value: the element type is unknown, so match it as Object too
74+
realType == Object::class.java ->
75+
match(potentialMatch, graphQLType.type, realType)
76+
else ->
7477
throw error(potentialMatch, "Java class is not a List or generic type information was lost: $realType")
75-
}
7678
}
7779

7880
is TypeName -> {
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package graphql.kickstart.tools
2+
3+
import graphql.GraphQL
4+
import org.junit.Assert.assertThrows
5+
import org.junit.Test
6+
7+
class PropertyMapListTest {
8+
9+
@Test
10+
fun `property maps should support list fields`() {
11+
val schema = SchemaParser.newParser()
12+
.schemaString(
13+
"""
14+
type Query {
15+
greeting: Greeting!
16+
}
17+
18+
type Greeting {
19+
name: String!
20+
tags: [String!]!
21+
matrix: [[Int]]
22+
key: Key
23+
keys: [Key!]
24+
}
25+
26+
type Key {
27+
a: String
28+
b: [String]
29+
}
30+
""")
31+
.resolvers(object : GraphQLQueryResolver {
32+
fun greeting(): Map<String, Any> = mapOf(
33+
"name" to "hello",
34+
"tags" to listOf("x", "y"),
35+
"matrix" to listOf(listOf(1, 2), listOf(3)),
36+
"key" to hashMapOf("a" to "one", "b" to listOf("ss")),
37+
"keys" to listOf(hashMapOf("a" to "two", "b" to listOf("tt")))
38+
)
39+
})
40+
.dictionary("Key", HashMap::class)
41+
.build()
42+
.makeExecutableSchema()
43+
val gql = GraphQL.newGraphQL(schema).build()
44+
45+
val data = assertNoGraphQlErrors(gql) {
46+
"""
47+
{
48+
greeting {
49+
name
50+
tags
51+
matrix
52+
key { a b }
53+
keys { a b }
54+
}
55+
}
56+
"""
57+
}
58+
59+
assertEquals(data["greeting"], mapOf(
60+
"name" to "hello",
61+
"tags" to listOf("x", "y"),
62+
"matrix" to listOf(listOf(1, 2), listOf(3)),
63+
"key" to mapOf("a" to "one", "b" to listOf("ss")),
64+
"keys" to listOf(mapOf("a" to "two", "b" to listOf("tt")))
65+
))
66+
}
67+
68+
@Test
69+
fun `property maps with typed list values should support list fields`() {
70+
val schema = SchemaParser.newParser()
71+
.schemaString(
72+
"""
73+
type Query {
74+
tags: Tags!
75+
}
76+
77+
type Tags {
78+
names: [String!]!
79+
}
80+
""")
81+
.resolvers(object : GraphQLQueryResolver {
82+
fun tags(): TagsMap = TagsMap().apply { put("names", listOf("x", "y")) }
83+
})
84+
.build()
85+
.makeExecutableSchema()
86+
val gql = GraphQL.newGraphQL(schema).build()
87+
88+
val data = assertNoGraphQlErrors(gql) {
89+
"""
90+
{
91+
tags {
92+
names
93+
}
94+
}
95+
"""
96+
}
97+
98+
assertEquals(data["tags"], mapOf("names" to listOf("x", "y")))
99+
}
100+
101+
@Test
102+
fun `property maps with object list fields should require a dictionary entry`() {
103+
val error = assertThrows(SchemaClassScannerError::class.java) {
104+
SchemaParser.newParser()
105+
.schemaString(
106+
"""
107+
type Query {
108+
greeting: Greeting!
109+
}
110+
111+
type Greeting {
112+
keys: [Key!]
113+
}
114+
115+
type Key {
116+
a: String
117+
}
118+
""")
119+
.resolvers(object : GraphQLQueryResolver {
120+
fun greeting(): Map<String, Any> = mapOf()
121+
})
122+
.build()
123+
}
124+
125+
assertEquals(error.message, "The GraphQL schema type 'Key' maps to a field of type java.lang.Object however there is no matching entry for this type in the type dictionary. You may need to add this type to the dictionary before building the schema.")
126+
}
127+
128+
class TagsMap : HashMap<String, List<String>>()
129+
}

0 commit comments

Comments
 (0)