diff --git a/src/main/kotlin/graphql/kickstart/tools/ResolverInfo.kt b/src/main/kotlin/graphql/kickstart/tools/ResolverInfo.kt index 63016fa1..8368bf44 100644 --- a/src/main/kotlin/graphql/kickstart/tools/ResolverInfo.kt +++ b/src/main/kotlin/graphql/kickstart/tools/ResolverInfo.kt @@ -48,21 +48,10 @@ internal class NormalResolverInfo( } } -internal class MultiResolverInfo(val resolverInfoList: List) : DataClassTypeResolverInfo, ResolverInfo() { - override val dataClassType = findDataClass() - - /** - * Checks if all `ResolverInfo` instances are related to the same data type - */ - private fun findDataClass(): Class { - val dataClass = resolverInfoList.asSequence().map { it.dataClassType }.distinct().singleOrNull() - if (dataClass == null) { - throw ResolverError("Resolvers may not use the same type.") - } else { - return dataClass - } - } +internal class MultiResolverInfo(val resolverInfoList: List, + override val dataClassType: Class +) : DataClassTypeResolverInfo, ResolverInfo() { override fun getFieldSearches(): List { return resolverInfoList diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt index 2472bef8..c8bd46be 100644 --- a/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt +++ b/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt @@ -249,14 +249,18 @@ internal class SchemaClassScanner( * Scan a new object for types that haven't been mapped yet. */ private fun scanQueueItemForPotentialMatches(item: QueueItem) { - val resolverInfoList = this.resolverInfos.filter { it.dataClassType == item.clazz } - val resolverInfo: ResolverInfo = (if (resolverInfoList.size > 1) { - MultiResolverInfo(resolverInfoList) + val resolverInfoList = this.resolverInfos.filter { it.dataClassType.unwrap().isAssignableFrom(item.clazz.unwrap()) } + val resolverInfo: ResolverInfo = (if (resolverInfoList.size > 1 && item.clazz != Object::class.java) { + MultiResolverInfo(resolverInfoList, item.clazz.unwrap()) } else { if (item.clazz == Object::class.java) { getResolverInfoFromTypeDictionary(item.type.name) } else { - resolverInfosByDataClass[item.clazz] ?: DataClassResolverInfo(item.clazz) + if (resolverInfoList.size == 1) { + MultiResolverInfo(resolverInfoList, item.clazz.unwrap()) + } else { + DataClassResolverInfo(item.clazz) + } } }) ?: throw throw SchemaClassScannerError("The GraphQL schema type '${item.type.name}' 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.") diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt index 8f7a9de9..06bdc3c2 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt @@ -127,7 +127,8 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) { private fun verifyMethodArguments(method: Method, requiredCount: Int, search: Search): Boolean { val appropriateFirstParameter = if (search.requiredFirstParameterType != null) { method.genericParameterTypes.firstOrNull()?.let { - it == search.requiredFirstParameterType || method.declaringClass.typeParameters.contains(it) + it == search.requiredFirstParameterType || (it is Class<*> && it.unwrap().isAssignableFrom(search.requiredFirstParameterType)) + || method.declaringClass.typeParameters.contains(it) } ?: false } else { true diff --git a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt index 3b56047c..f7ee95df 100644 --- a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt +++ b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt @@ -16,7 +16,7 @@ import javax.servlet.http.Part fun createSchema() = SchemaParser.newParser() .schemaString(schemaDefinition) - .resolvers(Query(), Mutation(), Subscription(), ItemResolver(), UnusedRootResolver(), UnusedResolver(), EchoFilesResolver()) + .resolvers(Query(), Mutation(), Subscription(), ItemResolver(), ItemInterfaceResolver(), UnusedRootResolver(), UnusedResolver(), EchoFilesResolver()) .scalars(customScalarUUID, customScalarMap, customScalarId, uploadScalar) .dictionary("OtherItem", OtherItemWithWrongName::class) .dictionary("ThirdItem", ThirdItem::class) @@ -155,6 +155,7 @@ type Item implements ItemInterface { type: Type! uuid: UUID! tags(names: [String!]): [Tag!] + uppercaseName: String! } type OtherItem implements ItemInterface { @@ -394,6 +395,10 @@ class ItemResolver : GraphQLResolver { } } +class ItemInterfaceResolver : GraphQLResolver { + fun uppercaseName(item: ItemInterface): String = item.name.toUpperCase() +} + class EchoFilesResolver : GraphQLMutationResolver { fun echoFiles(fileParts: List): List = fileParts.map { String(it.inputStream.readBytes()) } }