Here are a couple of examples of annotated bean classes:
a User class and an Address class. Note that
the two objects are related in a parent-child fashion.
First, listing 1 presents the User bean class:
User.java, a bean for user accounts
package com.wheelersoftware.demos.hibernatevalidator;
import org.hibernate.validator.Email;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.Valid;
public class User {
private String username;
private String firstName;
private String lastName;
private Address address;
private String email;
private String password;
@NotEmpty
@Length(max = 20)
public String getUsername() { return username; }
public void setUsername(String username) {
this.username = username;
}
@NotEmpty
@Length(max = 20)
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@NotEmpty
@Length(max = 20)
public String getLastName() { return lastName; }
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Valid
public Address getAddress() { return address; }
public void setAddress(Address address) {
this.address = address;
}
@NotEmpty
@Email
public String getEmail() { return email; }
public void setEmail(String email) {
this.email = email;
}
@NotEmpty
@Length(max = 20)
public String getPassword() { return password; }
public void setPassword(String password) {
this.password = password;
}
}
Let's talk a little about what's going on with the code above. As we noted earlier, we have a bean class (here, a class that represents user accounts of some sort) and we're using annotations to specify validation constraints. For a full list of the built-in constraints, see the official Hibernate Validator documentation, but we'll just focus on a small handful for right now.
First notice that we've attached our annotations to the getter methods. This is how we specify the validation constraints that attach to the associated properties.
We've used @NotEmpty in several places. This
annotation means that the annotated property can't be null and it
can't be the empty string either. There's also a @NotNull
annotation that we could have used if we'd wanted to, but in this case
I wanted to prevent the empty string from being used as values.
Another annotation that appears multiple times is
the @Length annotation. We can specify associated minimum
and maximum lengths by using the min and max
elements, respectively, though in the example above we've specified
only maximum lengths. (In the example that follows we'll see how to
specify a minimum length as well.) So for example we've specified that
passwords can't be any longer than 20 characters.
A third annotation is the @Email annotation. As you
would guess, this indicates that the property must contain a valid
e-mail address.
The fourth and final annotation of the ones that appear above is
the @Valid annotation. This tells Hibernate Validator
that it should validate the associated object—here an
associated Address object—using whatever validation
annotations we define on the Address class.
And that's our segue into our second example,
the Address bean class, which appears in listing 2
below.
Address.java, a bean for addresses
package com.wheelersoftware.demos.hibernatevalidator;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.Pattern;
public class Address {
private String street1;
private String street2;
private String city;
private String state;
private String zip;
@NotEmpty
@Length(max = 40)
public String getStreet1() { return street1; }
public void setStreet1(String street1) {
this.street1 = street1;
}
// No validation constraints
public String getStreet2() { return street2; }
public void setStreet2(String street2) {
this.street2 = street2;
}
@NotEmpty
@Length(max = 40)
public String getCity() { return city; }
public void setCity(String city) {
this.city = city;
}
@NotEmpty
@Length(max = 3)
public String getState() { return state; }
public void setState(String state) {
this.state = state;
}
@NotEmpty
@Length(min = 5, max = 5, message = "{zip.length}")
@Pattern(regex = "[0-9]+")
public String getZip() { return zip; }
public void setZip(String zip) {
this.zip = zip;
}
}
Our validation annotations for Address are pretty
similar to what we saw for User, but there are a few
differences worth mentioning. First, notice that we don't have to
attach validation constraints to every property. It's OK, for example,
for street2 to be null or anything else, so we simply
refrain from defining validation constraints for this property.
Second, we're using a @Pattern annotation for
the zip property. This allows us to specify regular
expression match patterns.
The third and final difference is the @Length
annotation we've defined for the zip property. Besides
including a min element (which, when combined with
the max element, indicates that the ZIP code must be
exactly five characters long), we've also included
a message element. We can use this element to do either
of two things. First, we can use it to define a hardcoded message to
display when the given validation constraint fails. That's not what
we're doing here. Instead we're doing the second thing we can do,
which is specify a message key using the brace syntax: message =
{key_name}. The idea is that we'll eventually use this message
key to look up a message in a resource bundle, thus externalizing the
message. Later in the tutorial we'll map the zip.length
message key to an actual message using a resource bundle.
That's it for the validation constraints themselves. Now let's see how we can tell Hibernate Validator to use them to perform our bean validation.