graphql-java-tools icon indicating copy to clipboard operation
graphql-java-tools copied to clipboard

ClassCastException when a resolver is simultaneously suspending & using the custom context class.

Open alacoste opened this issue 6 years ago • 1 comments

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.

alacoste avatar Oct 02 '19 14:10 alacoste

PRs are always welcome.

vojtapol avatar Feb 04 '20 15:02 vojtapol