@@ -2,7 +2,6 @@ package graphql.kickstart.tools.resolver
22
33import com.fasterxml.jackson.core.type.TypeReference
44import graphql.GraphQLContext
5- import graphql.TrivialDataFetcher
65import graphql.kickstart.tools.*
76import graphql.kickstart.tools.SchemaParserOptions.GenericWrapper
87import graphql.kickstart.tools.util.JavaType
@@ -12,12 +11,15 @@ import graphql.kickstart.tools.util.unwrap
1211import graphql.language.*
1312import graphql.schema.DataFetcher
1413import graphql.schema.DataFetchingEnvironment
14+ import graphql.schema.GraphQLFieldDefinition
1515import graphql.schema.GraphQLTypeUtil.isScalar
16+ import graphql.schema.LightDataFetcher
1617import kotlinx.coroutines.future.future
1718import org.slf4j.LoggerFactory
1819import java.lang.reflect.InvocationTargetException
1920import java.lang.reflect.Method
2021import java.util.*
22+ import java.util.function.Supplier
2123import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
2224import kotlin.reflect.full.valueParameters
2325import kotlin.reflect.jvm.javaType
@@ -122,9 +124,9 @@ internal class MethodFieldResolver(
122124 }
123125
124126 return if (args.isEmpty() && isTrivialDataFetcher(this .method)) {
125- TrivialMethodFieldResolverDataFetcher (getSourceResolver (), this .method, args , options)
127+ LightMethodFieldResolverDataFetcher (createSourceResolver (), this .method, options)
126128 } else {
127- MethodFieldResolverDataFetcher (getSourceResolver (), this .method, args, options)
129+ MethodFieldResolverDataFetcher (createSourceResolver (), this .method, args, options)
128130 }
129131 }
130132
@@ -203,17 +205,8 @@ internal open class MethodFieldResolverDataFetcher(
203205 false
204206 }
205207
206- private class CompareGenericWrappers {
207- companion object : Comparator <GenericWrapper > {
208- override fun compare (w1 : GenericWrapper , w2 : GenericWrapper ): Int = when {
209- w1.type.isAssignableFrom(w2.type) -> 1
210- else -> - 1
211- }
212- }
213- }
214-
215208 override fun get (environment : DataFetchingEnvironment ): Any? {
216- val source = sourceResolver(environment)
209+ val source = sourceResolver.resolve (environment)
217210 val args = this .args.map { it(environment) }.toTypedArray()
218211
219212 return if (isSuspendFunction) {
@@ -240,18 +233,59 @@ internal open class MethodFieldResolverDataFetcher(
240233 */
241234 @Suppress(" unused" )
242235 open fun getWrappedFetchingObject (environment : DataFetchingEnvironment ): Any {
243- return sourceResolver(environment)
236+ return sourceResolver.resolve (environment)
244237 }
245238}
246239
247- // TODO use graphql.schema.LightDataFetcher
248- internal class TrivialMethodFieldResolverDataFetcher (
249- sourceResolver : SourceResolver ,
250- method : Method ,
251- args : List <ArgumentPlaceholder >,
252- options : SchemaParserOptions ,
253- ) : MethodFieldResolverDataFetcher(sourceResolver, method, args, options),
254- TrivialDataFetcher <Any > // just to mark it for tracing and optimizations
240+ /* *
241+ * Similar to [MethodFieldResolverDataFetcher] but for light data fetchers which do not require the environment to be supplied unless suspend functions or
242+ * generic wrappers are used.
243+ */
244+ internal class LightMethodFieldResolverDataFetcher (
245+ private val sourceResolver : SourceResolver ,
246+ private val method : Method ,
247+ private val options : SchemaParserOptions ,
248+ ) : LightDataFetcher<Any?> {
249+
250+ private val resolverMethod = method
251+ private val isSuspendFunction = try {
252+ method.kotlinFunction?.isSuspend == true
253+ } catch (e: InternalError ) {
254+ false
255+ }
256+
257+ override fun get (fieldDefinition : GraphQLFieldDefinition , sourceObject : Any , environmentSupplier : Supplier <DataFetchingEnvironment >): Any? {
258+ return if (isSuspendFunction) {
259+ environmentSupplier.get().coroutineScope().future(options.coroutineContextProvider.provide()) {
260+ invokeSuspend(sourceObject, resolverMethod, emptyArray())?.transformWithGenericWrapper(environmentSupplier)
261+ }
262+ } else {
263+ invoke(resolverMethod, sourceObject, emptyArray())?.transformWithGenericWrapper(environmentSupplier)
264+ }
265+ }
266+
267+ private fun Any.transformWithGenericWrapper (environment : Supplier <DataFetchingEnvironment >): Any? {
268+ return options.genericWrappers
269+ .asSequence()
270+ .filter { it.type.isInstance(this ) }
271+ .sortedWith(CompareGenericWrappers )
272+ .firstOrNull()
273+ ?.transformer?.invoke(this , environment.get()) ? : this
274+ }
275+
276+ override fun get (environment : DataFetchingEnvironment ): Any? {
277+ throw UnsupportedOperationException (" This method should not be called as this is a LightDataFetcher." )
278+ }
279+ }
280+
281+ private class CompareGenericWrappers {
282+ companion object : Comparator <GenericWrapper > {
283+ override fun compare (w1 : GenericWrapper , w2 : GenericWrapper ): Int = when {
284+ w1.type.isAssignableFrom(w2.type) -> 1
285+ else -> - 1
286+ }
287+ }
288+ }
255289
256290private suspend inline fun invokeSuspend (target : Any , resolverMethod : Method , args : Array <Any ?>): Any? {
257291 return suspendCoroutineUninterceptedOrReturn { continuation ->
0 commit comments