You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Resolvers behind a JDK dynamic proxy build fine but fail on every field at runtime #822
A resolver wrapped in a JDK dynamic proxy (for example Spring AOP without proxyTargetClass) passes build(), but every field it resolves fails at query time:
IllegalArgumentException: object of type jdk.proxy2.$Proxy11 is not an instance of com.example.ProxiedQuery
Repro (master, 14.0.4-SNAPSHOT)
classProxiedQuery : GraphQLQueryResolver {
funtest(): String="ok"
}
val resolver =ProxyFactory(ProxiedQuery()).proxy asGraphQLQueryResolver// JDK dynamic proxyval schema =SchemaParser.newParser()
.schemaString("type Query { test: String }")
.resolvers(resolver)
.build()
.makeExecutableSchema()
GraphQL.newGraphQL(schema).build().execute("{ test }")
// data={test=null}// errors=[ExceptionWhileDataFetching{path=[test], exception=java.lang.IllegalArgumentException: object of type jdk.proxy2.$Proxy11 is not an instance of ...ProxiedQuery}]
The same resolver behind a CGLIB proxy works.
Cause
Spring4AopProxyHandler.getTargetClass returns the target class, so the resolver methods are found on ProxiedQuery. MethodFieldResolver.invoke (MethodFieldResolver.kt:286) then calls them on the proxy instance, which isn't a ProxiedQuery.
The existing test SchemaParserTest."parser handles spring AOP proxied resolvers by default" uses this kind of proxy but only builds the schema, so it doesn't catch this.
Fix
Invoking the method on the unwrapped target would skip the proxy's interceptors (e.g. @PreAuthorize), so that's not an option. Either:
fail at build() with a clear message, e.g. "resolver X is a JDK dynamic proxy, use class-based proxies", or
call through Proxy.getInvocationHandler(proxy) so interceptors still run (needs checking against non-Spring handlers).
Activity