diff --git a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt index fc8dcddd..ea8ec966 100644 --- a/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt +++ b/src/main/kotlin/graphql/kickstart/tools/resolver/FieldResolverScanner.kt @@ -4,10 +4,7 @@ import graphql.Scalars import graphql.kickstart.tools.ResolverInfo import graphql.kickstart.tools.RootResolverInfo import graphql.kickstart.tools.SchemaParserOptions -import graphql.kickstart.tools.util.GraphQLLangType -import graphql.kickstart.tools.util.JavaType -import graphql.kickstart.tools.util.declaredNonProxyMethods -import graphql.kickstart.tools.util.unwrap +import graphql.kickstart.tools.util.* import graphql.language.FieldDefinition import graphql.language.TypeName import graphql.schema.DataFetchingEnvironment @@ -83,6 +80,7 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) { // 2. Method that returns a boolean with "is" style getter // 3. Method with "get" style getter // 4. Method with "getField" style getter + // 5. Method with "get" style getter with the field name converted from snake_case to camelCased. ex: key_ops -> getKeyOps() return methods.find { it.name == name && verifyMethodArguments(it, argumentCount, search) } ?: methods.find { @@ -91,6 +89,8 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) { it.name == "get${name.capitalize()}" && verifyMethodArguments(it, argumentCount, search) } ?: methods.find { it.name == "getField${name.capitalize()}" && verifyMethodArguments(it, argumentCount, search) + } ?: methods.find { + it.name == "get${name.snakeToCamelCase()}" && verifyMethodArguments(it, argumentCount, search) } } diff --git a/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt b/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt index 9caeaf51..7ff5b506 100644 --- a/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt +++ b/src/main/kotlin/graphql/kickstart/tools/util/Utils.kt @@ -72,3 +72,5 @@ private fun isBooleanGetter(method: Method) = (method.name.startsWith("is") && (method.returnType == java.lang.Boolean::class.java) || method.returnType == Boolean::class.java) +internal fun String.snakeToCamelCase(): String = split("_").joinToString(separator = "") { it.capitalize() } + diff --git a/src/test/groovy/graphql/kickstart/tools/FieldResolverScannerSpec.groovy b/src/test/groovy/graphql/kickstart/tools/FieldResolverScannerSpec.groovy index da87551d..e2a14b89 100644 --- a/src/test/groovy/graphql/kickstart/tools/FieldResolverScannerSpec.groovy +++ b/src/test/groovy/graphql/kickstart/tools/FieldResolverScannerSpec.groovy @@ -87,6 +87,18 @@ class FieldResolverScannerSpec extends Specification { ((MethodFieldResolver) meta).getMethod().getReturnType() == BoatInformation.class } + def "scanner finds field resolver method using camelCase for snake_cased field_name"() { + setup: + def resolver = new RootResolverInfo([new CamelCaseQuery1()], options) + + when: + def meta = scanner.findFieldResolver(new FieldDefinition("hull_type", new TypeName("HullType")), resolver) + + then: + meta instanceof MethodFieldResolver + ((MethodFieldResolver) meta).getMethod().getReturnType() == HullType.class + } + class RootQuery1 implements GraphQLQueryResolver { def field1() {} } @@ -99,6 +111,12 @@ class FieldResolverScannerSpec extends Specification { def field1() {} } + class CamelCaseQuery1 implements GraphQLQueryResolver { + HullType getHullType(){} + } + + class HullType {} + class ParentPropertyQuery { private Integer version = 1 }