Java EE Bean Validation Example
1. Introduction
Hi Java Code Geeks fan! This article is about a Java EE Bean Validation Example. One coding practice that we should do is to always validate variables before using. In this example we validate the input received from the user to maintain data integrity. Maintaining data integrity is an important part of application logic. Validating data can take place at different layers. For example, the JavaServer Faces standard validators validate data at the presentation layer (e.g. validateLength, validateLongRange
, etc.).
2. Bean Validation
JavaBeans Validation is part of the Java EE platform. It was made available starting with Java EE 6. The Bean Validation model is supported by constraints in the form of annotations placed on a field, method, or class of a JavaBeans component, such as a managed bean. There are many built-in constraints available in the javax.validation.constraints
package. Furthermore, constraints can also be user defined or customized.
3. Bean Validation vs JSF Validation
To Bean validate or to JSF validate? That is the question. When should I use Bean validation? When should I use JSF validation? The short answer is it depends. It would depend on the requirement specification. But Bean validation has an advantage of being DRY. The validation logic is removed from the view and if configured at the entity level, it’s reusable for all frameworks other than JSF. If we use a bean multiple times, then we only write the validation once with Bean validation. In contrast, we would write JSF validation on every Facelets page which can lead to a maintenance headache.
4. Tools and Requirements
The source in this is example is based on the Java EE Web Project in Red Hat Central. We will not go through the details of setting up the project, so it is recommended that Eclipse with WildFly and JBoss Tools Example be read before trying out the example. We’ll be using WildFly 10.1.0 but later versions should work.
Once you have the tools and requirements done, import the java-ee-bean-validation-example project in Eclipse.
5. Backing Bean
Shown below is a fragment of IndexBacking.java
. Open the said file in Eclipse to view the entire code.
IndexBacking.java
package com.javacodegeeks.example.backing; import javax.enterprise.context.RequestScoped; import javax.inject.Named; import javax.validation.constraints.Digits; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.NotEmpty; import com.javacodegeeks.example.constraints.CompanyEmail; @Named @RequestScoped public class IndexBacking { @NotNull @Size(min = 1, max = 25) @Pattern(regexp = "[^0-9]*", message = "Must not contain numbers") private String name; @NotNull @NotEmpty @Email private String email; @NotNull @Size(min = 10, max = 12) @Digits(fraction = 0, integer = 12) private String phoneNumber; private String title; @NotNull @NotEmpty @Email @CompanyEmail(value = "@javacodegeeks.com") private String companyEmail; ...snipped... }
We have placed the following constraints on the fields of the IndexBacking
class.
@NotNull
, The value of the field or property must not be null.@Size
, The size of the field or property is evaluated and must match the specified boundaries. If the field or property is a String, the size of the string is evaluated. If the field or property is a Collection, the size of the Collection is evaluated. If the field or property is a Map, the size of the Map is evaluated. If the field or property is an array, the size of the array is evaluated. Use one of the optional max or min elements to specify the boundaries.@Pattern
, The value of the field or property must match the regular expression defined in the regexp element.@NotEmpty
, Checks whether the annotated element is not null nor empty.@Email
, Checks whether the specified character sequence is a valid email address. The optional parameters regexp and flags allow to specify an additional regular expression (including regular expression flags) which the email must match.@Digits
, The value of the field or property must be a number within a specified range. The integer element specifies the maximum integral digits for the number, and the fraction element specifies the maximum fractional digits for the number.@CompanyEmail
, Our custom constraint.
The @Email
and @NotEmpty
constraints belong to the Hibernate Validator library. The Hibernate Validator is the reference implementation of Bean validation. The @CompanyEmail
is our custom constraint which will be explained later. The rest belong to the Built-In Bean Validation Constraints. Check out the mentioned links for more details on the constraints.
Run the web application and input invalid data. You should see something like below:
6. Validating Null and Empty Strings
The Java programming language distinguishes between null and empty strings. Here is a web.xml context parameter that can save us a lot of headache. Let’s open our web.xml file. Here we have set the javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
context parameter to true. This parameter enables the JavaServer Faces implementation to treat empty strings as null. If you have a @NotNull
constraint on an element, meaning that input is required. An empty string will pass this validation constraint. However, if you set the aforementioned context parameter to true, the value of the managed bean attribute is passed to the Bean Validation runtime as a null value, causing the @NotNull
constraint to fail.
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" > <context-param> <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> <param-value>true</param-value> </context-param> </web-app>
In our example, there are no contraints on the title
field. Input the following, name: xyz, email: xyz@example.com, phone: 1234567890, company email: xyz@javacodegeeks.com, and leave title empty. We should see something like below in the console output.
null title
14:18:27,267 INFO [stdout] (default task-3) Registering xyz, xyz@example.com, 1234567890, null, xyz@javacodegeeks.com
The title is null
. Now, this time input a couple of spaces in the title
field. We should see something like below in the console output.
spaces on title
14:43:26,057 INFO [stdout] (default task-4) Registering xyz, xyz@example.com, 1234567890, , xyz@javacodegeeks.com
Did you notice the spaces in between the phone number and the javacodegeeks email?
7. Custom Bean Validation Contraint
In our example, we want the Company email to be @javacodegeeks.com. CompanyEmail
is our annotation type. To define this annotation type as a Bean Validation Constraint, we added the annotation @Constraint
in its declaration.
CompanyEmail.java
package com.javacodegeeks.example.constraints; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Target({ FIELD }) @Retention(RUNTIME) @Documented @Constraint(validatedBy = { CompanyEmailValidator.class }) public @interface CompanyEmail { String message() default "Company email does not contain {value}."; Class<?>[] groups() default { }; //required Class<? extends Payload>[] payload() default { }; //required String value(); }
@Target
, Is where our annotations can be used.@Retention
, Specifies how the marked annotation is stored. We choose RUNTIME, so it can be used by the runtime environment.@Constraint
, Marks an annotation as being a Bean Validation constraint. The elementvalidatedBy
specifies the class implementing the constraint.message
, Defines the message that will be shown when the input data is not valid.groups
, Lets the developer select to split the annotations into different groups to apply different validations to each group.payload
, Payloads are typically used to carry metadata information consumed by a validation client.value
, The value that will be used to define whether the input value is valid or is not.
CompanyEmailValidator.java
package com.javacodegeeks.example.constraints; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class CompanyEmailValidator implements ConstraintValidator<CompanyEmail, String> { protected String companyEmailSuffix; @Override public void initialize(CompanyEmail email) { companyEmailSuffix = email.value(); } @Override public boolean isValid(String email, ConstraintValidatorContext context) { if (email != null && email.endsWith(companyEmailSuffix)) { return true; } return false; } }
A validator class must implement ConstraintValidator
. It has two methods: initialize
and isValid
. The method initialize
will be used to establish the necessary attributes to execute the validation — in our case, the email is “@javacodegeeks.com”. isValid
is the method that received the input value and decides whether it is valid or is not. The implementation of ConstraintValidator<CompanyEmail, String>
says it accepts CompanyEmail
as an annotation and the input value must be a type of String.
As you might have already seen, this is how we used the custom constraint.
IndexBacking.java
@CompanyEmail(value = "@javacodegeeks.com") private String companyEmail;
8. Java EE Bean Validation Example Summary
There you have it. Now you know which validation technique to use. You may choose Bean validation over JSF validation. There are many built-in validation constraints but you can also create your own. Furthermore, setting the javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
context parameter of the web deployment descriptor can hopefully reduce your validation headache. Simples! Or not?
7. Download the Source Code
This is an example about Java EE Bean Validation.
You can download the source code of this example here: Java EE Bean Validation Example