3
votes

I have made an annotation for aop. When I use it at any method rather than controller methods it works well. However when I use it at my controller's methods my controller stops working. It starts to give 404 not found error for mappings. I found a similar question here: Spring 3 MVC @Controller with AOP interceptors? but I don' know how to do it. My method at my controller is that:

@WebAuditable // This is my annotation that works at other methods
@Override
@RequestMapping(value = "/ad", method = RequestMethod.POST, headers = "Accept=application/json")
public
@ResponseBody
Cd create(HttpServletResponse response, @RequestBody Cd cd) {
    ...
}

My interface that my controller implements is that:

public interface BaseController<T> {

    public List<T> getAll(HttpServletResponse response);

    public T getByName(HttpServletResponse response, String id);

    public T create(HttpServletResponse response, T t);

    public T update(HttpServletResponse response, T t);

}

Any advices?

PS: @SeanPatrickFloyd says that:

Note When using controller interfaces (e.g. for AOP proxying), make sure to consistently put all your mapping annotations - such as @RequestMapping and @SessionAttributes - on the controller interface rather than on the implementation class

1

1 Answers

4
votes

The thing is: controller mapping is done at runtime, and if you use AOP proxies, the proxy objects don't have annotations at runtime, only their interfaces do. I can think of two possible strategies to work around this limitation.

Either annotate the generic interface methods, or (if you don't want to advise all controllers) create a sub-interface per implementation type, explicitly annotating their methods. I know that's a lot of rewritten code and contrary to what AOP is about, but I don't know a better way when sticking with interface based proxies.

Another way would be to switch to CGLib proxies using proxy-target-class="true". That way the proxy classes should (I'm not sure about this) retain the annotations.

Update: annotating your interface should work like this (if it works)

public interface BaseController<T> {

    @WebAuditable
    public List<T> getAll(HttpServletResponse response);

    @WebAuditable
    public T getByName(HttpServletResponse response, String id);

    @WebAuditable
    public T create(HttpServletResponse response, T t);

    @WebAuditable
    public T update(HttpServletResponse response, T t);

}

Annotating a base class won't work, because JDK proxies don't expose any information that's not backed by interfaces.