Sunday, November 17, 2024
Google search engine
HomeLanguagesJavaWhat is Ambiguous Mapping in Spring?

What is Ambiguous Mapping in Spring?

Spring is a loosely coupled framework of java meaning all the objects are not dependent on each other and can be easily managed & modified. Basic architecture in every spring project involves the use of controllers or REST Controllers, any build tool like maven, gradle, or groove, an RDBMS, Service layers, etc. Someone just starting into the spring framework is most likely to encounter Ambiguous Mapping. When mapping a request to a particular controller there are chances of arising ambiguity, if some things are not taken care of.

1. Using ‘name = ‘ instead of ‘value = ‘

This type of error is very common as the terminology sounds like it does the same task. However, when you use this :

Java




@RequestMapping(name = "/getName", method = GET)


The name property of @RequestMapping Annotation only provides a name to your mapping but it doesn’t actually define the mapping hence resulting in Ambiguous Mapping. The solution to this would be to just replace the ‘name’ attribute with the ‘value’ attribute like this: 

Java




// Changed 'name' to 'value'  
@RequestMapping(value = "/getName", method = GET)


Let’s look at another common use case when this ambiguity would arise:

2. No parent mapping on the Rest Controller

Let’s say you have 2 controllers in your project namely: HomeController and TaskController. And as we know, under each controller we have defined various mappings for each request received from the client. Now, it’s possible that you might have forgotten to add a mapping on top of your controller or there’s a typo in the mapping that’s on top of your controller. 

Because, when we have more than 1 controller then it is better to add a Parent Mapping to a controller and the reason for that would be if you’ve defined so many @RequestMappings inside a controller and some or one of them are the same in both controllers then it would create an ambiguity in spring framework because it won’t be able to decide to which controller the call should be delegated to! Hence again resulting in ambiguity.

Let’s look at it code-wise to understand better, let’s consider the previous example where we said we have 2 controllers: HomeController & TaskController

HomeController.java:

Java




package com.neveropen.ambiguousmapping.controller;
  
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
  
@RestController
public class HomeController {
    
    @RequestMapping(value = "/writeArticles")
    public String writeArticles() {
        return "5 Articles written on GeeksForGeeks !";
    }
      
    @RequestMapping(value = "/doLaundry")
    public String doLaundry() {
        return "Laundry done at 5 PM !";
    }
}


TaskController.java:

Java




package com.neveropen.ambiguousmapping.controller;
  
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
  
@RestController
public class TaskController {
    
    @RequestMapping(value = "/writeArticles")
    public String writetwoMoreArticles() {
        return "2 More Articles written !";
    }
      
    @RequestMapping(value = "/doLaundry")
    public String checkLaundry() {
        return "Laundry already done @5 PM !";
    }
}


Code Explanation:

We have created 2 classes and marked them with @Controller annotation so spring will treat them as Controllers and @Controller inherits from @Component so this class will be scanned during component scanning. And inside both controllers, we have defined different methods having the same request mapping which would cause ambiguity. (Method names don’t matter, here call is decided with the help of @RequestMappings). Now, when we run our Spring Boot Application, it would throw the following Exceptions : 

  1. BeanCreationException
  2. Caused by: IllegalStateException

See the highlighted text in the following image it says – “Ambiguous Mapping. Cannot map ‘taskController’ method” 

 

Solution to Ambiguous Mapping

Let’s do this step by step: 

Step 1. Go to spring Initilizr and create a project using the dependency – Spring WEB

Step 2. Create a new package: Make sure the package name is the same as the previous package, and append .controller at the end of it. Because spring recursively scans all the packages.

Step 3. Then create 2 new classes inside this package namely: HomeController and TaskController and paste the below code accordingly

In the below code, we have overcome the ambiguous mapping problem just by providing another RequestMapping on top of our controller class which would help spring differentiate between the 2 controllers and map the request to the appropriate REST Controller. You just have to add another @RequestMapping on top of your RestController. Let’s look at the code:

HomeController.java:

Java




package com.neveropen.ambiguousmapping.controller;
  
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
  
@RestController
@RequestMapping(value = "/home")
public class HomeController {
    
    @RequestMapping(value = "/writeArticles")
    public String writeArticles() {
        return "5 Articles written on GeeksForGeeks !";
    }
      
    @RequestMapping(value = "/doLaundry")
    public String doLaundry() {
        return "Laundry done at 5 PM !";
    }
}


TaskController.java:

Java




package com.neveropen.ambiguousmapping.controller;
  
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
  
@RestController
@RequestMapping(value = "/task")
public class TaskController {
    
    @RequestMapping(value = "/writeArticles")
    public String writetwoMoreArticles() {
        return "2 More Articles written !";
    }
      
    @RequestMapping(value = "/doLaundry")
    public String checkLaundry() {
        return "Laundry already done @5 PM !";
    }
}


As you can see, we have added another @RequestMapping on top of both of our rest controllers which will now be appropriately called and there won’t be any ambiguity. So now let’s go to the browser and test this out. Go to: localhost:8080/home/writeArticles and localhost:8080/task/writeArticles (or to your configured port instead of 8080)

You’ll get the following output:

Url : localhost:8090/home/writeArticles (I've configured my port to 8090 hence I am using 8090)

Url : localhost:8090/home/writeArticles (I’ve configured my port to 8090 hence I am using 8090)

Url : localhost:8090/task/writeArticles (I've configured my port to 8090 hence I am using 8090)

Url : localhost:8090/task/writeArticles (I’ve configured my port to 8090 hence I am using 8090)

RELATED ARTICLES

Most Popular

Recent Comments