Model validation is driven by constraints specified against a model object. Web Flow supports enforcing such constraints programatically as well as declaratively with JSR-303 Bean Validation annotations.
Web Flow provides built-in support for the JSR-303 Bean Validation API
building on equivalent support available in Spring MVC.
To enable JSR-303 validation configure the flow-builder-services with
Spring MVC's LocalValidatorFactoryBean:
<webflow:flow-registry flow-builder-services="flowBuilderServices" /> <webflow:flow-builder-services id="flowBuilderServices" validator="validator" /> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
With the above in place, the configured validator will be applied to all model attributes after data binding.
Note that JSR-303 bean validation and validation by convention (explained in the next section) are not mutually exclusive. In other words Web Flow will apply all available validation mechanisms.
There are two ways to perform model validation programatically.
The first is to implement validation logic in your model object.
The second is to implement an external Validator.
Both ways provide you with a ValidationContext to record error messages and access information about the current user.
Defining validation logic in your model object is the simplest way to validate its state.
Once such logic is structured according to Web Flow conventions, Web Flow will automatically invoke that logic during the view-state postback lifecycle.
Web Flow conventions have you structure model validation logic by view-state, allowing you to easily validate the subset of model properties that are editable on that view.
To do this, simply create a public method with the name validate${state}, where ${state} is the id of your view-state where you want validation to run.
For example:
public class Booking {
private Date checkinDate;
private Date checkoutDate;
...
public void validateEnterBookingDetails(ValidationContext context) {
MessageContext messages = context.getMessageContext();
if (checkinDate.before(today())) {
messages.addMessage(new MessageBuilder().error().source("checkinDate").
defaultText("Check in date must be a future date").build());
} else if (!checkinDate.before(checkoutDate)) {
messages.addMessage(new MessageBuilder().error().source("checkoutDate").
defaultText("Check out date must be later than check in date").build());
}
}
}
In the example above, when a transition is triggered in a enterBookingDetails view-state that is editing a Booking model,
Web Flow will invoke the validateEnterBookingDetails(ValidationContext) method automatically unless validation has been suppressed for that transition.
An example of such a view-state is shown below:
<view-state id="enterBookingDetails" model="booking">
<transition on="proceed" to="reviewBooking">
</view-state>
Any number of validation methods are defined. Generally, a flow edits a model over a series of views. In that case, a validate method would be defined for each view-state where validation needs to run.
The second way is to define a separate object, called a Validator, which validates your model object.
To do this, first create a class whose name has the pattern ${model}Validator, where ${model} is the capitialized form of the model expression, such as booking.
Then define a public method with the name validate${state}, where ${state} is the id of your view-state, such as enterBookingDetails.
The class should then be deployed as a Spring bean. Any number of validation methods can be defined.
For example:
@Component
public class BookingValidator {
public void validateEnterBookingDetails(Booking booking, ValidationContext context) {
MessageContext messages = context.getMessageContext();
if (booking.getCheckinDate().before(today())) {
messages.addMessage(new MessageBuilder().error().source("checkinDate").
defaultText("Check in date must be a future date").build());
} else if (!booking.getCheckinDate().before(booking.getCheckoutDate())) {
messages.addMessage(new MessageBuilder().error().source("checkoutDate").
defaultText("Check out date must be later than check in date").build());
}
}
}
In the example above, when a transition is triggered in a enterBookingDetails view-state that is editing a Booking model,
Web Flow will invoke the validateEnterBookingDetails(Booking, ValidationContext) method automatically unless validation has been suppressed for that transition.
A Validator can also accept a Spring MVC Errors object, which is required for invoking existing Spring Validators.
Validators must be registered as Spring beans employing the naming convention ${model}Validator to be detected and invoked automatically.
In the example above, Spring 2.5 classpath-scanning would detect the @Component and automatically register it as a bean with the name bookingValidator.
Then, anytime the booking model needs to be validated, this bookingValidator instance would be invoked for you.
A Validator class can also define a method called validate not associated (by convention) with any specific view-state.
@Component
public class BookingValidator {
public void validate(Booking booking, ValidationContext context) {
//...
}
}
In the above code sample the method validate will be called every time a Model of type Booking is validated (unless validation has been suppressed for that transition).
If needed the default method can also be called in addition to an existing state-specific method. Consider the following example:
@Component
public class BookingValidator {
public void validate(Booking booking, ValidationContext context) {
//...
}
public void validateEnterBookingDetails(Booking booking, ValidationContext context) {
//...
}
}
In above code sample the method validateEnterBookingDetails will be called first.
The default validate method will be called next.
A ValidationContext allows you to obtain a MessageContext to record messages during validation.
It also exposes information about the current user, such as the signaled userEvent and the current user's Principal identity.
This information can be used to customize validation logic based on what button or link was activated in the UI, or who is authenticated.
See the API Javadocs for ValidationContext for more information.