Injected dependencies of Controller are sometimes null when using @SchemaMapping

Injected dependencies of Controller are sometimes null when using @SchemaMapping


1

I have a problem on a SpringBoot (3.2.0) application that uses GraphQL with spring-boot-starter-graphql.

I have several annotated controllers that contain some @SchemaMapping, @QueryMapping and @MutationMapping. For some reasons that I can’t figure out, some @SchemaMapping methods will be called but the injected dependencies of the Controller are null, leading to a NPE.

@Controller
@AllArgsConstructor
public class MyController{
    private final MyService service;

    // This one is working
    @SchemaMapping(typeName = "Foo", field = "bar")
    public String getBar(Foo foo) {
        return service.someMethod();
    }

    // This one is NOT working : service is null
    @SchemaMapping(typeName = "Foo", field = "bar2")
    public String getBar2(Foo foo) {
        return service.someOtherMethod()
    }
}

When I put breakpoint inside a @SchemaMapping method that I know it is not working, I can see that the type of the controller is MyController$$SpringCGLIB$$0@17823 and just MyController when it works. And when I look at the Threads stack for a "wrong" call and a "good" call I see a difference : the org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:713) method is called when its working.

Example of "good" stacktrace :

java.lang.Thread.State: RUNNABLE
      at com.company.project.controller.MyController.getData(MyController.java:39)
      at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
      at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
      at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:568)
      at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:352)
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:713)
      at com.company.project.controller.MyController$$SpringCGLIB$$0.getData(<generated>:-1)
      at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
      at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
      at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:568)
      at org.springframework.graphql.data.method.InvocableHandlerMethodSupport.doInvoke(InvocableHandlerMethodSupport.java:87)

Example of "wrong" stacktrace :

java.lang.Thread.State: RUNNABLE
      at com.company.project.controller.MyController.getData(MyController.java:44)
      at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
      at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
      at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:568)
      at org.springframework.graphql.data.method.InvocableHandlerMethodSupport.doInvoke(InvocableHandlerMethodSupport.java:87)

It seems that for some @SchemaMapping methods the AOP Proxy of the controller is frozen and cannot be intercepted.

If anyone has any idea what’s going on, any help is welcome :). Thanks

2 Answers
2


1

It seems like the issue is with Spring’s AOP proxy not being applied consistently to all @SchemaMapping methods, resulting in null dependencies. You should ensure that all methods in the controller that require dependency injection are properly intercepted by the Spring AOP proxy.

Try this instead:

@Controller
@AllArgsConstructor
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyController {
    private final MyService service;

    @SchemaMapping(typeName = "Foo", field = "bar")
    public String getBar(Foo foo) {
        return service.someMethod();
    }

    @SchemaMapping(typeName = "Foo", field = "bar2")
    public String getBar2(Foo foo) {
        return service.someOtherMethod();
    }
}

Let me know if this does the trick.


0

Can you make sure to try annotating the MyService to @Service and autowire myService?

@Autowire
private MyService myService;

Spring’s AOP infrastructure automatically uses CGLIB or JDK dynamic proxies unless any condition is stopping it from doing that.

For AOP proxy, a final class is generally not considered a suitable proxy target, as Spring AOP cannot create subclasses or extend a final classes. It needs this ability to create CGLIB-based proxies for myService, by using which you will be calling proxy of someMethod().

Note that this is happening because @SchemaMapping

Let me know if this worked for you.



Leave a Reply

Your email address will not be published. Required fields are marked *