diff --git a/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt b/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt index d2215367..6c3fbce1 100644 --- a/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt +++ b/src/main/kotlin/graphql/kickstart/tools/SchemaClassScanner.kt @@ -436,13 +436,15 @@ internal class SchemaClassScanner( private fun findInputValueTypeInType(name: String, clazz: Class<*>): JavaType? { val methods = clazz.methods - val filteredMethods = methods.filter { + val (getters, methodsWithParameters) = methods.filter { it.name == name || it.name == "get${name.replaceFirstChar(Char::titlecase)}" - }.sortedBy { it.name.length } + }.sortedBy { it.name.length }.partition { it.parameterCount == 0 } - return filteredMethods.find { !it.isSynthetic }?.genericReturnType - ?: filteredMethods.firstOrNull()?.genericReturnType + return getters.find { !it.isSynthetic }?.genericReturnType + ?: getters.firstOrNull()?.genericReturnType ?: clazz.fields.find { it.name == name }?.genericType + ?: methodsWithParameters.find { !it.isSynthetic }?.genericReturnType + ?: methodsWithParameters.firstOrNull()?.genericReturnType } private data class QueueItem(val type: ObjectTypeDefinition, val clazz: JavaType) diff --git a/src/test/kotlin/graphql/kickstart/tools/SchemaClassScannerTest.kt b/src/test/kotlin/graphql/kickstart/tools/SchemaClassScannerTest.kt index 67671ab5..24f0e662 100644 --- a/src/test/kotlin/graphql/kickstart/tools/SchemaClassScannerTest.kt +++ b/src/test/kotlin/graphql/kickstart/tools/SchemaClassScannerTest.kt @@ -146,6 +146,122 @@ class SchemaClassScannerTest { } } + @Test + fun `scanner ignores fluent setters when finding input field types`() { + SchemaParser.newParser() + .resolvers(FluentSetterMutation(), object : GraphQLQueryResolver { + fun test(): Boolean = true + }) + .schemaString( + """ + type Query { + test: Boolean + } + + type Mutation { + createRepairApply(body: RepairApplyInput): Boolean + createRepairMan(body: RepairManInput): Boolean + } + + input RepairApplyInput { + id: ID + repairMan: RepairManInput + reviewer: RepairManInput + approver: RepairManInput + } + + input RepairManInput { + id: ID + userName: String + } + """) + .build() + .makeExecutableSchema() + } + + private class FluentSetterMutation : GraphQLMutationResolver { + fun createRepairApply(body: RepairApply): Boolean = true + fun createRepairMan(body: RepairMan): Boolean = true + + class RepairApply { + var id: String? = null + var repairMan: RepairMan? = null + private var reviewer: RepairMan? = null + @JvmField + var approver: RepairMan? = null + + fun repairMan(repairMan: RepairMan?): RepairApply { + this.repairMan = repairMan + return this + } + + fun reviewer(): RepairMan? = reviewer + + fun reviewer(reviewer: RepairMan?): RepairApply { + this.reviewer = reviewer + return this + } + + fun approver(approver: RepairMan?): RepairApply { + this.approver = approver + return this + } + } + + class RepairMan { + var id: String? = null + var userName: String? = null + } + } + + @Test + fun `scanner finds input field types through getters with arguments`() { + SchemaParser.newParser() + .resolvers(GetterWithArgumentsQuery()) + .schemaString( + """ + type Query { + foo(input: FooInput): Foo + } + + type Foo { + bar: Bar + } + + type Bar { + name: String + } + + input FooInput { + bar: BarInput + } + + input BarInput { + name: String + } + """) + .build() + .makeExecutableSchema() + } + + private class GetterWithArgumentsQuery : GraphQLQueryResolver { + fun foo(input: Foo): Foo = input + + class Foo { + private var bar: Bar? = null + + fun getBar(env: DataFetchingEnvironment): Bar? = bar + + fun setBar(bar: Bar?) { + this.bar = bar + } + } + + class Bar { + var name: String? = null + } + } + @Test fun `scanner handles input types extensions`() { val schema = SchemaParser.newParser()