0

I have two Controllers:

@Controller
@Order(Ordered.LOWEST_PRECEDENCE)
public class BaseController {
    @RequestMapping("/hello.html")
    public String hello(ModelMap model) {
        model.addAttribute("hello", "world");
        return "hello";
    }
}

@Controller
public class ProjectSpecificController {
    @Autowired
    private BaseController baseController;

    @Override
    @RequestMapping("/hello.html")
    public String hello(ModelMap model) {
        model.addAttribute("project", "name");
        return baseController.hello(model);
    }
}

As Spring would trigger this Exception: java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'baseController' bean method public java.lang.String com.example.BaseController.hello(org.springframework.ui.ModelMap) to {[/hello.html],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'projectSpecificController' bean method public java.lang.String com.example.ProjectSpecificController.hello(org.springframework.ui.ModelMap) mapped.

I would like to use the @Order annotation to map ProjectSpecificController.hello first and if there's already a mapping found for /hello.html ignore the other mappings and do not register their methods:

public class OrderedRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    @Override
    protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
        try {
            super.registerHandlerMethod(handler, method, mapping);
        } catch (IllegalStateException e) {
            // mapping already happened for a controller of higher precedence, so ignore
        }
    }
}

Is it enough to catch the exception or do I have to look for the @Order annotation myself? If I have to take care of the @Order annotation myself: What's the best practice to realize my plan?

dtrunk
  • 4,685
  • 17
  • 65
  • 109

1 Answers1

0

If I were you, I would not try to go that way.

If I correctly understand, you have one BaseController and you want to override the processing of an URL. I already did something not too far from that by :

  • delegate processing to a normal method (not @RequestMapping annotated) in base controller
  • override that method in a class extending the controller
  • use the subclass as a bean (and not the parent class)

The hard part is that you have to explicitely declare the proper controller bean. I did it with XML so it was easy (just a line to change i the xml file). In Java config, I would explicitely declare the controller bean in a @Configuration annotated class.

Globally it would look like :

public class BaseController {
    @RequestMapping("/hello.html")
    public String hello(ModelMap model) {
        return doHello(model);
    }
    protected String doHello(ModelMap model) {
        model.addAttribute("hello", "world");
        return "hello";
    }
}

public class ProjectSpecificController extends BaseController{
    @Override
    protected String doHello(ModelMap model) {
        model.addAttribute("project", "name");
        return super.doHello(model);
    }
}

@Configuration
class HelloConfig {
    // other configuration elements ...
    @Bean
    public BaseController helloController() {
        // implement the logic to choose the right implementation
        return (specific ? new ProjectSpecificController() : new BaseController());
    }
    // other configuration elements ...
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • That's not a solution for me. I don't want to explicitly declare all controllers. Btw: I guess you missed the `@Bean` annotation at `HelloConfig.helloController`. – dtrunk Dec 04 '14 at 13:56
  • @dtrunk : fixed the `@Bean annotation` ... I understand your point, by I'm afraid you are overriding Spring MVC at a lower level and I often read that Spring is extensible but not (easily) modifiable. – Serge Ballesta Dec 04 '14 at 14:03
  • It is extensible (that's what I did above) and the way I did it works just great. My questions was just if Spring is taking care of the `@Order` annotation of my `BaseController`. I tried renaming `BaseController` to `ZBaseController` and back again and then renaming `ProjectSpecificController` to `ZProjectSpecificController` and back again and it worked in all cases. So I guess Spring is taking care of the `@Order` annotation. – dtrunk Dec 04 '14 at 14:37
  • This is far beyond my knowledge ! AFAIK there is no notion of `@Order` in RequestMapping annotated controller. But according to [this other anwser](http://stackoverflow.com/a/14443490/3545273), the order of mapping discovery is the order of bean creation. As ProjectSpecific depends on Base, it will be discovered after. My advice is to add a comment in a red flashing font for the case where you come back there later ... – Serge Ballesta Dec 04 '14 at 15:14