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();
}