6

I am using Spring 4. My form contains the following variables:

@NotNull
@Email
private String email;
@NotNull
private String firstName;
@NotNull
private String lastName;
@Digits(fraction = 0, integer = 10)
private String phoneNo;
@NotNull
private String role;

My controller:

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public ModelAndView add(@ModelAttribute("user") @Valid UserBean user, BindingResult result) {
    String message;
    if (result.hasErrors() && user != null)
        return new ModelAndView("userAdd");
    else {
        userService.addUser(user);
        message = "Successfully added user";
    }
    return new ModelAndView("success", "message", message);
    }

    @RequestMapping(value = "/register")
    public ModelAndView register(@ModelAttribute("user") UserBean user, BindingResult result) {
    List<String> roles = new ArrayList<String>();
    roles.add("Receiver");
    roles.add("Resolver");
    roles.add("Logger");
    Map<String, List<String>> model = new HashMap<String, List<String>>();
    model.put("roles", roles);
    return new ModelAndView("userAdd", "model", model);
    }
}

My jsp:

<c:url var="userAdd" value="user/add.do" />
    <sf:form method="post" action="${userAdd}" modelAttribute="user">
        <table>
            <tr>
                <td>First Name</td>
                <td><sf:input path="firstName" /><br /> <sf:errors
                        path="firstName" cssClass="error" /></td>
            </tr>
            <tr>
                <td>Last Name</td>
                <td><sf:input path="lastName" /><br /> <sf:errors
                        path="lastName" cssClass="error" /></td>
            </tr>
            <tr>
                <td>Email</td>
                <td><sf:input path="email" /><br /> <sf:errors
                        path="email" cssClass="error" /></td>
            </tr>
            <tr>
                <td>Phone No.</td>
                <td><sf:input path="phoneNo" /><br /> <sf:errors
                        path="phoneNo" cssClass="error" /></td>
            </tr>
            <tr>
                <td>Role</td>
                <td><sf:select path="role" items="${model.roles}" /><br /> <sf:errors
                        path="role" cssClass="error" /></td>
            </tr>
            <tr>
                <td><input type="submit" value="Submit" /></td>
            </tr>
        </table>
    </sf:form>

When I leave the the inputs blank, the form does not validate and does not throw any error. The BindingResult does not have any errors in it.

My libraries are: Libraries

My dispatcher-serlvet.xml is:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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">
    <!-- Scans for annotated @Controllers in the classpath -->
    <context:component-scan base-package="com.mj.cchp.controller">
        <context:include-filter type="annotation"
            expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    <bean id="myBeansValidator"
        class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
    <mvc:annotation-driven validator="myBeansValidator" />
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
</beans>

My applicationContext is:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="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">
    <!-- Scans for annotated @Controllers in the classpath -->
    <context:component-scan base-package="com.mj.cchp">
        <context:exclude-filter type="annotation"
            expression="org.springframework.stereotype.Controller" />
    </context:component-scan>
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver" />
        <property name="url" value="jdbc:db2://172.16.2.181:60000/CCHP" />
        <property name="username" value="db2inst1" />
        <property name="password" value="db2inst1" />
    </bean> 
</beans>

My web.xml is:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>CCHP</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/application-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>
</web-app>
khateeb
  • 5,265
  • 15
  • 58
  • 114

10 Answers10

11

You need to add

<bean id="myBeansValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

and

<mvc:annotation-driven validator="myBeansValidator">

and

    <!-- Hibernate Validator -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>4.2.0.Final</version>
    </dependency>

Should work!

Mannekenpix
  • 744
  • 7
  • 15
  • On doing that I am getting the following error: `Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.validation.beanvalidation.LocalValidatorFactoryBean] for bean with name 'myBeansValidator' defined in ServletContext resource [/WEB-INF/dispatcher-servlet.xml]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: javax/validation/ValidatorFactory` `Caused by: java.lang.ClassNotFoundException: javax.validation.ValidatorFactory` – khateeb Feb 03 '14 at 04:14
  • It's not possible. javax.validation.ValidatorFactory is in the jar validation-api and is included with hibernate-validator. Which tool do you use to build your project? Maven? If so, clean install should work to import the new librairies. http://i.imgur.com/F2R8QDb.png – Mannekenpix Feb 03 '14 at 08:52
  • I got the problem. I was not using any tool. I was manually adding dependencies. So the `validation-api` jar was not included. But why wasn't the class taken from `javaee-api` jar which has it included. – khateeb Feb 03 '14 at 10:37
  • This fixed my problem. But I'm not sure why I have to do this as the schema documentation says:"The bean name of the Validator that is to be used to validate Controller model objects. This attribute is not required, and only needs to be specified explicitly if a custom Validator needs to be configured. If not specified, JSR-303 validation will be installed if a JSR-303 provider is present on the classpath." – zhy2002 Sep 26 '14 at 06:07
  • "will be installed if a JSR-303 provider is present on the classpath". Maybe you didn't have a JSR-303 provider in your classpath – Mannekenpix Sep 26 '14 at 09:35
5

I had a similar problem and in my case it was sufficient to just add dependency for hibernate validator: org.hibernate:hibernate-validator:5.2.4.Final.

The validation is done by LocalValidatorFactoryBean bean and documentation about it comes handy (here).

Yet at the same time it is worth mentioning that you do not have to instantiate LocalValidatorFactoryBean explicitly as long as you use @EnableWebMvc annotation : http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-config-validation

By default use of @EnableWebMvc or automatically registers Bean Validation support in Spring MVC through the LocalValidatorFactoryBean when a Bean Validation provider such as Hibernate Validator is detected on the classpath.

Hope this helps.

Witold Kaczurba
  • 9,845
  • 3
  • 58
  • 67
2

I faced the same problem. I resolved by adding below statement in dispatcher-serlvet.xml file.

<mvc:annotation-driven />
Hari Krishna
  • 3,658
  • 1
  • 36
  • 57
1

I'm not sure whether you have found ways to fix this. I am facing the same issue as well. and I managed to solve it. The problem with my setting is totally manual and I'm doing big mistake by placing the whole hibernate-validator-5.1.3.Final-dist.zip inside lib folder.

So what I did is I get this 6 files inside "hibernate-validator-5.1.3.Final-dist.zip" in dist folder and place this with web app lib.

  • classmate-1.0.0.jar
  • hibernate-validator-5.1.3.Final.jar
  • javax.el-2.2.4.jar
  • javax.el-api-2.2.4.jar
  • jboss-logging-3.1.3.GA.jar
  • validation-api-1.1.0.Final.jar

This fixed my issue.

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
Fathi
  • 11
  • 1
  • 2
1

i also faced the same issue where my entire code was properly written.

The problem was the different version of jar files that i was using .

I had hibernate-validator-cdi- 5.0.7.Final and hibernate-validator-6.0.2.Final.

Just make sure your jar files are of the same version.

When i kept all the jars of same version, my issue got resolved. I hope this will help you .

1

You need to add @Valid in register method

@RequestMapping(value = "/register") public ModelAndView register(@Valid @ModelAttribute("user") UserBean user, BindingResult result) {

hema
  • 11
  • 1
  • 3
1

If you are using hibernate-validator, use version-6.2.4 Version 7 might not work.

Manas
  • 11
  • 1
0

In my case hibernate-validator jars are not available in run time. I've copied them to .../WEB-INF/lib/ then it worked correctly.

Siva R
  • 427
  • 2
  • 8
  • 23
0

I added the usual stuff you have done (libraries in pom, @Valid on RequestBody etc)

<dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.1.3.Final</version>
        </dependency>
        <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.1-b11</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>

What the Spring docs (and many blogs) leave it as subtle is that Spring looks for an exit point to throw the error but if that exit doesn't exist, it will reply with 404. After reading a lot especially this blog, adding this class got Spring to recognize @Valid and find an exit point to throw the error

    @RestControllerAdvice
    @Order(1) 
    public class RestControllerExceptionHandler {

    @RequestMapping(value = { "error/404" }, method = RequestMethod.GET)
    @ExceptionHandler(Exception.class)
    public String handleUnexpectedException(Exception e) {
        return "views/base/rest-error";         
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String handlemethodArgumentNotValid(MethodArgumentNotValidException exception) { //
        // TODO you can choose to return your custom object here, which will then get transformed to json/xml etc.
        return "Sorry, that was not quite right: " + exception.getMessage();
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public String handleConstraintViolation(ConstraintViolationException exception) { //
        // TODO you can choose to return your custom object here, which will then get transformed to json/xml etc.
        return "Sorry, that was not quite right: " + exception.getMessage();
    }

    
}
veritas
  • 378
  • 1
  • 6
  • 16
0

i spent nearly 2 days fixing the same problem and ultimately found one solution, if you still have this problem, i would like to suggest you one answer, in my case, i tried using hibernate-validator-5.1.3.Final-dist.zip,5.2.4.Final-dist.zip, 7.0.0.Final-dist.zip but none of these worked for me but when i used *hibernate-validator-6.2.0.Final-dist*, it supports jarkarta validation but it works perfectly even though people say because of Jakarta Bean Validation it does not work in hibernate-validator's version post 5. it worked miraculously and believe me, it might work for you as well.

web_walkerX
  • 840
  • 10
  • 19