diff --git a/pom.xml b/pom.xml index a5b934f6..972cb720 100644 --- a/pom.xml +++ b/pom.xml @@ -104,11 +104,6 @@ jackson-datatype-jdk8 ${jackson.version} - - com.esotericsoftware - reflectasm - 1.11.9 - org.apache.commons commons-lang3 diff --git a/src/main/kotlin/graphql/kickstart/tools/MethodFieldResolver.kt b/src/main/kotlin/graphql/kickstart/tools/MethodFieldResolver.kt index bb3dd955..09035b2d 100644 --- a/src/main/kotlin/graphql/kickstart/tools/MethodFieldResolver.kt +++ b/src/main/kotlin/graphql/kickstart/tools/MethodFieldResolver.kt @@ -1,6 +1,5 @@ package graphql.kickstart.tools -import com.esotericsoftware.reflectasm.MethodAccess import com.fasterxml.jackson.core.type.TypeReference import graphql.TrivialDataFetcher import graphql.execution.batched.Batched @@ -182,9 +181,7 @@ internal class MethodFieldResolver(field: FieldDefinition, search: FieldResolver open class MethodFieldResolverDataFetcher(private val sourceResolver: SourceResolver, method: Method, private val args: List, private val options: SchemaParserOptions) : DataFetcher { - // Convert to reflactasm reflection - private val methodAccess = MethodAccess.get(method.declaringClass)!! - private val methodIndex = methodAccess.getIndex(method.name, *method.parameterTypes) + private val resolverMethod = method private val isSuspendFunction = try { method.kotlinFunction?.isSuspend == true } catch (e: InternalError) { @@ -206,10 +203,10 @@ open class MethodFieldResolverDataFetcher(private val sourceResolver: SourceReso return if (isSuspendFunction) { environment.coroutineScope().future(options.coroutineContextProvider.provide()) { - methodAccess.invokeSuspend(source, methodIndex, args)?.transformWithGenericWrapper(environment) + invokeSuspend(source, resolverMethod, args)?.transformWithGenericWrapper(environment) } } else { - methodAccess.invoke(source, methodIndex, *args)?.transformWithGenericWrapper(environment) + invoke(resolverMethod, source, args)?.transformWithGenericWrapper(environment) } } @@ -236,9 +233,26 @@ open class TrivialMethodFieldResolverDataFetcher(sourceResolver: SourceResolver, } -private suspend inline fun MethodAccess.invokeSuspend(target: Any, methodIndex: Int, args: Array): Any? { +private suspend inline fun invokeSuspend(target: Any, resolverMethod: Method, args: Array): Any? { return suspendCoroutineUninterceptedOrReturn { continuation -> - invoke(target, methodIndex, *args + continuation) + invoke(resolverMethod, target, args + continuation) + } +} + +@Suppress("NOTHING_TO_INLINE") +private inline fun invoke(method: Method, instance:Any, args: Array): Any? { + try { + return method.invoke(instance, *args) + } catch (invocationException: java.lang.reflect.InvocationTargetException) { + val e = invocationException.cause + if (e is RuntimeException) { + throw e + } + if (e is Error) { + throw e + } + + throw java.lang.reflect.UndeclaredThrowableException(e); } } diff --git a/src/test/groovy/graphql/kickstart/tools/EndToEndSpec.groovy b/src/test/groovy/graphql/kickstart/tools/EndToEndSpec.groovy index f77555a5..7bbcc3d2 100644 --- a/src/test/groovy/graphql/kickstart/tools/EndToEndSpec.groovy +++ b/src/test/groovy/graphql/kickstart/tools/EndToEndSpec.groovy @@ -1,5 +1,6 @@ package graphql.kickstart.tools +import graphql.ExecutionInput import graphql.ExecutionResult import graphql.GraphQL import graphql.execution.AsyncExecutionStrategy @@ -664,4 +665,17 @@ class EndToEndSpec extends Specification { data.arrayItems.collect { it.name } == ['item1', 'item2'] } + def "generated schema should re-throw original runtime exception when executing a resolver method"() { + when: + + gql.execute(ExecutionInput.newExecutionInput().query(''' + { + throwsIllegalArgumentException + } + ''' + )) + + then: + IllegalArgumentException + } } diff --git a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt index 730bf91d..69e4b5df 100644 --- a/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt +++ b/src/test/kotlin/graphql/kickstart/tools/EndToEndSpecHelper.kt @@ -81,6 +81,8 @@ type Query { coroutineItems: [Item!]! arrayItems: [Item!]! + + throwsIllegalArgumentException: String } type ExtendedType { @@ -296,6 +298,10 @@ class Query : GraphQLQueryResolver, ListListResolver() { suspend fun coroutineItems(): List = CompletableDeferred(items).await() fun arrayItems() = items.toTypedArray() + + fun throwsIllegalArgumentException(): String { + throw IllegalArgumentException("Expected") + } } class UnusedRootResolver : GraphQLQueryResolver