Bean Validation in Vaadin 7
Join the DZone community and get the full member experience.
Join For FreeOne of Vaadin 7 key features is its tight JSR 303, also known as Bean Validation, integration. This article will detail on how to achieve such a validation.
For starters, let's have a simple use-case: the user fills in a form. When there's an error, the user is informed visually about the error. Submitting the form is only possible when all errors have been corrected. This a common scenario and we'll implement it with Vaadin.
Prerequisites
There are a couple of prerequisites to address before going further:- First, we'll need a JSR 303 implementation. In this case, we'll use Hibernate Validator (which is also JSR-303 Reference Implementation)
- The next step is to define the underlying bean. In our case, we'll keep it simple (and stupid): a Person and its associated attributes. The first name and the last name must not be null while the email, when it exists, has to respect an email pattern.
import java.util.Date; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.Email; public class Person { private long id; private Gender gender; @Size(max = 250) @NotNull private String firstName; @Size(max = 250) @NotNull private String lastName; @Size(max = 250) @Email private String email; private Date birthdate; // Getters and setters }
Note that NotNull and Size constraints come from the JSR itself (javax.validation.constraints package) while the Email comes from Hibernate Validator (org.hibernate.validator.constraints package). Despite the coupling, considering the added value, I don't have any scruples using it.
Validating
Once the bean is annotated, it's only a matter of:
- Creating a new bean: this is pretty self-explanatory
- Vaadin 7 having deprecated the Form class, we need putting the bean into its replacement FieldGroup.
- Then, we need to get a reference on each displayable field (as opposed to Form where there was a default and we could customize it). The FieldGroup has methods to create each field and bind it to the underlying bean property.
- Each field is then set its validator (if needed)
- Finally, each field has to be set on our layout the way want
Finishing touches
There are a couple of finishing touches necessary to achieve a polished user interface.No preliminary validation
If all previous code snippets take place in the init() method, users will see validation errors on first and last names when the page is displayed, since all bean attributes are initially empty.
Thus, it's higly desirable to install validators only after the page has been displayed for the first time without errors. This could be done when the field loses focus. Yet, it has to be done even if the field never receives focus. Thus, it has to be done in two places:
- In each validated field blur listener
- Just before the FieldGroup commit
Note that since we don't keep a reference to the installed validator, we have to uninstall it before installing it otherwise it leads to twice (or more) the same validation.
For clarity's sake, here's the ValidatorUtils code:
The right widget for the right data type
This point has nothing to do with validation, but it brings a nice finishing touch to the user interface. Did you notice that when we built the gender field, we passed a Select parameter and presto, the return field was a select. Wouldn't it be better if the birthdate field would be displayed as a true DateField? We can try this:
Unfortunately, this doesn't work as Vaadin loudly complains with a com.vaadin.data.fieldgroup.FieldGroup$BindException: Unable to build a field of type com.vaadin.ui.DateField for editing java.util.Date. This means that in contrast to the old Form, FieldGroup doesn't handle date fields. As both use field factories (albeit of a different type), this is easily corrected. We just have to create a field group factory that return DateField when passed Date attributes and delegates to the default field group factory otherwise.
Remove initial ugly null values
Finally, since the Person bean is initialized with null values, null appears when the page first loads. For a end-user, this is not particularly desirable. We have to cast the field returned by the field group to a more friendly type and call the setNullRepresentation() method.
Conclusion
In this article, we used the power of Vaadin 7 to easily create a submit form, complete with validation coming from JSR 303 annotations. The full sources of this article can be found on Github.
Published at DZone with permission of Nicolas Fränkel, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments