diff --git a/src/main/kotlin/graphql/kickstart/tools/DictionaryTypeResolver.kt b/src/main/kotlin/graphql/kickstart/tools/DictionaryTypeResolver.kt index 7851c134..e5f0a901 100644 --- a/src/main/kotlin/graphql/kickstart/tools/DictionaryTypeResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/DictionaryTypeResolver.kt @@ -16,22 +16,15 @@ internal abstract class DictionaryTypeResolver( private val dictionary: BiMap>, private val types: Map ) : TypeResolver { - private fun getTypeName(clazz: Class): String? { - val name = dictionary[clazz]?.name - - if (name == null && clazz.superclass != null) { - return getTypeName(clazz.superclass) - } - - return name + private fun getTypeDefinition(clazz: Class): TypeDefinition<*>? { + return dictionary[clazz] + ?: (if (clazz.superclass == null) null else getTypeDefinition(clazz.superclass)) + ?: clazz.interfaces.mapNotNull { getTypeDefinition(it) }.firstOrNull() } override fun getType(env: TypeResolutionEnvironment): GraphQLObjectType? { val clazz = env.getObject().javaClass - val name = clazz.interfaces.fold(getTypeName(clazz), { name, interfaceClazz -> - name ?: getTypeName(interfaceClazz) - }) ?: clazz.simpleName - + val name = getTypeDefinition(clazz)?.name ?: clazz.simpleName return types[name] ?: throw TypeResolverError(getError(name)) } diff --git a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt index 8047a1ae..e77d5ed6 100644 --- a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt +++ b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt @@ -22,6 +22,7 @@ fun createSchema() = SchemaParser.newParser() .dictionary("ThirdItem", ThirdItem::class) .dictionary("ComplexMapItem", ComplexMapItem::class) .dictionary("NestedComplexMapItem", NestedComplexMapItem::class) + .dictionary("NoDogError", NoDogError::class) .build() .makeExecutableSchema() @@ -83,6 +84,9 @@ type Query { arrayItems: [Item!]! throwsIllegalArgumentException: String + + allDogs: [Dog!]! + findSuitableDog(preferredColor: String!, minimumFluffiness: Int!): FindDogResult! } type ExtendedType { @@ -216,6 +220,18 @@ type Tag { type ItemWithGenericProperties { keys: [String!]! } + +type Dog { + name: String! + color: String! + fluffiness: Int! +} + +type NoDogError { + msg: String +} + +union FindDogResult = Dog | NoDogError """ val items = listOf( @@ -314,6 +330,13 @@ class Query : GraphQLQueryResolver, ListListResolver() { fun throwsIllegalArgumentException(): String { throw IllegalArgumentException("Expected") } + + fun allDogs(): List = listOf(LabradorRetriever("Hershey", "chocolate", 42, 3.14159f)) + + fun findSuitableDog(preferredColor: String, minimumFluffiness: Int): Any = + allDogs() + .firstOrNull { it.color == preferredColor && it.fluffiness >= minimumFluffiness } + ?: NoDogError("No $preferredColor-colored dog found that is sufficiently fluffy") } class UnusedRootResolver : GraphQLQueryResolver @@ -410,6 +433,15 @@ class MockPart(private val name: String, private val content: String) : Part { override fun delete() = throw IllegalArgumentException("Not supported") } +interface Dog { + val name: String + val color: String + val fluffiness: Int +} +interface Retriever : Dog { val speed: Float } +class LabradorRetriever(override val name: String, override val color: String, override val fluffiness: Int, override val speed: Float) : Retriever +class NoDogError(val msg: String) + val customScalarId = GraphQLScalarType.newScalar() .name("ID") .description("Overrides built-in ID") diff --git a/src/test/kotlin/graphql/kickstart/tools/EndToEndTest.kt b/src/test/kotlin/graphql/kickstart/tools/EndToEndTest.kt index 6ca764c1..5d4dc51d 100644 --- a/src/test/kotlin/graphql/kickstart/tools/EndToEndTest.kt +++ b/src/test/kotlin/graphql/kickstart/tools/EndToEndTest.kt @@ -178,6 +178,22 @@ class EndToEndTest { assertNotNull(data["itemByUUID"]) } + @Test + fun `generated schema should handle union types with deep hierarchy`() { + val data = assertNoGraphQlErrors(gql) { + """ + { + findSuitableDog(preferredColor: "chocolate", minimumFluffiness: 31) { + ... on Dog { name } + ... on NoDogError { msg } + } + } + """ + } + + assertNotNull(data["findSuitableDog"]) + } + @Test fun `generated schema should handle non nullable scalar types`() { val fileParts = listOf(MockPart("test.doc", "Hello"), MockPart("test.doc", "World"))