Data validation is such a common functionality in different tiers of Java applications that JSR 303 – bean validation, part of Java EE 6, provides a mechanism to define data validation constraints in a way that is independent of the application tier. This JSR allows you to specify data-validation constraints using annotations.
You can place these annotations on any field, method or class that follows the JavaBean naming convention. You can either use standard annotations (defined in the javax.validation.constraints
package) or write your own custom annotations for specifying constraints.
The table below describes standard bean validation annotations:
Bean Validation Annotation | Constraint Imposed on the Annotated Element |
@NotNull |
Cannot be null |
@Min |
Must be a number whose value must be higher or equal to the specified minimum |
@Max |
Must be a number whose value must be lower or equal to the specified maximum |
@Size |
Must be between specified minimum and maximum limits |
@Pattern |
Must match the specified Java regular expression |
The new release of JavaServer Faces, JSF 2.0, provides built-in support for bean validation if the server runtime (such as Java EE 6) requires it. You can also use it with Hibernate Validator (the reference implementation of JSR 303) in an environment where a Java EE 6 server may not be present.
Managed bean properties are mapped to UIInput
components on the form; so you can place the standard validation constraints on them. The JSF implementation can apply the validation constraints on the component’s values and capture any error message as FacesMessage
, so that you can display them using h:messages
or h:message
.
As an example, suppose you used a JSF 2.0 custom component to create the registration view for a simple online quiz application. (Refer to JSF 2.0: Creating Composite Components for details on how you would do this.) To learn how to use bean validation, you will remodel the RegistrationBean
from the online quiz application’s registration view to include validation constraints on the property fields as shown below:
@ManagedBean
@RequestScoped
public class RegisterBean2 {
@Size(min = 1, message = "Please enter the Email")
@Pattern(regexp = "[a-zA-Z0-9]+@[a-zA-Z0-9]+.[a-zA-Z0-9]+", message = "Email format is invalid.")
private String email;
@Size(min = 1, message = "Please enter a Username")
private String userName;
@Size(min = 1, max = 10, message = "Password is mandatory and cannot contain more than 10 characters")
private String password;
@Size(min = 1, message = "Enter password in Confirm Password field")
private String confirmPassword;
@NotNull(message = "Please enter Date of birth")
private Date dob;
//... no other change required
}
You can impose the mandatory constraint using the @NotNull
annotation, as in the case of the dob
field. For the email
, username
and password
fields, you cannot use @NotNull
as the default values for these would be an empty string and not null. Hence, no validation error will be generated if @NotNull
is used. Instead, you can use @Size
and specify the minimum boundary as 1
. In addition, every constraint annotation has a message element that accepts a string
. Its value will be used to build an error message that will be translated into FacesMessage
and displayed in the response view using h:messages
or h:message
.
Now, you can modify the composite component register.xhtml
. You can remove the mandatory field validation (done using required="true"
) because you have imposed this constraint on the managed bean properties. Similarly, you can also remove the <f:validateRegex>
tag as shown below:
<h:outputText value="#{cc.attrs.emailPrompt}"/>
<h:inputText id="email" value="#{cc.attrs.managedBean.email}" >
<!--
<f:validateRegex pattern="[a-zA-Z0-9]+@[a-zA-Z0-9]+.[a-zA-Z0-9]+"/>
-->
</h:inputText>
You can now test the bean validation support. Figure 1 shows a sample output from submitting the form without entering any values.
Figure 1. Testing Bean Validation Support in Online Quiz App: Here is a sample output from submitting the registration form without entering any values.
JSF 2 also provides a <f:validateBean>
tag that allows you to use validation groups. A validation group defines a subset of constraints; every constraint belongs to one or more groups. You can specify the validation group(s) to be considered during the validation of a component by using the validationGroups
attribute as shown below:
<h:inputText value="#{bean.prop1}">
<f:validateBean validationGroups="com.demo.validation.groups.Group1"/>
</h:inputText>
Dependency Injection in JSF 2.0
Dependency injection (DI) is the concept of providing an external dependency to a specific resource, generally by a Java EE container. It enables you to provide a set of services to Java EE components. The main intent of using DI is to avoid looking up or creating a particular resource from the client program. Part of JSR-330, dependency injection is comprised of a set of annotations.
One of the main features of Java EE 6 is the standardization of annotations to achieve DI through context and dependency injection (CDI), which is specified by JSR-299 (formerly known as Web Beans). Classes that are “injectable” in JSR-299 are portable across frameworks, as JSR-299 includes the DI specification (JSR-330) and the managed beans specification (JSR-316).
As specified by JSR-299, CDI essentially is responsible for providing the following two services:
- Context: Allows you to bind stateful components’ lifecycles and interactions to a well defined and extensible lifecycle context.
- Dependency injection: Allows you to inject these components in a type-safe manner into an application, as well as to inject a particular implementation of an interface at deployment time.
In the case of a Web application, JSR-299 allows you to use any Java EE component (Enterprise JavaBeans, or EJBs, for instance) in conjunction with JSF managed beans. EJBs are by nature transactional, while the components on the Web tier (JSF managed beans) are not transactional. JSR-299 bridges this transactional gap in a Java EE application by enabling the developer to replace the JSF managed bean with an EJB.
In the online quiz application, the SampleTest
managed bean is in the Request scope, whose responsibility is to help the user to get a feel for the questions by enabling him or her to view a sample question. Here is the code:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class SampleTest {
// Some code
}
In this tutorial, you will modify the SampleTest
managed bean class to act as a contextual class, which will include both the application code and the state.
The contextual SampleTest
class is marked with the @Named
annotation defined in the javax.inject
package. The @Named
annotation marks a class with a specific name. If no arguments are provided to the @Named
annotation, then the class name is considered to be the default bean name with the first letter being lowercase (the bean naming convention in JSF 2.0). The class is also annotated with @RequestScoped
, which is defined in the javax.enterprise.context
package (a JSR-299-specific annotation, which specifies that now the bean can be made available to all the other components in the request scope).
@Named
@RequestScoped
public class SampleTest {
@SampleTestQuestion
@Inject
private String sampleQuestion;
//Some more Code
}
The @Inject
annotation defined in the javax.inject
package is a CDI annotation applied to the sampleQuestion
property of the SampleTest
class. The @Inject
annotation identifies the point at which the dependency needs to be injected. The sampleQuestion
property is also decorated with the @SampleTestQuestion
qualifier annotation, which is the actual implementation that gets injected into the property. You can provide different implementations for the same bean type by using qualifiers. The @SampleTestQuestion
qualifier injects a sample question that the user can attempt to answer to the sampleQuestion
bean property.
The @SampleTestQuestion
qualifier is defined as follows:
@Target ({TYPE, METHOD, PARAMETER, FIELD})
@Retention (RUNTIME)
@Documented
@Qualifier
public @interface SampleTestQuestion {
}
The @Target
, @Retention
and @Documented
annotations are defined at the Java language level in the java.lang.annotation
package:
- The
@Target
annotation is required to identify all the elements of the program for which this annotation is applicable. - The
@Retention
annotation denotes the retention time for a particular annotation, and@SampleTestQuestion
will be retained completely within the runtime of the online quiz application. - The
@Documented
annotation suggests that by default the types should be documented by Javadoc or any other similar tools.
The @Qualifier
defined in the javax.inject
package is used to recognize a qualifier annotation, which is required to identify a particular implementation of a Java class or an interface that will be injected. @Interface
is the keyword used to create an Annotation type.
You now have to define the SampleTestQuestionGenerator
class, which defines a producer method that gets implicitly invoked when the injection takes place. This class has a generate()
method annotated with @Produces
(defined in javax.enterprise.inject
package) to mark the producer method of a qualifier. The generate()
method is also annotated with the qualifier for which this method acts as a producer. The generator class is defined in the application scope by annotating it with
@javax.enterprise.context.ApplicationScoped
.
@ApplicationScoped
public class SampleTestQuestionGenerator {
@Produces
@SampleTestQuestion
String generate () {
return "First Prime Minister of India";
}
}
After the user login is successful, the user chooses to check for a sample question by clicking the Try Sample link, which takes the user to the Sample Question page. The SampleTest
class is annotated with the @javax.inject.Named
annotation, where the class gets identified by a particular name in the application in a specific scope. The sampleQuestion
property of the SampleTest
class requires a dependency to be injected via @javax.inject.Inject
and the @SampleTestQuestion
annotation. The @SampleTestQuestion
qualifier has a generator class SampleTestQuestionGenerator
which has a producer method, generate()
, identified by @javax.enterprise.inject.Produces
, the method that gets invoked when a dependency needs to be injected into a resource.
Conclusion
JSF 2 introduces new features that have simplified the process of web application development in Java. Particularly, the bean validation support in JSF 2 provides an alternative to the existing validation model, which uses special tags and attributes. Dependency injection in conjunction with JSF 2.0 allows a bean to be given a name, which can be accessed anywhere within the scope of a JSF application. Classes that can be injected are now portable across various frameworks.
Acknowledgements
The authors would like to sincerely thank Mr. Subrahmanya (SV, VP, ECOM Research Group, E&R) for his ideas, guidance, support and constant encouragement and Ms. Mahalakshmi for kindly reviewing this article and for her valuable comments.About the Authors
Sangeetha S. works as a Senior Technical Architect at the E-Commerce Research Labs at Infosys Technologies. She has over 10 years of experience in design and development of Java and Java EE applications. She has co-authored a book on ‘J2EE Architecture’ and also has written articles for online Java publications.
Nitin KL works at the E-Commerce Research Labs at Infosys Technologies. He is involved in design and development of Java EE applications using Hibernate, iBATIS, and JPA.
Ananya S. works at the E-Commerce Research Labs at Infosys Technologies. She is involved in design and development of Java EE applications using Hibernate, iBATIS, and JPA.