weldContexts and Dependency Injection (CDI) (JSR 299) defines a set of services for the Java EE environment that makes applications much easier to develop. It provides an architecture that allows Java EE components such as servlets, enterprise beans, and JavaBeans to exist within the lifecycle of an application with well-defined scopes

 

 

 

In short, CDI helps to bridge a known "gap" between the enterprise tier and the web tier. Until now, if you were to access your business logic from your JSF pages, the best strategy would be to access the JSF Managed Beans which in turn contacted the enterprise components.
jsf-ejb

With CDI the JSF page can access directly enterprise components bringing transactional support to the web tier.

jsf-cdi
How does the magic trick happens ? This can happen thanks to the definition of Managed beans.
Managed beans, which is introduced in Java EE 6, is designed to unify all of the various types of beans in Java EE, including JSF managed beans, enterprise beans, and CDI beans.

Let's understand this better with a sample. We will create a demo application which uses a Facelet to access directly a Session Bean (See this Facelets tutorial for info about facelets)

This sample page collects input (bound to the EL expression #{user.name}) and has an action. The action invokes directly an EJB method:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core">
 
 <h:body>
 <h:form>
 <h:outputText value="Enter your name:" />
 <h:inputText id="name" value="#{user.name}"/> 

 <h:commandButton id="action" value="Done" action="#{clock.action}"  /> 
 <h:messages/>
</h:form>  
 </h:body>
 </html>

This is the sample EJB:
package sample;

import javax.ejb.Stateless;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Date;

@Named
@Stateless
public class Clock {
 
 @Inject User user;
 
 public void action() {
 
 String message = user.getName() + " it is now " + new Date().toString();    
 FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(message));
 }

}

The @Named annotation is a Dependency Injection For Java annotation that is used to associate a name with the bean. Because there is no name specified as an argument to the annotation, the name of the bean will be the name of the JavaBean with its first letter made lowercase, that is, clock. The annotation enables the application to reference the bean by that name using the EL expressions in the view.

The @Inject annotation in  is a CDI annotation that is used to identify a dependency injection point, that is, a point at which a dependency on a Java class or interface can be injected. In this case, the annotation identifies a dependency injection point for the user field of the User class.

And here's the User class:
package sample;

import java.io.Serializable;

import javax.enterprise.context.*;
import javax.inject.Named;


@Named
@SessionScoped
public class User  implements Serializable {
 private String name;

 public String getName() {
 return name;
 }

 public void setName(String name) {
 this.name = name;
 }
}

Here also, the @Named annotation associate the User class with its name (lowercased).
What you should note is the @SessionScoped annotation declares that this bean is a session scoped bean, meaning that its lifecycle is the lifecycle of the session. (And as such, it needs to be Serializable to save its state).

 



 

How to deploy this project ?

 

The simplest way to run this project you need to use JBoss 6 which ships with Weld CDI compatible implementation.

Download JBoss AS

However Weld also runs in servlet engines like Tomcat and Jetty, or even in a plain Java SE environment.

 

Structure of the Project:

 

This is how your Web project should look like:

CDIExample.war
¦   example.xhtml
¦
+---WEB-INF
¦   beans.xml
¦   faces-config.xml
¦   web.xml
¦
+---lib
+---sample
      Clock.class
      User.class

You might have noticed the beans.xml file. This file is required by CDI for using special features of CDI
(like Alternatives, Decorators and others). In our case, just add an empty file named beans.xml.

When executing the web application, you will see that, hitting the button, the EJB will display on your Faces message field the name you typed in the field user.name.

Letting the container create objects:
Using the @Produces annotation you can delegate to the container (instead of the application) the responsibility to create new objects.

By using producer methods let us (among others)

 

  • Expose a JPA entity as a bean,
  • Expose any JDK class as a bean,
  • Define multiple beans, with different scopes or initialization, varying the implementation of a bean type at runtime.


Let's see how to integrate this with out example. Add a new class named Factory to your application:

package sample;

import java.io.Serializable;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

 @ApplicationScoped
 public class Factory implements Serializable {
 private static final long serialVersionUID = -7213673465118041882L;
 
 @Inject User user;  
 
 @Produces @Time String printTime() {
 return user.getName() + " it is now " + new java.util.Date().toString();
 }
 

}

The @ApplicationScoped is the broadest scope which can be set for a bean. It corresponds roughly to the "application" scope of a Web application. (The other scopes allowed are  @RequestScoped, @SessionScoped and @ConversationScoped)

Here we are using the @Produces annotation along with the @Time annotation. @Time is a qualifier annotation which can be used to specify exactly which bean should be injected. (By using a qualifier annotation you can switch the bean implementation at runtime).

In our example, all we have to do is creating a class sample.Time which contains a bare bone definition of an annotation
package sample;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.inject.Qualifier;
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, METHOD, FIELD})
@Qualifier

public @interface Time { }

Think about qualifiers like an extension of the interface. It does not create a direct dependency to any particular implementation. There may be multiple alterative implementations of @Time.

Now, having moved the (silly) "logic" into the class Factory, how does our EJB changes ? simply you have to inject the
@Time annotation (produces by Factory.java) and that's all:
public class Clock {

 @Inject @Time String time;
 public void action() {

 FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(time));
 }

}

Seam vs CDI


The reader who has been playing with Seam framework, will surely found some similar concepts and,in some parts, the CDI implementation is exaclty borrowed from Seam. There are however some differences with Seam

The most important difference is that Seam uses a string-based approach to bind components which is not type safe. On the other hand CDI brings type safety to the limit.

For example, in Seam you would use:

@Name("sampleBean")
public class SampleBean {
 ...
}

While in CDI you would rather use the type-safe :
public class Bean2 {
 @Inject
 private Bean1 bean1;
 ...
}

Also Seam has annotation an (@Factory) which tells Seam to create an instance of a Bean and invoke a method to initialize the value. However you cannot use this annotation to switch the implementation at runtime.

References: http://docs.jboss.org/weld/reference/1.0.0/en-US/html/

0
0
0
s2smodern