Follow this quick tutorial for a simple example on how to use VRaptor's programmatic validation.
It finishes explaining why we have chosen not to implement an annotation based validation procedure (yet).
Please also check the hibernate validator plugin which offers even more powerful.
We will play around with a model class called Person. Create the following class:
package org.vraptor.examples.validation; public class Person { private String name; private String address; private Long preferredNumber; // getters and setters @Override public String toString() { return String.format("[Person %s,%s,%d]", name, address, preferredNumber); } }
Now let's go a step further and configure the add person business logic url.
Let's name this component person and the business logic represented by the method add by add.
It means that when the url person.add.logic is called, our component will be instantiated, the person field filled with the request's parameters and after that the method add is called.
package org.vraptor.examples.validation; import org.vraptor.annotations.Component; import org.vraptor.annotations.Logic; import org.vraptor.annotations.Parameter; @Component public class PersonLogic { public void add(Person p) { System.out.printf("Adding %s to the database!%n", p); } }
Yes, it is. Now let's validate our person:
package org.vraptor.examples.validation; import org.vraptor.annotations.Component; import org.vraptor.validator.*; import org.vraptor.i18n.*; @Component public class PersonLogic { public void add(Person p) { System.out.printf("Adding %s to the database!%n", p); } /** * Validates the add method */ public void validateAdd(ValidationErrors errors, Person p) { // checks if null, empty or trimmed empty if(StringValidation.isBlank(p.getName())) { errors.add(new Message("name","empty_name")); } // checks if null or empty if(StringValidation.isEmpty(p.getAddress())) { errors.add(new Message("address","empty_address")); } // checks if null (empty or invalid number) when using java.lang.Long if(p.getPreferredNumber()==null) { errors.add(new Message("number","empty_number")); } } }
Your logic method is called only if it's validation method is called and doesn't register any error!
This means: if no error happens, errors.size()==0, therefore vraptor's goes to person/add.ok.jsp:
<html> You have created a new person named ${person.name}, who lives at ${person.address} and his/her preferred number is ${person.preferredNumber}. </html>
If errors.size()!=0 this means that some error has occurred... vraptor's method return is invalid which redirects to component/logic.invalid.jsp, in our example: person/add.invalid.jsp:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> There was some validation problems: <div id="errors"> <ul> <c:forEach var="error" items="${errors.iterator}"> <li>${error.key}</li> </c:forEach> </ul> </div> </html>
Let's create a simple index.jsp page that contains the desired form:
<html> <form action="person.add.logic" method="get"> Name: <input name="person.name"/><br/> Address: <input name="person.address"/><br/> Preferred number: <input name="person.preferredNumber"/><br/> <input type="submit"/> </form> </html>
You can use the path property from an error to discover which was the path generated the validation error.
We are ready. just test it!
So how did we get that set up?
Let's configure vraptor to redirect back to the form if some validation problem occurrs.
First create the views.properties file in your classpath (java source or resources directory).
We shall map componentName.logic.invalid to any file we desire... so let's redirect it to our form:
person.add.invalid = /index.jsp
And we change the index.jsp file to display the default values:
<html> <form action="person.add.logic" method="get"> Name: <input name="person.name" value="${person.name}"/><br/> Address: <input name="person.address" value="${person.address}"/><br/> Preferred number: <input name="person.preferredNumber" value="${person.preferredNumber}"/><br/> <input type="submit"/> </form> </html>
Error messages should use internationalization, so use the fmt tag to get something like:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <div id="errors"> <ul> <c:forEach var="error" items="${errors.iterator}"> <li><fmt:message key="${error.key}"/></li> </c:forEach> </ul> </div>
Don't forget to setup the resource bundle! (read the fmt jstl documentation or download vraptor's blank application).
VRaptor already includes some default validation messages. You should add these messages to your properties file.
no_converter_found = No converter was found. invalid_converter = Unable to instantiate converter. invalid_date = Invalid date. invalid_time = Invalid time. invalid_value = Invalid value. invalid_number = Invalid number. invalid_character = Invalid character.
The base message interface is called ValidationMessage while the i18n class is Message (due to compatibility issues).
If you want to mix i18n messages with fixed messages you can instantiate the FixedMessage class.
Both classes implement the method isAlreadyLocalized: Message returns false, while FixedMessage returns true, therefore you can easily mix them in your view:
<c:if test="${error.alreadyLocalized}"> ${error.key} </c:if> <c:if test="${not error.alreadyLocalized}"> <fmt:message key="${error.key}"/> </c:if>
Hibernate Validator is already supported by VRaptor.