@@ -29,6 +29,8 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
2929
3030 private val allowedLastArgumentTypes = listOfNotNull(DataFetchingEnvironment ::class .java, GraphQLContext ::class .java, options.contextClass)
3131
32+ private val methodsByNameCache = mutableMapOf<Pair <Class <out Any >, Boolean > , Map <String , List <Method >>>()
33+
3234 fun findFieldResolver (field : FieldDefinition , resolverInfo : ResolverInfo ): FieldResolver {
3335 val searches = resolverInfo.getFieldSearches()
3436
@@ -86,29 +88,34 @@ internal class FieldResolverScanner(val options: SchemaParserOptions) {
8688 }
8789
8890 private fun findResolverMethod (field : FieldDefinition , search : Search ): Method ? {
89- val methods = getAllMethods (search)
91+ val methodsByName = getMethodsByName (search)
9092 val argumentCount = field.inputValueDefinitions.size + if (search.requiredFirstParameterType != null ) 1 else 0
9193 val name = field.name
94+ val capitalizedName = name.replaceFirstChar(Char ::titlecase)
9295
9396 // Check for the following one by one:
9497 // 1. Method with exact field name
9598 // 2. Method that returns a boolean with "is" style getter
9699 // 3. Method with "get" style getter
97100 // 4. Method with "getField" style getter
98101 // 5. Method with "get" style getter with the field name converted from snake_case to camelCased. ex: key_ops -> getKeyOps()
99- return methods.find {
100- it.name == name && verifyMethodArguments(it, argumentCount, search)
101- } ? : methods.find {
102- (isBoolean(field.type) && it.name == " is${name.replaceFirstChar(Char ::titlecase)} " ) && verifyMethodArguments(it, argumentCount, search)
103- } ? : methods.find {
104- it.name == " get${name.replaceFirstChar(Char ::titlecase)} " && verifyMethodArguments(it, argumentCount, search)
105- } ? : methods.find {
106- it.name == " getField${name.replaceFirstChar(Char ::titlecase)} " && verifyMethodArguments(it, argumentCount, search)
107- } ? : methods.find {
108- it.name == " get${name.snakeToCamelCase()} " && verifyMethodArguments(it, argumentCount, search)
102+ return listOfNotNull(
103+ name,
104+ if (isBoolean(field.type)) " is$capitalizedName " else null ,
105+ " get$capitalizedName " ,
106+ " getField$capitalizedName " ,
107+ " get${name.snakeToCamelCase()} "
108+ ).firstNotNullOfOrNull { methodName ->
109+ methodsByName[methodName]?.find { verifyMethodArguments(it, argumentCount, search) }
109110 }
110111 }
111112
113+ // root fields are searched on every root resolver, so each class's methods are only indexed once
114+ private fun getMethodsByName (search : Search ): Map <String , List <Method >> =
115+ methodsByNameCache.getOrPut(search.type.unwrap() to search.isSubscription) {
116+ getAllMethods(search).groupBy { it.name }
117+ }
118+
112119 private fun getAllMethods (search : Search ): List <Method > {
113120 val type = search.type.unwrap()
114121 val declaredMethods = type.declaredNonProxyMethods
0 commit comments