javaspring-mvcspring-bean

How to decorate interface driven controllers in spring mvc?


I have a interface driven controller like this:

@ResponseBody
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
@RequestMapping("/foo")
interface Foo {
    @GetMapping("/{id}")
    String bar(String id);
}

And an implementation delegating to the actual business logic

@Controller
public class FooImpl implements Foo {
    @Override
    public String bar(String id) {
        return "<actual business logic>";
    }
}

I would like to decorate interface Foo to add additional functionality to the application.

However when I use a jdk proxy and try to start the application with that spring won't register the endpoints anymore. This is because the bean now isn't annotated with @Controller anymore on the beans type. The annotation is only present on the implementation (and I can't use a @Bean method because that annotation is only allowed on types) and not the proxy, which is now the type spring web mvc sees. I also can't annotate the decoration and implementation with @Controller because then I will have ambigous mappings since the decoration interface and the implementation will be treated as components where handler mappings need to be created for.

I would also like to keep the controller annotation at the implementation for the actual business logic so that its still obvious where the main focus of the controller is.

So how can I decorate an interface driven controller in spring web mvc keeping the actual implementation and any decorations that shall be applied to it distinct?


Solution

  • I created an additional interface for adding back the @Controller annotation to the created proxy:

    @Controller
    public interface AddControllerAnnotations {
    }
    

    And I'm passing this interface additionally to the interfaces of the java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler) call I'm using to create the proxy instance. This way spring will still consider the decorated instance as a controller.

    However this will not scale if there will be more annotations to apply this way.