JavaWeb-based JavaJSF 2.0 Bean Validation and Dependency Injection

JSF 2.0 Bean Validation and Dependency Injection

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

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.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories