graphql-java-tools
graphql-java-tools copied to clipboard
The detail message from Checked Exceptions thrown by Resolvers is ignored in ExecutionResult.getErrors()
Description
graphql-java-tools
maps fields on GraphQL objects to methods and properties on "Resolvers" and "Data Classes" thus eliminating the boilerplate code required to setup graphql-java
manually. Resolver methods are invoked via reflection and are free to throw both checked and unchecked exceptions in their method signatures.
When an exception is thrown it eventually ends up as a GraphQLError object in the ExecutionResult.getErrors() list. For runtime exceptions the resulting GraphQLError object inherits their error messages. But for checked exceptions or Throwables (which the Resolver methods are technically free to throw as well) the detail message is lost and a null
is returned.
This problem does not exist in graphql-java
.
Expected behavior
The detail message from Checked Exceptions thrown by Resolvers should be propogated to GraphQLError.getMessage() returned from ExecutionResult.getErrors().
Actual behavior
GraphQLError objects corresponding to Checked Exceptions thrown by Resolvers return a null
in their getMessage().
Steps to reproduce the bug
- Create a simple hello-world demo using a GraphQLQueryResolver (and write the schema accordingly)
- Once the demo works, change the hello() method to throw a checked exception with a message.
- Examine the errors in ExecutionResult.
I have a gist that clearly demonstrates the bug: https://gist.github.com/zleonov/32f45aefdce49d4666877f4d276d5c2a
I took a cursory look at the source code and I think this is where the bug occurs:
src\main\kotlin\graphql\kickstart\tools\resolver\MethodFieldResolver.kt(267):
@Suppress("NOTHING_TO_INLINE")
private inline fun invoke(method: Method, instance: Any, args: Array<Any?>): 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)
}
}
UndeclaredThrowableException does not inherit the detailed message from the underlying exception and as far as I can tell that exception is not unwrapped downstream. UndeclaredThrowableException.getMessage() returns a null
.
I just realized this may be the same issue as #477
Fixed in https://github.com/graphql-java-kickstart/graphql-java-tools/pull/757