java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'category' available as request attribute

likeachamp picture likeachamp · Feb 14, 2014 · Viewed 43k times · Source

I looked almost all answers related this problem on the web but could not figure out the problem in my code.

Here is my JSP page.

<form:form method="POST" commandName="category" modelAttribute="category" action="search_category">
    <form:input path="category_name" /> 
    <input type="submit" value="Submit">  
</form:form>

When I delete

<form:input path="category_name" /> 

It works fine. I can communicate with my controller. So the problem is related to this line.

@Controller
public class SearchCategory {

    @Autowired      
    private CategoryService categoryService;

    @RequestMapping(value = "/search_category",  method = RequestMethod.POST)
    public @ResponseBody String searchCategoryFromDatabase(@ModelAttribute("category") Category category, BindingResult result){        

        return "something";
    }
}

Here is my web.xml

<?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">

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

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

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

    <filter>  
        <filter-name>hibernateFilter</filter-name>  
        <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>hibernateFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>      

    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

</web-app>

This is my servlet-context.xml

<!--  Set the default page as index.jsp -->
<mvc:view-controller path="/" view-name="index"/>

<!-- Map resources --> 
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/web-resources/" /> 

<!-- Map simple view name such as "test" into /WEB-INF/views/test.jsp -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/" />
    <property name="suffix" value=".jsp" />
</bean>

And my applicationContext.xml

<!-- Enable @Controller annotation support -->
    <mvc:annotation-driven />

    <context:annotation-config/>    

    <!--  Set the default page as index.jsp -->
    <mvc:view-controller path="/" view-name="index"/>

     <!-- Map resources --> 
    <mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/web-resources/" /> 

    <!-- Map simple view name such as "test" into /WEB-INF/views/test.jsp -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <!-- Scan classpath for annotations (eg: @Service, @Repository etc) -->
    <context:component-scan base-package="com.XXXX"/>

    <!-- JDBC Data Source. It is assumed you have MySQL running on localhost port 3306 with 
         username root and blank password. Change below if it's not the case -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/XXXX"/>
        <property name="username" value="XXXX"/>
        <property name="password" value="XXXX"/>
        <property name="validationQuery" value="SELECT 1"/>
    </bean>

    <!-- Hibernate Session Factory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="packagesToScan">
            <array>
                <value>com.XXXX</value>
            </array>
        </property>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=org.hibernate.dialect.MySQLDialect
            </value>
        </property>     
    </bean>

    <!-- Hibernate Transaction Manager -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!-- Activates annotation based transaction management -->
    <tx:annotation-driven transaction-manager="transactionManager"/>  

I am probably doing something wrong in my XML files. I am new for this Spring - Hibernate staff so waiting for your help. Thanks..

This is the exception getting thrown

Stacktrace:] with root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'category' available as request attribute
    at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)
    at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
    at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
    at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:154)
    at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:141)
    at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:132)
    at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:116)
    at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:422)
    at org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
    at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
    at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
    at org.apache.jsp.index_jsp._jspx_meth_form_005finput_005f0(index_jsp.java:208)
    at org.apache.jsp.index_jsp._jspx_meth_form_005fform_005f0(index_jsp.java:168)
    at org.apache.jsp.index_jsp._jspService(index_jsp.java:100)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:149)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)

Answer

Sotirios Delimanolis picture Sotirios Delimanolis · Feb 17, 2014

If you're getting to index.jsp through something like http://localhost:8080/yourapp, I'll assume you have a <welcome-file> for it.

This means that the index.jsp generates the HTML without any pre-processing by Spring. You're trying to render this

<form:form method="POST" commandName="category" modelAttribute="category" action="search_category">
    <form:input path="category_name" /> 
    <input type="submit" value="Submit">  
</form:form>

where <form:form> is from Spring's tag library. First, note that you are using both commandName and modelAttribute. This is redundant. Use one or the other, not both. Second, when you specify either of these, the tag implementation looks for a HttpServletRequest attribute with the name specified. In your case, no such attribute was added to the HttpServletRequest attributes. This is because the Servlet container forwarded to your index.jsp directly.

Instead of doing that, create a new @Controller handler method which will added an attribute to the model and forward to the index.jsp view.

@RequestMapping(value = "/", method = RequestMethod.GET)
public String welcomePage(Model model) {
    model.addAttribute("category", new Category()); // the Category object is used as a template to generate the form
    return "index";
}

You can get rid of this

<!--  Set the default page as index.jsp -->
<mvc:view-controller path="/" view-name="index"/>

Also, move any mvc configuration from your applicationContext.xml file to your servlet-context.xml file. That's where it belongs. Here's why.