Request Mapping with multiple Rest Controllers

In this post we will look at a possible problem when multiple rest controllers are defined onto the same path and how to use multiple rest controllers within your application. I used Spring Boot to write this application.

So what happens when you have two rest controller defined onto the same path? If you don’t have any overlapping request mappings other than the code being slightly confusing, nothing will actually go wrong and you can successfully send requests to the methods inside each controller. But if you have the same mapping defined in each one, then you are going to run into a problem.

In the code below there are two different controllers where both are mapped to the same path and also each contain a mapping to the same location.



If you were to start up you application now the following stack trace would appear in your console.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: 
Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'userRestController' method
public lankydan.tutorial.springboot.dto.UserDTO lankydan.tutorial.springboot.controller.UserRestController.getFromUserController()
to {[/get]}: There is already 'personRestController' bean method
public lankydan.tutorial.springboot.dto.PersonDTO lankydan.tutorial.springboot.controller.PersonRestController.getFromPersonController() mapped.
 at ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at$1.getObject( ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
 at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh( ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
 at org.springframework.boot.SpringApplication.refresh( [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
 at org.springframework.boot.SpringApplication.refreshContext( [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
 at [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
 at [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
 at [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
 at lankydan.tutorial.springboot.Application.main( [classes/:na]
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'userRestController' method

From looking at this stack trace it paints quite a clear picture at what has gone wrong.

Starting from the top

Ambiguous mapping. Cannot map 'userRestController' method

telling us that there must be at least one other place that has the same mapping defined.

Going down a line

UserRestController.getFromUserController() to {[/get]}: There is already 'personRestController' bean method

Makes it even clearer. UserRestController.getFromUserController() is mapped to /get but there is already one on the PersonRestController.

And just to be sure

PersonRestController.getFromPersonController() mapped

Indicating which method in the PersonRestController has already taken the /get mapping.

This can be tested by commenting out the getFromUserController method in UserRestController, restarting the application and sending the request via postman.

The results will be

 "firstName": "Joe",
 "secondName": "Blogs",
 "dateOfBirth": "07/04/2017",
 "profession": "Programmer",
 "salary": 0

which is the JSON of the PersonDTO that was correctly returned from the get method in the PersonRestController, which is now the only request mapping trying to point to /get

To double check that the other request mappings can be accessed we can send a request to /getUser and /getPerson which will both return the expected JSON.

A possible fix to this is to change the request mapping path of one of the controller methods. This will quickly fix this problem but suggests that these methods should be not only separated by class but also by their request mappings. Which leads onto a better solutions.

One solution is to manually append a base mapping to each @RequestMapping annotation.

This would be defined by


This would fix the immediate problem but will not prevent further errors from occurring in the future unless you always remember to append the domain on each @RequestMapping

For example if we only altered the code above and not the other mappings in the controllers the paths that they would accept from would be




In this scenario the correct solution would be to change the path that the controllers accept requests from. To do so we need to add the @RequestMapping annotation to each class in a similar way that it has already been used on the methods.


This is more likely to reduce conflicts of mappings as each class will have its own specific base mapping and then each method’s path will be built upon it.

Now the PersonRestController accepts requests from


for example


The UserRestController accepts from


for example


Not only does it prevent the conflicts but it is much clearer from looking at the request what controller it will eventually go to, which in the future could help with debugging.

After reading this post you should know how to set the path of a rest controller and understand the consequences if you don’t. As well as some reasons for setting the path via the controller to make the code tidier and less likely to run into issues in the future.

The code for this post can be found on my github.

  1. Great



  2. You could use the spring annotation @GetMapping on the method and remove get from the path because the rest verb ‘get’ is implied from the request type (GetMapping will make it be a GET request). conversely if you wre removing one you could use @DeleteMapping to annotation that controller mapping.



    1. Yes, your right you can use them instead. Luckily I started doing that in my future posts.




Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: