graphql-java-tools
                                
                                
                                
                                    graphql-java-tools copied to clipboard
                            
                            
                            
                        ClassCastException when a resolver is simultaneously suspending & using the custom context class.
Example that would trigger the bug:
graphql schema:
schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}
type Query {
  myQuery: Boolean!
}
Resolver:
object Query : GraphQLQueryResolver {
  suspend fun myQuery(context: MyCustomContextType): Boolean {
    /* some logic */
    return true
  }
}
With such an example, graphql-java-kickstart successfully wires the schema, but at runtime during resolution of the 'myQuery' field, the following ClassCastException error is thrown:
ERROR ace.graphql.errors.CustomDataFetcherExceptionHandler - class graphql.schema.DataFetchingEnvironmentImpl cannot be cast to class MyCustomContextType
After some debugging I believe that the bug resides in MethodFieldResolver.kt, inside of override fun createDataFetcher(): DataFetcher<*> in the following block of code:
override fun createDataFetcher(): DataFetcher<*> {
        [...]
        // Add DataFetchingEnvironment/Context argument
        if (this.additionalLastArgument) {
            when (this.method.parameterTypes.last()) {
                null -> throw ResolverError("Expected at least one argument but got none, this is most likely a bug with graphql-java-tools")
                options.contextClass -> args.add { environment -> environment.getContext() }
                else -> args.add { environment -> environment }
            }
        }
        [...]
}
This piece of code is the one that creates the lambda that will compute the additional environment/context argument passed to the method at resolution time from the DataFetchingEnvironment.
It looks at the method's last argument type to decide if it should pass the DataFetchingEnvironment as-is or extract the custom context. However in the case of suspending function the actual last argument will be the Continuation, not the DataFetchingEnvironment/Context.
The bug is silent unless you resolver is simultaneously suspending and using a custom context because of the generous "else" case that passes the environment even when the "supposedly" expected type is Continuation.
Thanks for the library & let me know if you would like me to make a small PR to fix this bug or would rather tackle it yourselves.
PRs are always welcome.