Skip to content

Commit 0aa962a

Browse files
authored
Merge branch 'master' into hotfix-java-proxy
2 parents b114b0d + 0e4b8a9 commit 0aa962a

File tree

4 files changed

+86
-5
lines changed

4 files changed

+86
-5
lines changed

src/main/kotlin/com/coxautodev/graphql/tools/MethodFieldResolver.kt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.coxautodev.graphql.tools
33
import com.coxautodev.graphql.tools.SchemaParserOptions.GenericWrapper
44
import com.esotericsoftware.reflectasm.MethodAccess
55
import com.fasterxml.jackson.core.type.TypeReference
6+
import graphql.TrivialDataFetcher
67
import graphql.execution.batched.Batched
78
import graphql.language.FieldDefinition
89
import graphql.language.ListType
@@ -11,7 +12,7 @@ import graphql.language.Type
1112
import graphql.language.TypeName
1213
import graphql.schema.DataFetcher
1314
import graphql.schema.DataFetchingEnvironment
14-
import graphql.schema.GraphQLTypeUtil.isScalar
15+
import graphql.schema.GraphQLTypeUtil.*
1516
import kotlinx.coroutines.GlobalScope
1617
import kotlinx.coroutines.future.future
1718
import java.lang.reflect.Method
@@ -116,17 +117,24 @@ internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolver
116117
return if (batched) {
117118
BatchedMethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
118119
} else {
119-
MethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
120+
if (args.isEmpty() && isTrivialDataFetcher(this.method)) {
121+
TrivialMethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
122+
} else {
123+
MethodFieldResolverDataFetcher(getSourceResolver(), this.method, args, options)
124+
}
125+
120126
}
121127
}
122128

123129
private fun isScalarType(environment: DataFetchingEnvironment, type: Type<*>, genericParameterType: JavaType): Boolean =
124-
when (type) {
125-
is ListType ->
130+
when {
131+
type is ListType ->
126132
List::class.java.isAssignableFrom(this.genericType.getRawClass(genericParameterType))
127133
&& isScalarType(environment, type.type, this.genericType.unwrapGenericType(genericParameterType))
128-
is TypeName ->
134+
type is TypeName ->
129135
environment.graphQLSchema?.getType(type.name)?.let { isScalar(it) } ?: false
136+
type is NonNullType && type.type is TypeName ->
137+
environment.graphQLSchema?.getType((type.type as TypeName).name)?.let { isScalar(unwrapNonNull(it)) } ?: false
130138
else ->
131139
false
132140
}
@@ -221,6 +229,10 @@ open class MethodFieldResolverDataFetcher(private val sourceResolver: SourceReso
221229
}
222230
}
223231

232+
open class TrivialMethodFieldResolverDataFetcher(private val sourceResolver: SourceResolver, method: Method, private val args: List<ArgumentPlaceholder>, private val options: SchemaParserOptions) : MethodFieldResolverDataFetcher(sourceResolver, method, args, options), TrivialDataFetcher<Any> {
233+
234+
}
235+
224236
private suspend inline fun MethodAccess.invokeSuspend(target: Any, methodIndex: Int, args: Array<Any?>): Any? {
225237
return suspendCoroutineUninterceptedOrReturn { continuation ->
226238
invoke(target, methodIndex, *args + continuation)

src/main/kotlin/com/coxautodev/graphql/tools/Utils.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import graphql.language.NonNullType
66
import graphql.language.ObjectTypeDefinition
77
import graphql.language.ObjectTypeExtensionDefinition
88
import graphql.language.Type
9+
import java.lang.reflect.Method
910
import java.lang.reflect.ParameterizedType
1011
import java.lang.reflect.Proxy
1112

@@ -36,10 +37,30 @@ internal fun JavaType.unwrap(): Class<out Any> =
3637
this as Class<*>
3738
}
3839

40+
3941
internal val Class<*>.declaredNonProxyMethods: List<JavaMethod>
4042
get() {
4143
return when {
4244
Proxy.isProxyClass(this) -> emptyList()
4345
else -> this.declaredMethods.toList()
4446
}
4547
}
48+
49+
/**
50+
* Simple heuristic to check is a method is a trivial data fetcher.
51+
*
52+
* Requirements are:
53+
* prefixed with get
54+
* must have zero parameters
55+
*/
56+
internal fun isTrivialDataFetcher(method: Method): Boolean {
57+
return (method.parameterCount == 0
58+
&& (
59+
method.name.startsWith("get")
60+
|| isBooleanGetter(method)))
61+
}
62+
63+
private fun isBooleanGetter(method: Method) = (method.name.startsWith("is")
64+
&& (method.returnType == java.lang.Boolean::class.java)
65+
|| method.returnType == Boolean::class.java)
66+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.coxautodev.graphql.tools;
2+
3+
public class UtilsTestTrivialDataFetcherBean {
4+
5+
public boolean isBooleanPrimitive() {
6+
return false;
7+
}
8+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.coxautodev.graphql.tools
2+
3+
import org.junit.Assert
4+
import org.junit.Test
5+
6+
class UtilsTest {
7+
8+
@Suppress("unused")
9+
class Bean {
10+
fun getterValid(): String = ""
11+
12+
fun getterWithArgument(@Suppress("UNUSED_PARAMETER") arg1: String): String = ""
13+
14+
internal fun getterInternal(): String = ""
15+
16+
fun notAGetter(): String = ""
17+
18+
fun isString(): String = ""
19+
20+
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
21+
fun isJavaBoolean(): java.lang.Boolean = java.lang.Boolean(false)
22+
23+
fun isKotlinBoolean(): Boolean = false
24+
}
25+
26+
@Test
27+
fun `isTrivialDataFetcher`() {
28+
val clazz = Bean::class.java
29+
30+
Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("getterValid")))
31+
Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("getterWithArgument", String::class.java)))
32+
Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("notAGetter")))
33+
34+
Assert.assertFalse(isTrivialDataFetcher(clazz.getMethod("isString")))
35+
Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("isJavaBoolean")))
36+
Assert.assertTrue(isTrivialDataFetcher(clazz.getMethod("isKotlinBoolean")))
37+
38+
Assert.assertTrue(isTrivialDataFetcher(UtilsTestTrivialDataFetcherBean::class.java.getMethod("isBooleanPrimitive")))
39+
}
40+
}

0 commit comments

Comments
 (0)