V|Raptor

documentation

configuration, migration and utilization.

Validation

VRaptor3 supports two different validation styles: classic and fluent. The starting point to both styles is the Validator interface. In order to access the Validator, your resource must receive it in the constructor:
import br.com.caelum.vraptor.Validator;
...

@Resource
class EmployeeController {
   
private Validator validator;
   
   
public EmployeeController(Validator validator) {
       
this.validator = validator;
   
}
}

Classic style

The classic style is very similar to VRaptor2's validation. Inside your business logic, all you have to do is check the data you want, and if you find any validation errors, add them to the errors list. For example, to validate that employee name is 'John Doe':
public void add(Employee employee) {
   
if (!employee.getName().equals("John Doe")) {
       
validator.add(new ValidationMessage("error","invalidName"));
   
}
   
validator.onErrorUse(page()).of(EmployeeController.class).form();
   
    dao.add
(employee);
}
When you call validator.onErrorUse, if there are any validation errors, VRaptor will stop execution and redirect to the page you specified. This redirect has the same behavior as the result.use(..) redirects.

Fluent style

The goal of fluent style is to write the validation code in such way that it feels natural. For example, if we want the employee name to be required:
public add(Employee employee) {
   
validator.checking(new Validations(){{
       
that(!employee.getName().isEmpty(), "error","nameIsRequired");
   
}});
    validator.onErrorUse
(page()).of(EmployeeController.class).form();
   
    dao.add
(employee);
}
You can read the code above like this: "Validator, check my validations. First one is that employee name cannot be empty". Much closer to natural language. So, if employee name is empty, the flow will be redirected to the "form" logic, which shows the user a form to insert employee data again. Also, the error message is sent back to the form. There are validations that may occur only if other validation succeeded, for instance I will check user age only if the user is not null. The that method will return a boolean that represents the success of the validation:
validator.checking(new Validations(){{
   
if (that(user != null, "user", "null.user")) {
       
that(user.getAge() >= 18, "user.age", "user.is.underage");
   
}
}})
;
So the second validation will execute only if the first didn't fail.

Validation with message parameters

You can add parameters to you message keys:
greater_than = {0} should be greater than {1}
And use it on your validations code:
validator.checking(new Validations(){{
   
that(user.getAge() >= 18, "user.age", "greater_than", "Age", 18);
   
// Age should be greater than 18
}});
You can even i18n your parameters, with i18n method:
user.age = User age
validator.checking(new Validations(){{
   
that(user.getAge() >= 18, "user.age", "greater_than", i18n("user.age"), 18);
   
// User age should be greater than 18
}});

Validation using Hamcrest Matchers

You can use Hamcrest matchers for making validation even more fluent and readable, with the advantage of matcher composition and the creation of new matchers that Hamcrest allows:
public admin(Employee employee) {
   
validator.checking(new Validations(){{
       
that(employee.getRoles(), hasItem("ADMIN"), "admin","employee.is.not.admin");
   
}});
    validator.onErrorUse
(page()).of(LoginController.class).login();   
    dao.add
(employee);
}

Bean Validation (JSR303) and Hibernate Validator

VRaptor 3 also supports Bean Validation and Hibernate Validator. To use these features you only need to put any implementation of Bean Validation or Hibernate Validator jars in your classpath. In the example above, to validate the employee object using HibernateValidator, just add one line to your code:
public add(Employee employee) {
   
//Validation with Bean Validation or Hibernate Validator
   
validator.validate(funcionario);
   
    validator.checking
(new Validations(){{
       
that(!employee.getName().isEmpty(), "error","nameIsRequired");
   
}});
    validator.onErrorUse
(page()).of(EmployeeController.class).form();
       
    dao.add
(employee);
}

Where to redirect in case of errors

Another issue that one must consider when validating data is where to redirect when an error occurs. How do one redirect the user to another resource using VRaptor3 in case of validation errors? Easy, just tell your validator to do just that: when you find any validation error, send the user to the specified resource. See the example:
public add(Employee employee) {
   
   
//Fluent validation
   
validator.checking(new Validations(){{
       
that(!employee.getName().isEmpty(), "error","nameIsRequired");
   
}});
   
   
//Classic validation
   
if (!employee.getName().equals("John Doe")) {
       
validator.add(new ValidationMessage("error","invalidName"));
   
}
   
validator.onErrorUse(page()).of(EmployeeController.class).form();
   
    dao.add(employee);
}
If your logic may add any validation error you must specify where to go in case of error. Validator.onErrorUse works just like result.use: you can use any view from Results class.

Shortcuts on Validator

Some redirections are pretty common, so there are shortcuts on Result interface for them. The available shortcuts are:
  • validator.onErrorForwardTo(ClientController.class).list() ==> validator.onErrorUse(logic()).forwardTo(ClientController.class).list();
  • validator.onErrorRedirectTo(ClientController.class).list() ==> validator.onErrorUse(logic()).redirectTo(ClientController.class).list();
  • validator.onErrorUsePageOf(ClientController.class).list() ==> validator.onErrorUse(page()).of(ClientController.class).list();
  • validator.onErrorSendBadRequest() ==> validator.onErrorUse(status()).badRequest(errors);
Furthermore, if one are redirecting to a method on the same controller, one can use:
  • validator.onErrorForwardTo(this).list() ==> validator.onErrorUse(logic()).forwardTo(this.getClass()).list();
  • validator.onErrorRedirectTo(this).list() ==> validator.onErrorUse(logic()).redirectTo(this.getClass()).list();
  • validator.onErrorUsePageOf(this).list() ==> validator.onErrorUse(page()).of(this.getClass()).list();

Showing validation errors on JSP

When there are validation errors, VRaptor will set a request attribute named errors with the error list, so you can show them on your JSP with:
<c:forEach var="error" items="${errors}">
    ${error.category} - ${error.message}<br />
</c:forEach>
vraptor logo

Apache 2.0 License - VRaptor ©2009 Caelum - Ensino e Inovação

Profiled with JProfiler

loki|design