44

I am trying to build an app which can list some values from the database and modify, add, delete if necessary using Spring 4 and i receive the following error(only if the "@Controller" annotation is present in both of my controller files, if i delete the annotation from one of the files it works but i get a message in console "no mapping found ... in dispatcherservlet with name ...):

    INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/edit/{id}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.bookReview.app.BookController.editBook(int,org.springframework.ui.Model)
WARN : org.springframework.web.context.support.XmlWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'reviewController' bean method 
public java.lang.String com.bookReview.app.ReviewController.editReview(int,org.springframework.ui.Model)
to {[/edit/{id}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'bookController' bean method
public java.lang.String com.bookReview.app.BookController.editBook(int,org.springframework.ui.Model) mapped.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4728)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5166)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'reviewController' bean method 
public java.lang.String com.bookReview.app.ReviewController.editReview(int,org.springframework.ui.Model)
to {[/edit/{id}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'bookController' bean method
public java.lang.String com.bookReview.app.BookController.editBook(int,org.springframework.ui.Model) mapped.
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:212)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:184)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:144)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:123)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:126)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
    ... 21 more

This is my pom.xml file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.bookReview.app</groupId>
  <artifactId>BookReviewApp</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>BookReviewApp</name>
  <description>review app</description>

   <!--   <properties>

        Generic properties
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        Spring
        <spring-framework.version>4.0.3.RELEASE</spring-framework.version>

        Hibernate / JPA
        <hibernate.version>4.3.5.Final</hibernate.version>
        <hibernate.version>3.6.9.Final</hibernate.version>

        Logging
        <logback.version>1.0.13</logback.version>
        <slf4j.version>1.7.5</slf4j.version>

    </properties> -->

  <dependencies>
  <!-- Spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.6.RELEASE</version>
        <!-- Exclude Commons Logging in favor of SLF4j -->
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <!-- Hibernate -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.3.9.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.9.Final</version>
    </dependency>
    <!-- Apache Commons DBCP -->
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <!-- Spring ORM -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <!-- AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.5</version>
    </dependency>
    <!-- Logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.12</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.12</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.12</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.15</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.mail</groupId>
                    <artifactId>mail</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>javax.jms</groupId>
                    <artifactId>jms</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jdmk</groupId>
                    <artifactId>jmxtools</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jmx</groupId>
                    <artifactId>jmxri</artifactId>
                </exclusion>
            </exclusions>
            <scope>runtime</scope>
        </dependency>
        <!-- @Inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2.1-b03</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- Test -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
  </dependencies>
</project>

This is my web.xml file

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/app/root-context.xml</param-value>
    </context-param>

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Processes application requests -->
    <servlet>
        <servlet-name>servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/app/servlet/sevlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>servlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

This is my sevlet-context.xml file

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing 
        infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <beans:bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <beans:property name="url"
            value="jdbc:mysql://localhost:3306/test" />
        <beans:property name="username" value="serban" />
        <beans:property name="password" value="serban" />
    </beans:bean>

    <!-- Hibernate 4 SessionFactory Bean definition -->
    <beans:bean id="hibernate4AnnotatedSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="annotatedClasses">
            <beans:list>
                <beans:value>com.bookReview.app.model.book</beans:value>
                <beans:value>com.bookReview.app.model.review</beans:value>
            </beans:list>
        </beans:property>
        <beans:property name="hibernateProperties">
            <beans:props>
                <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
                </beans:prop>
                <beans:prop key="hibernate.show_sql">true</beans:prop>
            </beans:props>
        </beans:property>
    </beans:bean>

    <beans:bean id="bookDAO" class="com.bookReview.app.dao.bookDAOImpl">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </beans:bean>
    <beans:bean id="bookService" class="com.bookReview.app.service.BookServiceImpl">
        <beans:property name="bookDAO" ref="bookDAO"></beans:property>
    </beans:bean>

    <beans:bean id="reviewDAO" class="com.bookReview.app.dao.reviewDAOImpl">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </beans:bean>
    <beans:bean id="reviewService" class="com.bookReview.app.service.ReviewServiceImpl">
        <beans:property name="reviewDAO" ref="reviewDAO"></beans:property>
    </beans:bean>

    <!-- <default-servlet-handler/> -->

    <context:component-scan base-package="com.bookReview.app" />

    <tx:annotation-driven transaction-manager="transactionManager"/>

        <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </beans:bean>

    </beans:beans>

This is my BookController.java file

package com.bookReview.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.bookReview.app.model.book;
import com.bookReview.app.service.BookService;


@Controller
public class BookController {

    private BookService  bookService;

    @Autowired(required=true)
    @Qualifier(value="bookService")
    public void setBookService(BookService bs){
        this.bookService = bs;
    }

    @RequestMapping(value = "/books", method = RequestMethod.GET)
    public String listBooks(Model model) {
        model.addAttribute("book", new book());
        model.addAttribute("listBooks", this.bookService.listBooks());
        return "book";
    }

    //For add and update book both
        @RequestMapping(value= "/book/add", method = RequestMethod.POST)
        public String addBook(@ModelAttribute("book") book b){

            if(b.getBookid() == 0){
                //new book, add it
                this.bookService.addBook(b);
            }else{
                //existing book, call update
                this.bookService.updateBook(b);
            }

            return "redirect:/books";

        }

        @RequestMapping("/remove/{id}")
        public String removeBook(@PathVariable("id") int id){

            this.bookService.removeBook(id);
            return "redirect:/books";
        }

         @RequestMapping("/edit/{id}")
            public String editBook(@PathVariable("id") int id, Model model){
                model.addAttribute("book", this.bookService.getBookById(id));
                model.addAttribute("listBooks", this.bookService.listBooks());
                return "book";
            }


}

And this is my ReviewController.java file

package com.bookReview.app;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.bookReview.app.model.review;
import com.bookReview.app.service.ReviewService;


@Controller
public class ReviewController {

    private ReviewService  reviewService;

    @Autowired(required=true)
    @Qualifier(value="reviewService")
    public void setReviewService(ReviewService rs){
        this.reviewService = rs;
    }

    @RequestMapping(value = "/reviews", method = RequestMethod.GET)
    public String listReviews(Model model) {
        model.addAttribute("book", new review());
        model.addAttribute("listReviews", this.reviewService.listReviews());
        return "review";
    }

    //For add and update review both
    @RequestMapping(value= "/review/add", method = RequestMethod.POST)
    public String addReview(@ModelAttribute("review") review r){

        if(r.getId() == 0){
            //new review, add it
            this.reviewService.addReview(r);
        }else{
            //existing review, call update
            this.reviewService.updateReview(r);
        }

        return "redirect:/reviews";

    }

    @RequestMapping("/remove/{id}")
    public String removeReview(@PathVariable("id") int id){

        this.reviewService.removeReview(id);
        return "redirect:/reviews";
    }

     @RequestMapping("/edit/{id}")
        public String editReview(@PathVariable("id") int id, Model model){
            model.addAttribute("review", this.reviewService.getReviewById(id));
            model.addAttribute("listReviews", this.reviewService.listReviews());
            return "review";
        }


}

Thank you

Aniket Kulkarni
  • 12,825
  • 9
  • 67
  • 90
Serban Gorcea
  • 549
  • 1
  • 4
  • 11
  • 2
    Wow. This is a lot of code. Are you sure this is a [minimal complete verifiable example](http://stackoverflow.com/help/mcve), emphasis on the minimal? Creating a minimal example helps others more quickly identify your error and may also help you find the problem on your own. – Cecilia Apr 29 '15 at 16:40
  • 3
    Sorry, i was trying to give as much information as possible in order for the problem to be traced more easily. If you pay attention the pom, web and servlet context xml files are necessary because there may be the error, other than that you can find the error log which is also important and two class files which it was ok i put them in full format because the problem was at the bottom of those two files. thank anyway – Serban Gorcea Apr 29 '15 at 17:14
  • When I got this error, it was because I was upgrading Spring Boot to a newer version. I had to remove the pre-existing "@Bean" for the controller because the "@RestController" annotation made spring create it already! – Will Newton Aug 29 '18 at 21:20

5 Answers5

56

You should write

@Controller("/review")
public class ReviewController {

and

@Controller("/book")
public class BookController {

because in your code you have the two methods without an explicit/unique path for mapping(eg. if we have a call /edit/1 , this is impossible clearly to determine a controller's method from your editBook BookController or ReviewController editReview)

aliteralmind
  • 19,847
  • 17
  • 77
  • 108
Alexey Semenyuk
  • 3,263
  • 2
  • 32
  • 36
  • Thank you very much that was the problem, in the first place i modified the name of the "edit" and "remove" of ReviewController into "edit review" and "remove review" and i couldn't change @Controller into @Controller(/book) so i used @Controller(value="book"), i hope it's right. maybe it's a different spring version. Now i only have the console message: No mapping found for HTTP request with URI [/BookReviewApp/] in DispatcherServlet with name 'servlet' i do not know if it is related or not to this problem – Serban Gorcea Apr 29 '15 at 17:19
46

If the issue is about ambigious method, probably the @RequestMapping should be the issue. Change from @RequestMapping(name =...) to @RequestMapping(value =...)

@RequestMapping(name = "xxx.htm", method = RequestMethod.GET)

to

@RequestMapping(value = "xxx.htm", method = RequestMethod.GET)
hzitoun
  • 5,492
  • 1
  • 36
  • 43
gilberto Nd
  • 611
  • 6
  • 4
  • This answer was my solution to the problem described above when using the spring boot framework. Thanks! – Fratt Jan 12 '18 at 23:05
12

For me adding "params" attribute in @RequestMapping worked as shown

  @ResponseBody
  @RequestMapping(method = RequestMethod.GET, params = {"id"})
  public User getUserById(final @RequestParam(name="id", required = true) String Id)
    throws InvalidArgumentException {

    return userService.getUserById(UUID.fromString(Id));
  }

  /**
   * REST service endpoint.
   * @param name Unique name for the user in the system.
   * @return Object of type {@link User} if exists otherwise null.
   */
  @ResponseBody
  @RequestMapping(method = RequestMethod.GET, params = {"name"})
  public User getUserByName(final @RequestParam(name="name", required = true) String name)
    throws InvalidArgumentException {

    return userService.getUserByName(name);
  }

However adding both the parameters at a time in query string will give 500 error with message :

Ambiguous handler methods mapped for HTTP path

In that case you can have another controller method taking both params and but only uses one of them which I feel is not necessary.

Shrikant Prabhu
  • 709
  • 8
  • 13
0

In my case I had two methods in two different controllers in a Spring boot application, both with the same @DeleteMapping("/detailbonadelete/{id}") // delete, I changed one of them to @DeleteMapping("/bonadelete/{id}") // delete and it works.

The same thing if you have:

@PutMapping("/detailbonaupdate/{id}") // update

@PostMapping("/detailbonainsert") // insert

@GetMapping("/detailbonaidbon/{idBona}") // selectByBonaId

Make sure it is unique for every controller.

SourceCode
  • 45
  • 2
  • 7
0

In my case I had two methods in two different controllers in a Spring Boot application , both with same @RequestMappinG("/") and second Controller I wrote @RequestMapping("/") . They looked like(name). This was my problem . I changed : @RequestMapping("/") to : @RequestMapping("/modelName") second controller we can write : @RequestMapping("/")