Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/main/kotlin/graphql/kickstart/tools/TypeClassMatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,16 @@ internal class TypeClassMatcher(private val definitionsByName: Map<String, TypeD
match(potentialMatch, graphQLType.type, realType)
}

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

is TypeName -> {
Expand Down
129 changes: 129 additions & 0 deletions src/test/kotlin/graphql/kickstart/tools/PropertyMapListTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package graphql.kickstart.tools

import graphql.GraphQL
import org.junit.Assert.assertThrows
import org.junit.Test

class PropertyMapListTest {

@Test
fun `property maps should support list fields`() {
val schema = SchemaParser.newParser()
.schemaString(
"""
type Query {
greeting: Greeting!
}

type Greeting {
name: String!
tags: [String!]!
matrix: [[Int]]
key: Key
keys: [Key!]
}

type Key {
a: String
b: [String]
}
""")
.resolvers(object : GraphQLQueryResolver {
fun greeting(): Map<String, Any> = mapOf(
"name" to "hello",
"tags" to listOf("x", "y"),
"matrix" to listOf(listOf(1, 2), listOf(3)),
"key" to hashMapOf("a" to "one", "b" to listOf("ss")),
"keys" to listOf(hashMapOf("a" to "two", "b" to listOf("tt")))
)
})
.dictionary("Key", HashMap::class)
.build()
.makeExecutableSchema()
val gql = GraphQL.newGraphQL(schema).build()

val data = assertNoGraphQlErrors(gql) {
"""
{
greeting {
name
tags
matrix
key { a b }
keys { a b }
}
}
"""
}

assertEquals(data["greeting"], mapOf(
"name" to "hello",
"tags" to listOf("x", "y"),
"matrix" to listOf(listOf(1, 2), listOf(3)),
"key" to mapOf("a" to "one", "b" to listOf("ss")),
"keys" to listOf(mapOf("a" to "two", "b" to listOf("tt")))
))
}

@Test
fun `property maps with typed list values should support list fields`() {
val schema = SchemaParser.newParser()
.schemaString(
"""
type Query {
tags: Tags!
}

type Tags {
names: [String!]!
}
""")
.resolvers(object : GraphQLQueryResolver {
fun tags(): TagsMap = TagsMap().apply { put("names", listOf("x", "y")) }
})
.build()
.makeExecutableSchema()
val gql = GraphQL.newGraphQL(schema).build()

val data = assertNoGraphQlErrors(gql) {
"""
{
tags {
names
}
}
"""
}

assertEquals(data["tags"], mapOf("names" to listOf("x", "y")))
}

@Test
fun `property maps with object list fields should require a dictionary entry`() {
val error = assertThrows(SchemaClassScannerError::class.java) {
SchemaParser.newParser()
.schemaString(
"""
type Query {
greeting: Greeting!
}

type Greeting {
keys: [Key!]
}

type Key {
a: String
}
""")
.resolvers(object : GraphQLQueryResolver {
fun greeting(): Map<String, Any> = mapOf()
})
.build()
}

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.")
}

class TagsMap : HashMap<String, List<String>>()
}
Loading