Skip to content

Commit 2f6689e

Browse files
committed
Simplify lightweight data fetcher heuristic
1 parent 698708a commit 2f6689e

File tree

6 files changed

+16
-65
lines changed

6 files changed

+16
-65
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<groupId>com.graphql-java-kickstart</groupId>
66
<artifactId>graphql-java-tools</artifactId>
7-
<version>14.0.0-LOCAL</version>
7+
<version>14.1.0-LOCAL</version>
88
<packaging>jar</packaging>
99

1010
<name>GraphQL Java Tools</name>

src/main/kotlin/graphql/kickstart/tools/resolver/MapFieldResolver.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ internal class MapFieldResolverDataFetcher(
5555
private val key: String,
5656
) : LightDataFetcher<Any> {
5757

58-
override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier<DataFetchingEnvironment>): Any? {
58+
override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier<DataFetchingEnvironment>): Any? {
5959
if (sourceObject is Map<*, *>) {
6060
return sourceObject[key]
6161
} else {

src/main/kotlin/graphql/kickstart/tools/resolver/MethodFieldResolver.kt

+13-26
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import graphql.kickstart.tools.*
66
import graphql.kickstart.tools.SchemaParserOptions.GenericWrapper
77
import graphql.kickstart.tools.util.JavaType
88
import graphql.kickstart.tools.util.coroutineScope
9-
import graphql.kickstart.tools.util.isTrivialDataFetcher
109
import graphql.kickstart.tools.util.unwrap
1110
import graphql.language.*
1211
import graphql.schema.DataFetcher
@@ -37,13 +36,9 @@ internal class MethodFieldResolver(
3736

3837
private val log = LoggerFactory.getLogger(javaClass)
3938

40-
private val additionalLastArgument =
41-
try {
42-
(method.kotlinFunction?.valueParameters?.size
43-
?: method.parameterCount) == (field.inputValueDefinitions.size + getIndexOffset() + 1)
44-
} catch (e: InternalError) {
45-
method.parameterCount == (field.inputValueDefinitions.size + getIndexOffset() + 1)
46-
}
39+
private val isSuspendFunction = method.isSuspendFunction()
40+
private val numberOfParameters = method.kotlinFunction?.valueParameters?.size ?: method.parameterCount
41+
private val hasAdditionalParameter = numberOfParameters == (field.inputValueDefinitions.size + getIndexOffset() + 1)
4742

4843
override fun createDataFetcher(): DataFetcher<*> {
4944
val args = mutableListOf<ArgumentPlaceholder>()
@@ -100,7 +95,7 @@ internal class MethodFieldResolver(
10095
}
10196

10297
// Add DataFetchingEnvironment/Context argument
103-
if (this.additionalLastArgument) {
98+
if (this.hasAdditionalParameter) {
10499
when (this.method.parameterTypes.last()) {
105100
null -> throw ResolverError("Expected at least one argument but got none, this is most likely a bug with graphql-java-tools")
106101
options.contextClass -> args.add { environment ->
@@ -123,10 +118,12 @@ internal class MethodFieldResolver(
123118
}
124119
}
125120

126-
return if (args.isEmpty() && isTrivialDataFetcher(this.method)) {
127-
LightMethodFieldResolverDataFetcher(createSourceResolver(), this.method, options)
121+
return if (numberOfParameters > 0 || isSuspendFunction) {
122+
// requires arguments and environment or is a suspend function
123+
MethodFieldResolverDataFetcher(createSourceResolver(), this.method, args, options, isSuspendFunction)
128124
} else {
129-
MethodFieldResolverDataFetcher(createSourceResolver(), this.method, args, options)
125+
// if there are no parameters an optimized version of the data fetcher can be used
126+
LightMethodFieldResolverDataFetcher(createSourceResolver(), this.method, options)
130127
}
131128
}
132129

@@ -196,10 +193,9 @@ internal class MethodFieldResolverDataFetcher(
196193
private val method: Method,
197194
private val args: List<ArgumentPlaceholder>,
198195
private val options: SchemaParserOptions,
196+
private val isSuspendFunction: Boolean
199197
) : DataFetcher<Any> {
200198

201-
private val isSuspendFunction = method.isSuspendFunction()
202-
203199
override fun get(environment: DataFetchingEnvironment): Any? {
204200
val source = sourceResolver.resolve(environment, null)
205201
val args = this.args.map { it(environment) }.toTypedArray()
@@ -223,27 +219,18 @@ internal class MethodFieldResolverDataFetcher(
223219
}
224220

225221
/**
226-
* Similar to [MethodFieldResolverDataFetcher] but for light data fetchers which do not require the environment to be supplied unless suspend functions or
227-
* generic wrappers are used.
222+
* Similar to [MethodFieldResolverDataFetcher] but for light data fetchers which do not require the environment to be supplied unless generic wrappers are used.
228223
*/
229224
internal class LightMethodFieldResolverDataFetcher(
230225
private val sourceResolver: SourceResolver,
231226
private val method: Method,
232227
private val options: SchemaParserOptions,
233228
) : LightDataFetcher<Any?> {
234229

235-
private val isSuspendFunction = method.isSuspendFunction()
236-
237-
override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier<DataFetchingEnvironment>): Any? {
230+
override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier<DataFetchingEnvironment>): Any? {
238231
val source = sourceResolver.resolve(null, sourceObject)
239232

240-
return if (isSuspendFunction) {
241-
environmentSupplier.get().coroutineScope().future(options.coroutineContextProvider.provide()) {
242-
invokeSuspend(source, method, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier)
243-
}
244-
} else {
245-
invoke(method, source, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier)
246-
}
233+
return invoke(method, source, emptyArray())?.transformWithGenericWrapper(options.genericWrappers, environmentSupplier)
247234
}
248235

249236
override fun get(environment: DataFetchingEnvironment): Any? {

src/main/kotlin/graphql/kickstart/tools/resolver/PropertyFieldResolver.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ internal class PropertyFieldResolverDataFetcher(
4444
private val field: Field,
4545
) : LightDataFetcher<Any> {
4646

47-
override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any, environmentSupplier: Supplier<DataFetchingEnvironment>): Any? {
47+
override fun get(fieldDefinition: GraphQLFieldDefinition, sourceObject: Any?, environmentSupplier: Supplier<DataFetchingEnvironment>): Any? {
4848
return field.get(sourceResolver.resolve(null, sourceObject))
4949
}
5050

src/main/kotlin/graphql/kickstart/tools/util/Utils.kt

-18
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,4 @@ internal fun getDocumentation(node: AbstractNode<*>, options: SchemaParserOption
6161
.trimIndent()
6262
}
6363

64-
/**
65-
* Simple heuristic to check if a method is a trivial data fetcher.
66-
*
67-
* Requirements are:
68-
* - prefixed with get
69-
* - must have zero parameters
70-
*/
71-
internal fun isTrivialDataFetcher(method: Method): Boolean {
72-
return (method.parameterCount == 0
73-
&& (
74-
method.name.startsWith("get")
75-
|| isBooleanGetter(method)))
76-
}
77-
78-
private fun isBooleanGetter(method: Method) = (method.name.startsWith("is")
79-
&& (method.returnType == java.lang.Boolean::class.java)
80-
|| method.returnType == Boolean::class.java)
81-
8264
internal fun String.snakeToCamelCase(): String = split("_").joinToString(separator = "") { it.replaceFirstChar(Char::titlecase) }
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package graphql.kickstart.tools.util
22

3-
import org.junit.Assert
4-
import org.junit.Test
5-
63
class UtilsTest {
74

85
@Suppress("unused")
@@ -26,19 +23,4 @@ class UtilsTest {
2623
private class UtilsTestTrivialDataFetcherBean {
2724
val isBooleanPrimitive = false
2825
}
29-
30-
@Test
31-
fun isTrivialDataFetcher() {
32-
val clazz = Bean::class.java
33-
34-
Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("getterValid")))
35-
Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("getterWithArgument", String::class.java)))
36-
Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("notAGetter")))
37-
38-
Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("isString")))
39-
Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("isJavaBoolean")))
40-
Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("isKotlinBoolean")))
41-
42-
Assert.assertTrue(isTrivialDataFetcher(UtilsTestTrivialDataFetcherBean::class.java.getMethod("isBooleanPrimitive")))
43-
}
4426
}

0 commit comments

Comments
 (0)