Davide Cavestro opened SPR-11809 and commented

When defining two beans annotated with @Controller and providing the same @RequestMapping the container throws an exception complaining

java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'myStdController' bean method... There is already 'myCustomController' bean method

It would be really useful having a simple way to provide a customized version for a standard controller by simply adding a new controller annotated as @Primary and mapping to the same urls. This kind of customization hack works quite well for beans that don't provide mappings (i.e. services). An additional refinement could support some sort of overlaying: the urls not remapped by the @Primary/custom controller could be served by the standard/secondary controller. If using @Primary for this purpose is considered unsafe, then an additional annotation could expose this behavior.


Affects: 3.2.8

3 votes, 5 watchers

Comment From: spring-projects-issues

Davide Cavestro commented

Any idea? So far the best workaround has been moving the controller code to an injected delegate bean, which can easily be customized using @Primary

Comment From: spring-projects-issues

Rossen Stoyanchev commented

Note the ISE is for a conflict between individual HandlerMethod's possibly even within the same class. In other words while with services @Primary helps to select between two components with equally matching types, with controllers we are trying to select between two controller methods with equally matching request mappings. The granularity is different so trying to think of it as one controller replacing another is bound to lead to situations with no good solutions.

What we could do at the point of detecting two controller methods with duplicate request mappings is check whether they belong to different controllers. If so check if one controller is marked @Primary and resolve the conflict in its favor. That also means you can create one @Primary controller and override individual methods in any number of existing controllers where other methods in those existing controllers would continue to work since they don't have conflicts.

This is certainly doable. I guess the question is whether it's stretching the meaning of how @Primary is used today.

What do you think Juergen Hoeller?

Comment From: spring-projects-issues

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.

Comment From: a-sayyed

In case someone is still looking for a workaround for this issue: What you need to do, is deregister the existing handler methods from the other controller, and register your (new) handler method instead. This could be done as follows:

    @Autowired
    public void registerOverriddenControllerEndpoint(final RequestMappingHandlerMapping handlerMapping,
            final NewController controller) throws NoSuchMethodException {

        final RequestMappingInfo mapping = RequestMappingInfo.paths("path/to/be/overridden")
           .methods(RequestMethod.GET) // or any other request method
           .build();

        handlerMapping.unregisterMapping(mapping);
        Class[] argTypes = new Class[]{/* The parameter types needed for the 'methodThatHandlesTheEndpoint' method */};
        handlerMapping.registerMapping(mapping, controller, NewController.class.getMethod("methodThatHandlesTheEndpoint", argTypes));
    }

    @Bean
    NewController newController() {
        return new NewController();
    }