Search code examples
javaspringaspectjaspect

Constructor of Spring Boot RestController not invoked when using aspect


I am new to AOP and currently trying to implement an aspect for controller methods annotated with a custom annotation. I allways get a NullPointerException on repository when myFunction is invoked. It seems that i have two instances of of the controller. One of them is instantiated without autowiring the repository. When i remove @MyAnnotation everything works as expected.

Can you give me any hint on how to force Spring/AspectJ to use my constructor?

My controller looks like:

@RestController
@RequestMapping(value = "/api")
public class MyController {
    private Repository repository;

    public MyController(Repository repository) {
        this.repository = repository;
    }

    @RequestMapping(value = "/{variable1}", method = GET)
    @MyAnnotation
    public final FeatureCollection myFunction(
        final @PathVariable(required = true) long variable1
    ) {
        repository.findById(variable1);
        (...)
    }
}

The aspect:

@Aspect
public class MyAspect {
    @Around("@annotation(MyAnnotation)")
    public Object any(ProceedingJoinPoint pjp) throws Throwable {
        return pjp.proceed();
    }
}

The configuration:

@Configuration
@EnableAspectJAutoProxy
public class WebConfig {
    @Bean
    public MyAspect myAspect() {
        return new MyAspect();
    }
}

Solution

  • It comes from the fact that the annotated method is final.

    If you can remove the final keyword, it'll work.

    If you google something like "spring aop final methods", you'll find more info, but basically, when Spring creates the proxy, it generates a subclass from your original class, to wrap the call to super with your aspect. The problem is that a final method cannot be inherited by the subclass, so that makes it hard for the proxy to work. Therefore, a lot of limitations come from that, and AOP doesn't work that much with final stuff.

    This limitation is mentioned in the docs, I don't think you'll get a workaround for it:

    11.6 Proxying mechanisms

    ...

    final methods cannot be advised, as they cannot be overridden.

    Hoping this will help you!