SeamFramework.orgCommunity Documentation
Shortly before the final draft of JSR-299 was submitted, the specification changed its name from "Web Beans" to "Java Contexts and Dependency Injection for the Java EE platform", abbreviated CDI. For a brief period after the renaming, the reference implementation adopted the name "Web Beans". However, this ended up causing more confusion than it solved and Red Hat decided to change the name of the reference implementation to "Weld". You may still find other documentation, blogs, forum posts, etc. that use the old nomenclature. Please update any references you can. The naming game is over.
You'll also find that some of the functionality that once existed in the specification is now missing, such as defining beans in XML. These features will be available as portable extensions for CDI in the Weld project, and perhaps other implementations.
Note that this reference guide was started while changes were still being made to the specification. We've done our best to update it for accuracy. If you discover a conflict between what is written in this guide and the specification, the specification is the authority—assume it is correct. If you believe you have found an error in the specification, please report it to the JSR-299 EG.
The JSR-299 specification (CDI) defines a set of complementary services that help improve the structure of application code. CDI layers an enhanced lifecycle and interaction model over existing Java component types, including managed beans and Enterprise Java Beans. The CDI services provide:
an improved lifecycle for stateful objects, bound to well-defined contexts,
a typesafe approach to dependency injection,
object interaction via an event notification facility,
a better approach to binding interceptors to objects, along with a new kind of interceptor, called a decorator, that is more appropriate for use in solving business problems, and
an SPI for developing portable extensions to the container.
The CDI services are a core aspect of the Java EE platform and include full support for Java EE modularity and the Java EE component architecture. But the specification does not limit the use of CDI to the Java EE environment. In the Java SE environment, the services might be provided by a standalone CDI implementation like Weld (see Section 18.4.1, “CDI SE Module”), or even by a container that also implements the subset of EJB defined for embedded usage by the EJB 3.1 specification. CDI is especially useful in the context of web application development, but the problems it solves are general development concerns and it is therefore applicable to a wide variety of application.
An object bound to a lifecycle context is called a bean. CDI includes built-in support for several different kinds of bean, including the following Java EE component types:
managed beans, and
EJB session beans.
Both managed beans and EJB session beans may inject other beans. But some other objects, which are not themselves beans in the sense used here, may also have beans injected via CDI. In the Java EE platform, the following kinds of component may have beans injected:
message-driven beans,
interceptors,
servlets, servlet filters and servlet event listeners,
JAX-WS service endpoints and handlers, and
JSP tag handlers and tag library event listeners.
CDI relieves the user of an unfamiliar API of the need to answer the following questions:
What is the lifecycle of this object?
How many simultaneous clients can it have?
Is it multithreaded?
How do I get access to it from a client?
Do I need to explicitly destroy it?
Where should I keep the reference to it when I'm not currently using it?
How can I define an alternative implementation, so that the implementation can vary at deployment time?
How should I go about sharing this object between other objects?
CDI is more than a framework. It's a whole, rich programming model. The theme of CDI is loose-coupling with strong typing. Let's study what that phrase means.
A bean specifies only the type and semantics of other beans it depends upon. It need not be aware of the actual lifecycle, concrete implementation, threading model or other clients of any bean it interacts with. Even better, the concrete implementation, lifecycle and threading model of a bean may vary according to the deployment scenario, without affecting any client. This loose-coupling makes your code easier to maintain.
Events, interceptors and decorators enhance the loose-coupling inherent in this model:
event notifications decouple event producers from event consumers,
interceptors decouple technical concerns from business logic, and
decorators allow business concerns to be compartmentalized.
What's even more powerful (and comforting) is that CDI provides all these facilities in a typesafe way. CDI never relies on string-based identifiers to determine how collaborating objects fit together. Instead, CDI uses the typing information that is already available in the Java object model, augmented using a new programming pattern, called qualifier annotations, to wire together beans, their dependencies, their interceptors and decorators, and their event consumers. Usage of XML descriptors is minimized to truly deployment-specific information.
But CDI isn't a restrictive programming model. It doesn't tell you how you should to structure your application into layers, how you should handle persistence, or what web framework you have to use. You'll have to decide those kinds of things for yourself.
CDI even provides a comprehensive SPI, allowing other kinds of object defined by future Java EE specifications or by third-party frameworks to be cleanly integrated with CDI, take advantage of the CDI services, and interact with any other kind of bean.
CDI was influenced by a number of existing Java frameworks, including Seam, Guice and Spring. However, CDI has its own, very distinct, character: more typesafe than Seam, more stateful and less XML-centric than Spring, more web and enterprise-application capable than Guice. But it couldn't have been any of these without inspiration from the frameworks mentioned and lots of collaboration and hard work by the JSR-299 Expert Group (EG).
Finally, CDI is a Java Community Process (JCP) standard. Java EE 6 requires that all compliant application servers provide support for JSR-299 (even in the web profile).
Table of Contents
So you're keen to get started writing your first bean? Or perhaps you're skeptical, wondering what kinds of hoops the CDI specification will make you jump through! The good news is that you've probably already written and used hundreds, perhaps thousands of beans. CDI just makes it easier to actually use them to build an application!
A bean is exactly what you think it is. Only now, it has a true identity in the container environment.
Prior to Java EE 6, there was no clear definition of the term "bean" in the Java EE platform. Of course, we've been calling Java classes used in web and enterprise applications "beans" for years. There were even a couple of different kinds of things called "beans" in EE specifications, including EJB beans and JSF managed beans. Meanwhile, other third-party frameworks such as Spring and Seam introduced their own ideas of what it meant to be a "bean". What we've been missing is a common definition.
Java EE 6 finally lays down that common definition in the Managed Beans specification. Managed Beans are defined as container-managed objects with minimal programming restrictions, otherwise known by the acronym POJO (Plain Old Java Object). They support a small set of basic services, such as resource injection, lifecycle callbacks and interceptors. Companion specifications, such as EJB and CDI, build on this basic model. But, at last, there's a uniform concept of a bean and a lightweight component model that's aligned across the Java EE platform.
With very few exceptions, almost every concrete Java class that has a constructor with no parameters (or a
constructor designated with the annotation @Inject) is a bean. This includes every
JavaBean and every EJB session bean. If you've already got some JavaBeans or session beans lying around,
they're already beans—you won't need any additional special metadata. There's just little one thing you
need to do before you can start injecting them into stuff: you need to put them in an archive (a jar, or a
Java EE module such as a war or EJB jar) that contains a special marker file: META-INF/beans.xml.
The JavaBeans and EJBs you've been writing every day, up until now, have not been able to take advantage of the new services defined by the CDI specification. But you'll be able to use every one of them with CDI—allowing the container to create and destroy instances of your beans and associate them with a designated context, injecting them into other beans, using them in EL expressions, specializing them with qualifier annotations, even adding interceptors and decorators to them—without modifying your existing code. At most, you'll need to add some annotations.
Now let's see how to create your first bean that actually uses CDI.
Suppose that we have two existing Java classes that we've been using for years in various applications. The first class parses a string into a list of sentences:
public class SentenceParser {
public List<String> parse(String text) { ... }
}
The second existing class is a stateless session bean front-end for an external system that is able to translate sentences from one language to another:
@Stateless
public class SentenceTranslator implements Translator {
public String translate(String sentence) { ... }
}
Where Translator is the EJB local interface:
@Local
public interface Translator {
public String translate(String sentence);
}
Unfortunately, we don't have a class that translates whole text documents. So let's write a bean for this job:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Inject
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
}
But wait! TextTranslator does not have a constructor with no parameters! Is it still a bean?
If you remember, a class that does not have a constructor with no parameters can still be a bean if it has a
constructor annotated @Inject.
As you've guessed, the @Inject annotation has something to do with dependency injection!
@Inject may be applied to a constructor or method of a bean, and tells the container to
call that constructor or method when instantiating the bean. The container will inject other beans into the
parameters of the constructor or method.
We may obtain an instance of TextTranslator by injecting it into a constructor, method
or field of a bean, or a field or method of a Java EE component class such as a servlet. The container
chooses the object to be injected based on the type of the injection point, not the name of the field,
method or parameter.
Let's create a UI controller bean that uses field injection to obtain an instance of the
TextTranslator, translating the text entered by a user:
@Named @RequestScoped
public class TranslateController {@Inject TextTranslator textTranslator;
private String inputText;
private String translation;
// JSF action method, perhaps
public void translate() {
translation = textTranslator.translate(inputText);
}
public String getInputText() {
return inputText;
}
public void setInputText(String text) {
this.inputText = text;
}
public String getTranslation() {
return translation;
}
}
|
Field injection of |
Notice the controller bean is request-scoped and named. Since this combination is so common in web
applications, there's a built-in annotation for it in CDI that we could have used as a shorthand. When the
(stereotype) annotation @Model is declared on a class, it creates a request-scoped and
named bean.
Alternatively, we may obtain an instance of TextTranslator programmatically from an injected
instance of Instance, parameterized with the bean type:
@Inject Instance<TextTranslator> textTranslatorInstance;
...
public void translate() {
textTranslatorInstance.get().translate(inputText);
}
Notice that it isn't necessary to create a getter or setter method to inject one bean into another. CDI can access an injected field directly (even if it's private!), which sometimes helps eliminate some wasteful code. The name of the field is arbitrary. It's the field's type that determines what is injected.
At system initialization time, the container must validate that exactly one bean exists which satisfies each
injection point. In our example, if no implementation of Translator is available—if
the SentenceTranslator EJB was not deployed—the container would inform us of an
unsatisfied dependency. If more than one implementation of Translator
were available, the container would inform us of the ambiguous dependency.
Before we get too deep in the details, let's pause and examine a bean's anatomy. What aspects of the bean are significant, and what gives it its identity? Instead of just giving examples of beans, we're going to define what makes something a bean.
A bean is usually an application class that contains business logic. It may be called directly from Java code, or it may be invoked via the Unified EL. A bean may access transactional resources. Dependencies between beans are managed automatically by the container. Most beans are stateful and contextual. The lifecycle of a bean is always managed by the container.
Let's back up a second. What does it really mean to be contextual? Since beans may be stateful, it matters which bean instance I have. Unlike a stateless component model (for example, stateless session beans) or a singleton component model (such as servlets, or singleton beans), different clients of a bean see the bean in different states. The client-visible state depends upon which instance of the bean the client has a reference to.
However, like a stateless or singleton model, but unlike stateful session beans, the client does not control the lifecycle of the instance by explicitly creating and destroying it. Instead, the scope of the bean determines:
the lifecycle of each instance of the bean and
which clients share a reference to a particular instance of the bean.
For a given thread in a CDI application, there may be an active context associated with the scope of the bean. This context may be unique to the thread (for example, if the bean is request scoped), or it may be shared with certain other threads (for example, if the bean is session scoped) or even all other threads (if it is application scoped).
Clients (for example, other beans) executing in the same context will see the same instance of the bean. But clients in a different context may see a different instance (depending on the relationship between the contexts).
One great advantage of the contextual model is that it allows stateful beans to be treated like services! The client need not concern itself with managing the lifecycle of the bean it's using, nor does it even need to know what that lifecycle is. Beans interact by passing messages, and the bean implementations define the lifecycle of their own state. The beans are loosely coupled because:
they interact via well-defined public APIs
their lifecycles are completely decoupled
We can replace one bean with another different bean that implements the same interface and has a different lifecycle (a different scope) without affecting the other bean implementation. In fact, CDI defines a simple facility for overriding bean implementations at deployment time, as we will see in Section 4.7, “Alternatives”.
Note that not all clients of a bean are beans themselves. Other objects such as servlets or message-driven beans—which are by nature not injectable, contextual objects—may also obtain references to beans by injection.
Enough hand-waving. More formally, the anatomy of a bean, according to the spec:
A bean comprises the following attributes:
A (nonempty) set of bean types
A (nonempty) set of qualifiers
A scope
Optionally, a bean EL name
A set of interceptor bindings
A bean implementation
Furthermore, a bean may or may not be an alternative.
Let's see what all this new terminology means.
Beans usually acquire references to other beans via dependency injection. Any injected attribute specifies a "contract" that must be satisfied by the bean to be injected. The contract is:
a bean type, together with
a set of qualifiers.
A bean type is a user-defined class or interface; a type that is client-visible. If the bean is an EJB
session bean, the bean type is the @Local interface or bean-class local view. A bean
may have multiple bean types. For example, the following bean has four bean types:
public class BookShop
extends Business
implements Shop<Book> {
...
}
The bean types are BookShop, Business and
Shop<Book>, as well as the implicit type java.lang.Object.
(Notice that a parameterized type is a legal bean type).
Meanwhile, this session bean has only the local interfaces BookShop,
Auditable and java.lang.Object as bean types, since the bean class,
BookShopBean is not a client-visible type.
@Stateful
public class BookShopBean
extends Business
implements BookShop, Auditable {
...
}
The bean types of a session bean include local interfaces and the bean class local view (if any). EJB remote interfaces are not considered bean types of a session bean. You can't inject an EJB using its remote interface unless you define a resource, which we'll meet in Chapter 14, Java EE component environment resources.
Bean types may be restricted to an explicit set by annotating the bean with the @Typed
annotation and listing the classes that should be bean types. For instance, the bean types of this bean have
been restricted to Shop<Book>, together with java.lang.Object:
@Typed(Shop.class)
public class BookShop
extends Business
implements Shop<Book> {
...
}
Sometimes, a bean type alone does not provide enough information for the container to know which bean to inject.
For instance, suppose we have two implementations of the PaymentProcessor interface:
CreditCardPaymentProcessor and DebitPaymentProcessor. Injecting a field of
type PaymentProcessor introduces an ambiguous condition. In these cases, the client must
specify some additional quality of the implementation it is interested in. We model this kind of "quality" using
a qualifier.
A qualifier is a user-defined annotation that is itself annotated @Qualifer. A qualifier
annotation is an extension of the type system. It lets us disambiguate a type without having to fall back to
string-based names. Here's an example of a qualifier annotation:
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface CreditCard {}
You may not be used to seeing the definition of an annotation. In fact, this might be the first time you've encountered one. With CDI, annotation definitions will become a familiar artifact as you'll be creating them from time to time.
Pay attention to the names of the built-in annotations in CDI and EJB. You'll notice that they are often adjectives. We encourage you to follow this convention when creating your custom annotations, since they serve to describe the behaviors and roles of the class.
Now that we have defined a qualifier annotation, we can use it to disambiguate an injection point. The
following injection point has the bean type PaymentProcessor and qualifier
@CreditCard:
@Inject @CreditCard PaymentProcessor paymentProcessor
If an injection point does not explicitly specify a qualifier, it has the default qualifier,
@Default.
For each injection point, the container searches for a bean which satisfies the contract, one which has the bean type and all the qualifiers. If it finds exactly one matching bean, it injects an instance of that bean. If it doesn't, it reports an error to the user.
How do we specify that qualifiers of a bean? By annotating the bean class, of course! The following bean
has the qualifier @CreditCard and implements the bean type PaymentProcessor.
Therefore, it satisfies our qualified injection point:
@CreditCard
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }
If a bean does not explicitly specify a qualifier, it has the default qualifier, @Default.
That's not quite the end of the story. CDI also defines a simple resolution rule that helps the container decide what to do if there is more than one bean that satisfies a particular contract. We'll get into the details in Chapter 4, Dependency injection and programmatic lookup.
The scope of a bean defines the lifecycle and visibility of its instances. The CDI context model is extensible, accommodating arbitrary scopes. However, certain important scopes are built into the specification, and provided by the container. Each scope is represented by an annotation type.
For example, any web application may have session scoped bean:
public @SessionScoped
class ShoppingCart implements Serializable { ... }
An instance of a session-scoped bean is bound to a user session and is shared by all requests that execute in the context of that session.
Keep in mind that once a bean is bound to a context, it remains in that context until the context is destroyed. There is no way to manually remove a bean from a context. If you don't want the bean to sit in the session indefinitely, consider using another scope with a shorted lifespan, such as the request or conversation scope.
If a scope is not explicitly specified, then the bean belongs to a special scope called the dependent pseudo-scope. Beans with this scope live to serve the object into which they were injected, which means their lifecycle is bound to the lifecycle of that object.
We'll talk more about scopes in Chapter 5, Scopes and contexts.
If you want to reference a bean in non-Java code that supports Unified EL expressions, for example, in a JSP or JSF page, you must assign the bean an EL name.
The EL name is specified using the @Named annotation, as shown here:
public @SessionScoped @Named("cart")
class ShoppingCart implements Serializable { ... }
Now we can easily use the bean in any JSF or JSP page:
<h:dataTable value="#{cart.lineItems}" var="item">
...
</h:dataTable>
The @Named annotation is not what makes the class a bean. Most classes in a bean
archive are already recognized as beans. The @Named annotation just makes it
possible to reference the bean from the EL, most commonly from a JSF view.
We can let CDI choose a name for us by leaving off the value of the @Named annotation:
public @SessionScoped @Named
class ShoppingCart implements Serializable { ... }
The name defaults to the unqualified class name, decapitalized; in this case,
shoppingCart.
We've already seen how qualifiers let us choose between multiple implementations of an interface
at development time. But sometimes we have an interface (or other bean type) whose implementation
varies depending upon the deployment environment. For example, we may want to use a mock
implementation in a testing environment. An alternative may be declared by
annotating the bean class with the @Alternative annotation.
public @Alternative
class MockPaymentProcessor extends PaymentProcessorImpl { ... }
We normally annotate a bean @Alternative only when there is some other
implementation of an interface it implements (or of any of its bean types). We can choose between
alternatives at deployment time by selecting an alternative in the CDI
deployment descriptor META-INF/beans.xml of the jar or Java EE module that uses
it. Different modules can specify that they use different alternatives.
We cover alternatives in more detail in Section 4.7, “Alternatives”.
You might be familiar with the use of interceptors in EJB 3.0. In Java EE 6, this functionality has been generalized to work with other managed beans. That's right, you no longer have to make your bean an EJB just to intercept its methods. Holler. So what does CDI have to offer above and beyond that? Well, quite a lot actually. Let's cover some background.
The way that interceptors were defined in Java EE 5 was counter-intuitive. You were required to specify the
implementation of the interceptor directly on the implementation
of the EJB, either in the @Interceptors annotation or in the XML descriptor. You might as
well just put the interceptor code in the implementation! Second, the order in which
the interceptors are applied is taken from the order in which they are declared in the annotation or the XML
descriptor. Perhaps this isn't so bad if you're applying the interceptors to a single bean. But, if you are
applying them repeatedly, then there's a good chance that you'll inadvertently define a different order for
different beans. Now that's a problem.
CDI provides a new approach to binding interceptors to beans that introduces a level of indirection (and thus control). We must define an interceptor binding type to describe the behavior implemented by the interceptor.
An interceptor binding type is a user-defined annotation that is itself annotated @InterceptorBinding.
It lets us bind interceptor classes to bean classes with no direct dependency between the two classes.
@InterceptorBinding
@Inherited
@Target( { TYPE, METHOD })
@Retention(RUNTIME)
public @interface Transactional {}
The interceptor that implements transaction management declares this annotation:
public @Transactional @Interceptor
class TransactionInterceptor { ... }
We can apply the interceptor to a bean by annotating the bean class with the same interceptor binding type:
public @SessionScoped @Transactional
class ShoppingCart implements Serializable { ... }
Notice that ShoppingCart and TransactionInterceptor don't know
anything about each other.
Interceptors are deployment-specific. (We don't need a TransactionInterceptor in our
unit tests!) By default, an interceptor is disabled. We can enable an interceptor using the CDI deployment
descriptor META-INF/beans.xml of the jar or Java EE module. This is also where we
specify the interceptor ordering.
We'll discuss interceptors, and their cousins, decorators, in Chapter 9, Interceptors and Chapter 10, Decorators.
We've already seen two types of beans: JavaBeans and EJB session beans. Is that the whole story? Actually, it's just the beginning. Let's explore the various kinds of beans that CDI implementations must support out-of-the-box.
A managed bean is a Java class. The basic lifecycle and semantics of a managed bean are defined by the
Managed Beans specification. You can explicitly declare a managed bean by annotating the bean class
@ManagedBean, but in CDI you don't need to. According to the specification, the CDI
container treats any class that satisfies the following conditions as a managed bean:
It is not a non-static inner class.
It is a concrete class, or is annotated
@Decorator.It is not annotated with an EJB component-defining annotation or declared as an EJB bean class in
ejb-jar.xml.It does not implement
javax.enterprise.inject.spi.Extension.It has an appropriate constructor—either:
the class has a constructor with no parameters, or
the class declares a constructor annotated
@Inject.
According to this definition, JPA entities are technically managed beans. However, entities have their own
special lifecycle, state and identity model and are usually instantiated by JPA or using new.
Therefore we don't recommend directly injecting an entity class. We especially recommend against assigning
a scope other than @Dependent to an entity class, since JPA is not able to persist
injected CDI proxies.
The unrestricted set of bean types for a managed bean contains the bean class, every superclass and all interfaces it implements directly or indirectly.
If a managed bean has a public field, it must have the default scope @Dependent.
Managed beans support the @PostConstruct and @PreDestroy lifecycle
callbacks.
Session beans are also, technically, managed beans. However, since they have their own special lifecycle and take advantage of additional enterprise services, the CDI specification considers them to be a different kind of bean.
Session beans belong to the EJB specification. They have a special lifecycle, state management and concurrency model that is different to other managed beans and non-managed Java objects. But session beans participate in CDI just like any other bean. You can inject one session bean into another session bean, a managed bean into a session bean, a session bean into a managed bean, have a managed bean observe an event raised by a session bean, and so on.
Message-driven and entity beans are by nature non-contextual objects and may not be injected into other objects. However, message-driven beans can take advantage of some CDI functionality, such as dependency injection, interceptors and decorators. In fact, CDI will perform injection into any session or message-driven bean, even those which are not contextual instances.
The unrestricted set of bean types for a session bean contains all local interfaces of the bean and their
superinterfaces. If the session bean has a bean class local view, the unrestricted set of bean types
contains the bean class and all superclasses. In addition, java.lang.Object is a bean
type of every session bean. But remote interfaces are not included in the set of bean
types.
There's no reason to explicitly declare the scope of a stateless session bean or singleton session bean.
The EJB container controls the lifecycle of these beans, according to the semantics of the @Stateless
or @Singleton declaration. On the other hand, a stateful session bean may have any scope.
Stateful session beans may define a remove method, annotated @Remove,
that is used by the application to indicate that an instance should be destroyed. However, for a contextual
instance of the bean—an instance under the control of CDI—this method may only be called by the
application if the bean has scope @Dependent. For beans with other scopes, the application
must let the container destroy the bean.
So, when should we use a session bean instead of a plain managed bean? Whenever we need the advanced enterprise services offered by EJB, such as:
method-level transaction management and security,
concurrency management,
instance-level passivation for stateful session beans and instance-pooling for stateless session beans,
remote or web service invocation, or
timers and asynchronous methods,
When we don't need any of these things, an ordinary managed bean will serve just fine.
Many beans (including any @SessionScoped or @ApplicationScoped
beans) are available for concurrent access. Therefore, the concurrency management provided by EJB 3.1
is especially useful. Most session and application scoped beans should be EJBs.
Beans which hold references to heavy-weight resources, or hold a lot of internal state benefit from the advanced container-managed lifecycle defined by the EJB stateless/stateful/singleton model, with its support for passivation and instance pooling.
Finally, it's usually obvious when method-level transaction management, method-level security, timers, remote methods or asynchronous methods are needed.
The point we're trying to make is: use a session bean when you need the services it provides, not just
because you want to use dependency injection, lifecycle management, or interceptors. Java EE 6 provides
a graduated programming model. It's usually easy to start with an ordinary managed bean, and later turn
it into an EJB just by adding one of the following annotations: @Stateless,
@Stateful or @Singleton.
On the other hand, don't be scared to use session beans just because you've heard your friends say they're "heavyweight". It's nothing more than superstition to think that something is "heavier" just because it's hosted natively within the Java EE container, instead of by a proprietary bean container or dependency injection framework that runs as an additional layer of obfuscation. And as a general principle, you should be skeptical of folks who use vaguely defined terminology like "heavyweight".
Not everything that needs to be injected can be boiled down to a bean class instantiated by the container
using new. There are plenty of cases where we need additional control. What if we need
to decide at runtime which implementation of a type to instantiate and inject? What if we need to inject
an object that is obtained by querying a service or transactional resource, for example by executing a JPA
query?
A producer method is a method that acts as a source of bean instances. The method declaration itself describes the bean and the container invokes the method to obtain an instance of the bean when no instance exists in the specified context. A producer method lets the application take full control of the bean instantiation process.
A producer method is declared by annotating a method of a bean class with the @Produces
annotation.
@ApplicationScoped
public class RandomNumberGenerator {
private Random random = new Random(System.currentTimeMillis());
@Produces @Named @Random int getRandomNumber() {
return random.nextInt(100);
}
}
We can't write a bean class that is itself a random number. But we can certainly write a method that returns
a random number. By making the method a producer method, we allow the return value of the method—in this
case an Integer—to be injected. We can even specify a qualifier—in this case
@Random, a scope—which in this case defaults to @Dependent,
and an EL name—which in this case defaults to randomNumber according to the JavaBeans
property name convention. Now we can get a random number anywhere:
@Inject @Random int randomNumber;
Even in a Unified EL expression:
<p>Your raffle number is #{randomNumber}.</p>A producer method must be a non-abstract method of a managed bean class or session bean class. A producer method may be either static or non-static. If the bean is a session bean, the producer method must be either a business method of the EJB or a static method of the bean class.
The bean types of a producer method depend upon the method return type:
If the return type is an interface, the unrestricted set of bean types contains the return type, all
interfaces it extends directly or indirectly and java.lang.Object.
If a return type is primitive or is a Java array type, the unrestricted set of bean types contains
exactly two types: the method return type and java.lang.Object.
If the return type is a class, the unrestricted set of bean types contains the return type, every superclass and all interfaces it implements directly or indirectly.
Producer methods and fields may have a primitive bean type. For the purpose of resolving dependencies,
primitive types are considered to be identical to their corresponding wrapper types in
java.lang.
If the producer method has method parameters, the container will look for a bean that satisfies the type and qualifiers of each parameter and pass it to the method automatically—another form of dependency injection.
@Produces Set<Roles> getRoles(User user) {
return user.getRoles();
}
We'll talk much more about producer methods in Chapter 8, Producer methods.
A producer field is a simpler alternative to a producer method. A producer field is
declared by annotating a field of a bean class with the @Produces annotation—the
same annotation used for producer methods.
public class Shop {
@Produces PaymentProcessor paymentProcessor = ....;
@Produces @Catalog List<Product> products = ....;
}
The rules for determining the bean types of a producer field parallel the rules for producer methods.
A producer field is really just a shortcut that lets us avoid writing a useless getter method. However, in addition to convenience, producer fields serve a specific purpose as an adaptor for Java EE component environment injection, but to learn more about that, you'll have to wait until Chapter 14, Java EE component environment resources. Because we can't wait to get to work on some examples.
Let's illustrate these ideas with a full example. We're going to implement user login/logout for an application that uses JSF. First, we'll define a request-scoped bean to hold the username and password entered during login, with constraints defined using annotations from the Bean Validation specification:
@Named @RequestScoped
public class Credentials {
private String username;
private String password;
@NotNull @Length(min=3, max=25)
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
@NotNull @Length(min=6, max=20)
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
This bean is bound to the login prompt in the following JSF form:
<h:form>
<h:panelGrid columns="2" rendered="#{!login.loggedIn}">
<f:validateBean>
<h:outputLabel for="username">Username:</h:outputLabel>
<h:inputText id="username" value="#{credentials.username}"/>
<h:outputLabel for="password">Password:</h:outputLabel>
<h:inputSecret id="password" value="#{credentials.password}"/>
</f:validateBean>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
<h:commandButton value="Logout" action="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form>
Users are represented by a JPA entity:
@Entity
public class User {
private @NotNull @Length(min=3, max=25) @Id String username;
private @NotNull @Length(min=6, max=20) String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String setPassword(String password) { this.password = password; }
}
(Note that we're also going to need a persistence.xml file to configure the JPA persistence
unit containing User.)
The actual work is done by a session-scoped bean that maintains information about the currently logged-in user
and exposes the User entity to other beans:
@SessionScoped @Named
public class Login implements Serializable {
@Inject Credentials credentials;
@Inject @UserDatabase EntityManager userDatabase;
private User user;
public void login() {
List<User> results = userDatabase.createQuery(
"select u from User u where u.username = :username and u.password = :password")
.setParameter("username", credentials.getUsername())
.setParameter("password", credentials.getPassword())
.getResultList();
if (!results.isEmpty()) {
user = results.get(0);
}
else {
// perhaps add code here to report a failed login
}
}
public void logout() {
user = null;
}
public boolean isLoggedIn() {
return user != null;
}
@Produces @LoggedIn User getCurrentUser() {
return user;
}
}
@LoggedIn and @UserDatabase are custom qualifier annotations:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, PARAMETER, FIELD})
public @interface LoggedIn {}
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, PARAMETER, FIELD})
public @interface UserDatabase {}
We need an adaptor bean to expose our typesafe EntityManager:
class UserDatabaseProducer {
@Produces @UserDatabase @PersistenceContext
static EntityManager userDatabase;
}
Now DocumentEditor, or any other bean, can easily inject the current user:
public class DocumentEditor {
@Inject Document document;
@Inject @LoggedIn User currentUser;
@Inject @DocumentDatabase EntityManager docDatabase;
public void save() {
document.setCreatedBy(currentUser);
docDatabase.persist(document);
}
}
Or we can reference the current user in a JSF view:
<h:panelGroup rendered="#{login.loggedIn}">
signed in as #{currentUser.username}
</h:panelGroup>
Hopefully, this example gave you a taste of the CDI programming model. In the next chapter, we'll explore dependency injection in greater depth.
One of the most significant features of CDI—certainly the most recognized—is dependency injection; excuse me, typesafe dependency injection.
The @Inject annotation lets us define an injection point that is injected during bean
instantiation. Injection can occur via three different mechanisms.
Bean constructor parameter injection:
public class Checkout {
private final ShoppingCart cart;
@Inject
public Checkout(ShoppingCart cart) {
this.cart = cart;
}
}
A bean can only have one injectable constructor.
Initializer method parameter injection:
public class Checkout {
private ShoppingCart cart;
@Inject
void setShoppingCart(ShoppingCart cart) {
this.cart = cart;
}
}
A bean can have multiple initializer methods. If the bean is a session bean, the initializer method is not required to be a business method of the session bean.
And direct field injection:
public class Checkout {
private @Inject ShoppingCart cart;
}
Getter and setter methods are not required for field injection to work (unlike with JSF managed beans).
Dependency injection always occurs when the bean instance is first instantiated by the container. Simplifying just a little, things happen in this order:
First, the container calls the bean constructor (the default constructor or the one annotated
@Inject), to obtain an instance of the bean.
Next, the container initializes the values of all injected fields of the bean.
Next, the container calls all initializer methods of bean (the call order is not portable, don't rely on it).
Finally, the @PostConstruct method, if any, is called.
(The only complication is that the container might call initializer methods declared by a superclass before initializing injected fields declared by a subclass.)
One major advantage of constructor injection is that it allows the bean to be immutable.
CDI also supports parameter injection for some other methods that are invoked by the container. For instance, parameter injection is supported for producer methods:
@Produces Checkout createCheckout(ShoppingCart cart) {
return new Checkout(cart);
}
This is a case where the @Inject annotation is not required at the
injection point. The same is true for observer methods (which we'll meet in Chapter 11, Events) and
disposer methods.
The CDI specification defines a procedure, called typesafe resolution, that the container follows when identifying the bean to inject to an injection point. This algorithm looks complex at first, but once you understand it, it's really quite intuitive. Typesafe resolution is performed at system initialization time, which means that the container will inform the developer immediately if a bean's dependencies cannot be satisfied.
The purpose of this algorithm is to allow multiple beans to implement the same bean type and either:
allow the client to select which implementation it requires using a qualifier or
allow the application deployer to select which implementation is appropriate for a particular deployment, without changes to the client, by enabling or disabling an alternative, or
allow the beans to be isolated into separate modules.
Obviously, if you have exactly one bean of a given type, and an injection point with that same type, then bean A is going to go into slot A. That's the simplest possible scenario. When you first start your application, you'll likely have lots of those.
But then, things start to get complicated. Let's explore how the container determines which bean to inject in more advanced cases. We'll start by taking a closer look at qualifiers.
If we have more than one bean that implements a particular bean type, the injection point can specify exactly
which bean should be injected using a qualifier annotation. For example, there might be two implementations of
PaymentProcessor:
@Synchronous
public class SynchronousPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
@Asynchronous
public class AsynchronousPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
Where @Synchronous and @Asynchronous are qualifier annotations:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Synchronous {}
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Asynchronous {}
A client bean developer uses the qualifier annotation to specify exactly which bean should be injected.
Using field injection:
@Inject @Synchronous PaymentProcessor syncPaymentProcessor;
@Inject @Asynchronous PaymentProcessor asyncPaymentProcessor;
Using initializer method injection:
@Inject
public void setPaymentProcessors(@Synchronous PaymentProcessor syncPaymentProcessor,
@Asynchronous PaymentProcessor asyncPaymentProcessor) {
this.syncPaymentProcessor = syncPaymentProcessor;
this.asyncPaymentProcessor = asyncPaymentProcessor;
}
Using constructor injection:
@Inject
public Checkout(@Synchronous PaymentProcessor syncPaymentProcessor,
@Asynchronous PaymentProcessor asyncPaymentProcessor) {
this.syncPaymentProcessor = syncPaymentProcessor;
this.asyncPaymentProcessor = asyncPaymentProcessor;
}
Qualifier annotations can also qualify method arguments of producer, disposer and observer methods. Combining qualified arguments with producer methods is a good way to have an implementation of a bean type selected at runtime based on the state of the system:
@Produces
PaymentProcessor getPaymentProcessor(@Synchronous PaymentProcessor syncPaymentProcessor,
@Asynchronous PaymentProcessor asyncPaymentProcessor) {
return isSynchronous() ? syncPaymentProcessor : asyncPaymentProcessor;
}
If an injected field or a parameter of a bean constructor or initializer method is not explicitly annotated
with a qualifier, the default qualifier, @Default, is assumed.
Now, you may be thinking, "What's the different between using a qualifier and just specifying the
exact implementation class you want?" It's important to understand that a qualifier is like an
extension of the interface. It does not create a direct dependency to any particular implementation. There
may be multiple alterative implementations of @Asynchronous PaymentProcessor!
Whenever a bean or injection point does not explicitly declare a qualifier, the container assumes the
qualifier @Default. From time to time, you'll need to decare an injection point without
specifying a qualifier. There's a qualifier for that too. All beans have the qualifier @Any.
Therefore, by explicitly specifying @Any at an injection point, you suppress the default
qualifier, without otherwise restricting the beans that are eligible for injection.
This is especially useful if you want to iterate over all beans with a certain bean type. For example:
@Inject
void initServices(@Any Instance<Service> services) {
for (Service service: services) {
service.init();
}
}
Java annotations can have members. We can use annotation members to further discriminate a qualifier. This prevents a potential explosion of new annotations. For example, instead of creating several qualifiers representing different payment methods, we could aggregate them into a single annotation with a member:
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface PayBy {
PaymentMethod value();
}
Then we select one of the possible member values when appling the qualifier:
private @Inject @PayBy(CHECK) PaymentProcessor checkPayment;
We can force the container to ignore a member of a qualifier type by annotating the member
@Nonbinding.
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface PayBy {
PaymentMethod value();
@Nonbinding String comment() default "";
}
An injection point may specify multiple qualifiers:
@Inject @Synchronous @Reliable PaymentProcessor syncPaymentProcessor;
Then only a bean which has both qualifier annotations would be eligible for injection.
@Synchronous @Reliable
public class SynchronousReliablePaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
Alternatives are beans whose implementation is specific to a particular client module or deployment
scenario. This alternative defines a mock implementation of both @Synchronous PaymentProcessor
and @Asynchronous PaymentProcessor, all in one:
@Alternative @Synchronous @Asynchronous
public class MockPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}
By default, @Alternative beans are disabled. We need to enable an
alternative in the beans.xml descriptor of a bean archive to make it available for
instantiation and injection. This activation only applies to the beans in that archive.
<beans
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>org.mycompany.mock.MockPaymentProcessor</class>
</alternatives>
</beans>
When an ambiguous dependency exists at an injection point, the container attempts to resolve the ambiguity by looking for an enabled alternative among the beans that could be injected. If there is exactly one enabled alternative, that's the bean that will be injected.
The typesafe resolution algorithm fails when, after considering the qualifier annotations on all beans that
implement the bean type of an injection point and filtering out disabled beans (@Alternative
beans which are not explicitly enabled), the container is unable to identify exactly one bean to inject. The
container will abort deployment, informing us of the unsatisfied or ambiguous dependency.
During the course of your development, you're going to encounter this situation. Let's learn how to resolve it.
To fix an unsatisfied dependency, either:
create a bean which implements the bean type and has all the qualifier types of the injection point,
make sure that the bean you already have is in the classpath of the module with the injection point, or
explicitly enable an @Alternative bean that implements the bean type and has the
appropriate qualifier types, using beans.xml.
To fix an ambiguous dependency, either:
introduce a qualifier to distinguish between the two implementations of the bean type,
disable one of the beans by annotating it @Alternative,
move one of the implementations to a module that is not in the classpath of the module with the injection point, or
disable one of two @Alternative beans that are trying to occupy the same space,
using beans.xml.
See this FAQ for step-by-step instructions for how to resolve an ambigous resolution exception between a raw bean type and a producer method that returns the same bean type.
Just remember: "There can be only one."
On the other hand, if you really do have an optional or multivalued injection point, you should change
the type of your injection point to Instance, as we'll see in Section 4.10, “Obtaining a contextual instance by programmatic lookup”.
Now there's one more issue you need to be aware of when using the dependency injection service.
Clients of an injected bean do not usually hold a direct reference to a bean instance, unless the bean is
a dependent object (scope @Dependent).
Imagine that a bean bound to the application scope held a direct reference to a bean bound to the request scope. The application-scoped bean is shared between many different requests. However, each request should see a different instance of the request scoped bean—the current one!
Now imagine that a bean bound to the session scope holds a direct reference to a bean bound to the application scope. From time to time, the session context is serialized to disk in order to use memory more efficiently. However, the application scoped bean instance should not be serialized along with the session scoped bean! It can get that reference any time. No need to hoard it!
Therefore, unless a bean has the default scope @Dependent, the container must indirect all
injected references to the bean through a proxy object. This client proxy is responsible
for ensuring that the bean instance that receives a method invocation is the instance that is associated with
the current context. The client proxy also allows beans bound to contexts such as the session context to be
serialized to disk without recursively serializing other injected beans.
Unfortunately, due to limitations of the Java language, some Java types cannot be proxied by the container.
If an injection point declared with one of these types resolves to a bean with any scope other than
@Dependent, the container will abort deployment, informing us of the problem.
The following Java types cannot be proxied by the container:
classes which don't have a non-private constructor with no parameters, and
classes which are declared final or have a final method,
arrays and primitive types.
It's usually very easy to fix an unproxyable dependency problem. If an injection point of type
X results in an unproxyable dependency, simply:
add a constructor with no parameters to X,
change the type of the injection point to Instance<X>,
introduce an interface Y, implemented by the injected bean, and change
the type of the injection point to Y, or
if all else fails, change the scope of the injected bean to @Dependent.
A future release of Weld will likely support a non-standard workaround for this limitation, using non-portable JVM APIs:
Sun, IcedTea, Mac: Unsafe.allocateInstance() (The most efficient)
IBM, JRockit: ReflectionFactory.newConstructorForSerialization()
But we didn't get around to implementing this yet.
In certain situations, injection is not the most convenient way to obtain a contextual reference. For example, it may not be used when:
the bean type or qualifiers vary dynamically at runtime, or
depending upon the deployment, there may be no bean which satisfies the type and qualifiers, or
we would like to iterate over all beans of a certain type.
In these situations, the application may obtain an instance of the interface Instance,
parameterized for the bean type, by injection:
@Inject Instance<PaymentProcessor> paymentProcessorSource;
The get() method of Instance produces a contextual instance of the bean.
PaymentProcessor p = paymentProcessorSource.get();
Qualifiers can be specified in one of two ways:
by annotating the Instance injection point, or
by passing qualifiers to the select() of Event.
Specifying the qualifiers at the injection point is much, much easier:
@Inject @Asynchronous Instance<PaymentProcessor> paymentProcessorSource;
Now, the PaymentProcessor returned by get() will have the qualifier
@Asynchronous.
Alternatively, we can specify the qualifier dynamically. First, we add the @Any qualifier to
the injection point, to suppress the default qualifier. (All beans have the qualifier @Any.)
@Inject @Any Instance<PaymentProcessor> paymentProcessorSource;
Next, we need to obtain an instance of our qualifier type. Since annotatons are interfaces, we can't just write
new Asynchronous(). It's also quite tedious to create a concrete implementation of an annotation
type from scratch. Instead, CDI lets us obtain a qualifier instance by subclassing the helper class
AnnotationLiteral.
abstract class AsynchronousQualifier
extends AnnotationLiteral<Asynchronous> implements Asynchronous {}
In some cases, we can use an anonymous class:
PaymentProcessor p = paymentProcessorSource
.select(new AnnotationLiteral<Asynchronous>() {});
We can't use an anonymous class to implement a qualifier type with members.
Now, finally, we can pass the qualifier to the select() method of Instance.
Annotation qualifier = synchronously ?
new SynchronousQualifier() : new AsynchronousQualifier();
PaymentProcessor p = anyPaymentProcessor.select(qualifier).get().process(payment);There are certain kinds of dependent objects (beans with scope @Dependent)
that need to know something about the object or injection point into which they are injected in order
to be able to do what they do. For example:
The log category for a Logger depends upon the class of the object
that owns it.
Injection of a HTTP parameter or header value depends upon what parameter or header name was specified at the injection point.
Injection of the result of an EL expression evaluation depends upon the expression that was specified at the injection point.
A bean with scope @Dependent may inject an instance of
InjectionPoint and access metadata relating to the injection point to which
it belongs.
Let's look at an example. The following code is verbose, and vulnerable to refactoring problems:
Logger log = Logger.getLogger(MyClass.class.getName());
This clever little producer method lets you inject a JDK Logger without
explicitly specifying the log category:
class LogFactory {
@Produces Logger createLogger(InjectionPoint injectionPoint) {
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
}
We can now write:
@Inject Logger log;
Not convinced? Then here's a second example. To inject HTTP parameters, we need to define a qualifier type:
@BindingType
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface HttpParam {
@Nonbinding public String value();
}
We would use this qualifier type at injection points as follows:
@HttpParam("username") String username;
@HttpParam("password") String password;
The following producer method does the work:
class HttpParams
@Produces @HttpParam("")
String getParamValue(ServletRequest request, InjectionPoint ip) {
return request.getParameter(ip.getAnnotated().getAnnotation(HttpParam.class).value());
}
}
(Note that the value() member of the HttpParam
annotation is ignored by the container since it is annotated @Nonbinding.)
The container provides a built-in bean that implements the InjectionPoint
interface:
public interface InjectionPoint {
public Type getType();
public Set<Annotation> getQualifiers();
public Bean<?> getBean();
public Member getMember();
public Annotated getAnnotated();
public boolean isDelegate();
public boolean isTransient();
}
So far, we've seen a few examples of scope type annotations. The scope of a bean determines the lifecycle of instances of the bean. The scope also determines which clients refer to which instances of the bean. According to the CDI specification, a scope determines:
When a new instance of any bean with that scope is created
When an existing instance of any bean with that scope is destroyed
Which injected references refer to any instance of a bean with that scope
For example, if we have a session-scoped bean, CurrentUser, all beans that are called in the
context of the same HttpSession will see the same instance of CurrentUser.
This instance will be automatically created the first time a CurrentUser is needed in that
session, and automatically destroyed when the session ends.
JPA entities aren't a great fit for this model. Entities have their whole own lifecycle and identity model
which just doesn't map naturally to the model used in CDI. Therefore, we recommend against treating entities
as CDI beans. You're certainly going to run into problems if you try to give an entity a scope other than
the default scope @Dependent. The client proxy will get in the way if you try to pass
an injected instance to the JPA EntityManager.
CDI features an extensible context model. It's possible to define new scopes by creating a new scope type annotation:
@ScopeType
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface ClusterScoped {}
Of course, that's the easy part of the job. For this scope type to be useful, we will also need to define a
Context object that implements the scope! Implementing a Context is
usually a very technical task, intended for framework development only. You can expect an implementation of the
business scope, for instance, in a future version of Seam.
We can apply a scope type annotation to a bean implementation class to specify the scope of the bean:
@ClusterScoped
public class SecondLevelCache { ... }
Usually, you'll use one of CDI's built-in scopes.
CDI defines four built-in scopes:
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
For a web application that uses CDI:
any servlet request has access to active request, session and application scopes, and, additionally
any JSF request has access to an active conversation scope.
A CDI extension can implement support for the conversation scope in other web frameworks.
The request and application scopes are also active:
during invocations of EJB remote methods,
during invocations of EJB asynchronous methods,
during EJB timeouts,
during message delivery to a message-driven bean,
during message delivery to a MessageListener, and
during web service invocations.
If the application tries to invoke a bean with a scope that does not have an active context, a
ContextNotActiveException is thrown by the container at runtime.
Managed beans with scope @SessionScoped or @ConversationScoped must be
serializable, since the container passivates the HTTP session from time to time.
Three of the four built-in scopes should be extremely familiar to every Java EE developer, so let's not waste time discussing them here. One of the scopes, however, is new.
The conversation scope is a bit like the traditional session scope in that it holds state associated with a user of the system, and spans multiple requests to the server. However, unlike the session scope, the conversation scope:
is demarcated explicitly by the application, and
holds state associated with a particular web browser tab in a JSF application (browsers tend to share domain cookies, and hence the session cookie, between tabs, so this is not the case for the session scope).
A conversation represents a task—a unit of work from the point of view of the user. The conversation context holds state associated with what the user is currently working on. If the user is doing multiple things at the same time, there are multiple conversations.
The conversation context is active during any JSF request. Most conversations are destroyed at the end of the request. If a conversation should hold state across multiple requests, it must be explicitly promoted to a long-running conversation.
CDI provides a built-in bean for controlling the lifecycle of conversations in a JSF application. This bean may be obtained by injection:
@Inject Conversation conversation;
To promote the conversation associated with the current request to a long-running conversation, call the
begin() method from application code. To schedule the current long-running conversation
context for destruction at the end of the current request, call end().
In the following example, a conversation-scoped bean controls the conversation with which it is associated:
@ConversationScoped @Stateful
public class OrderBuilder {
private Order order;
private @Inject Conversation conversation;
private @PersistenceContext(type = EXTENDED) EntityManager em;
@Produces public Order getOrder() {
return order;
}
public Order createOrder() {
order = new Order();
conversation.begin();
return order;
}
public void addLineItem(Product product, int quantity) {
order.add(new LineItem(product, quantity));
}
public void saveOrder(Order order) {
em.persist(order);
conversation.end();
}
@Remove
public void destroy() {}
}
This bean is able to control its own lifecycle through use of the Conversation API. But
some other beans have a lifecycle which depends completely upon another object.
The conversation context automatically propagates with any JSF faces request (JSF form submission) or redirect. It does not automatically propagate with non-faces requests, for example, navigation via a link.
We can force the conversation to propagate with a non-faces request by including the unique identifier of
the conversation as a request parameter. The CDI specification reserves the request parameter named
cid for this use. The unique identifier of the conversation may be obtained from the
Conversation object, which has the EL bean name conversation.
Therefore, the following link propagates the conversation:
<a href="/addProduct.jsp?cid=#{conversation.id}">Add Product</a>
It's probably better to use one of the link components in JSF 2:
<h:link outcome="/addProduct.xhtml value="Add Product">
<f:param name="cid" value="#{conversation.id}"/>
</h:link>
The conversation context propagates across redirects, making it very easy to implement the common POST-then-redirect pattern, without resort to fragile constructs such as a "flash" object. The container automatically adds the conversation id to the redirect URL as a request parameter.
The container is permitted to destroy a conversation and all state held in its context at any time in order to conserve resources. A CDI implementation will normally do this on the basis of some kind of timeout—though this is not required by the specification. The timeout is the period of inactivity before the conversation is destroyed (as opposed to the amount of time the conversation is active).
The Conversation object provides a method to set the timeout. This is a hint to the
container, which is free to ignore the setting.
conversation.setTimeout(timeoutInMillis);
In addition to the four built-in scopes, CDI also supports two pseudo-scopes. The first
is the singleton pseudo-scope, which we specify using the annotation @Singleton.
Unlike the other scopes, which belong to the package javax.enterprise.context, the
@Singleton annotation is defined in the package javax.inject.
You can guess what "singleton" means here. It means a bean that is instantiated once. Unfortunately, there's
a little problem with this pseudo-scope. Beans with scope @Singleton don't have a proxy
object. Clients hold a direct reference to the singleton instance. So we need to consider the case of a client
that can be serialized, for example, any bean with scope @SessionScoped or
@ConversationScoped, any dependent object of a bean with scope @SessionScoped
or @ConversationScoped, or any stateful session bean.
Now, if the singleton instance is a simple, immutable, serializable object like a string, a number or a date, we probably don't mind too much if it gets duplicated via serialization. However, that makes it no stop being a true singleton, and we may as well have just declared it with the default scope.
There are several ways to ensure that the singleton bean remains a singleton when its client gets serialized:
have the singleton bean implement writeResolve() and readReplace()
(as defined by the Java serialization specification),
make sure the client keeps only a transient reference to the singleton bean, or
give the client a reference of type Instance<X> where X is the
bean type of the singleton bean.
A fourth, better solution is to instead use @ApplicationScoped, allowing the container to
proxy the bean, and take care of serialization problems automatically.
Finally, CDI features the so-called dependent pseudo-scope. This is the default scope for a bean which does not explicitly declare a scope type.
For example, this bean has the scope type @Dependent:
public class Calculator { ... }
An instance of a dependent bean is never shared between different clients or different injection points. It is strictly a dependent object of some other object. It is instantiated when the object it belongs to is created, and destroyed when the object it belongs to is destroyed.
If a Unified EL expression refers to a dependent bean by EL name, an instance of the bean is instantiated every time the expression is evaluated. The instance is not reused during any other expression evaluation.
If you need to access a bean directly by EL name in a JSF page, you probably need to give it a scope other
than @Dependent. Otherwise, any value that gets set to the bean by a JSF input will be
lost immediately. That's why CDI features the @Model stereotype; it lets you give a bean
a name, and set its scope to @RequestScoped in one stroke. If you need to access a bean
that really has to have the scope @Dependent from a JSF page,
inject it into a different bean, and expose it to EL via a getter method.
Beans with scope @Dependent don't need a proxy object. The client holds a direct reference
to its instance.
CDI makes it easy to obtain a dependent instance of a bean, even if the bean is already declared as a bean with some other scope type.
The built-in qualifier @New allows us to obtain a dependent object of a specified class.
@Inject @New Calculator calculator;
The class must be a valid managed bean or session bean, but need not be an enabled bean.
This works even if Calculator is already declared with a different
scope type, for example:
@ConversationScoped
public class Calculator { ... }
So the following injected attributes each get a different instance of Calculator:
public class PaymentCalc {
@Inject Calculator calculator;
@Inject @New Calculator newCalculator;
}
The calculator field has a conversation-scoped instance of Calculator
injected. The newCalculator field has a new instance of Calculator
injected, with a lifecycle that is bound to the owning PaymentCalc.
This feature is particularly useful with producer methods, as we'll see in the next chapter.
Weld, the JSR-299 Reference Implementation (RI), is being developed as part of the Seam project. You can download the latest community release of Weld from the download page. Information about the Weld source code repository and instructions about how to obtain and build the source can be found on the same page.
Weld provides a complete SPI allowing Java EE containers such as JBoss AS and GlassFish to use Weld as their built-in CDI implementation. Weld also runs in servlet engines like Tomcat and Jetty, or even in a plain Java SE environment.
Weld comes with an extensive library of examples, which are a great starting point from which to learn CDI.
Weld comes with two starter example applications, in addition to more specialized examples. The first,
weld-numberguess, is a web (war) example containing only non-transactional managed beans.
This example can be run on a wide range of servers, including JBoss AS, GlassFish, Apache Tomcat, Jetty, Google
App Engine, and any compliant Java EE 6 container. The second example, weld-translator, is
an enterprise (ear) example that contains session beans. This example must be run on JBoss AS 6.0, Glassfish 3.0
or any compliant Java EE 6 container.
Both examples use JSF 2.0 as the web framework and, as such, can be found in the examples/jsf
directory of the Weld distribution.
To run the examples with the provided build scripts, you'll need the following:
the latest release of Weld, which contains the examples
Ant 1.7.0, to build and deploy the examples
a supported runtime environment (minimum versions shown)
JBoss AS 6.0.0,
GlassFish 3.0,
Apache Tomcat 6.0.x (war example only), or
Jetty 6.1.x (war example only)
(optionally) Maven 2.x, to run the examples in an embedded servlet container
You'll need a full install of Ant 1.7.0. Some linux distributions only supply a partial installation of Ant which cause the build to fail. If you encounter problems, verify that ant-nodeps.jar is on the classpath.
In the next few sections, you'll be using the Ant command (ant) to invoke the Ant build script
in each example to compile, assemble and deploy the example to JBoss AS and, for the war example, Apache Tomcat.
You can also deploy the generated artifact (war or ear) to any other container that supports Java EE 6, such as
GlassFish 3.
If you have Maven installed, you can use the Maven command (mvn) to compile and assemble the
standalone artifact (war or ear) and, for the war example, run it in an embedded container.
The sections below cover the steps for deploying with both Ant and Maven in detail. Let's start with JBoss AS.
To deploy the examples to JBoss AS, you'll need JBoss AS 6.0.0 or above. If a release of the JBoss AS 6.0 line isn't yet available, you can download a nightly snapshot. The reason JBoss AS 6.0.0 or above is required is because it's the first release that has both CDI and Bean Validation support built-in, making it close enough to Java EE 6 to run the examples. The good news is that there are no additional modifications you have to make to the server. It's ready to go!
After you have downloaded JBoss AS, extract it. (We recommended renaming the folder to include the
as qualifier so it's clear that it's the application server). You can move the extracted
folder anywhere you like. Wherever it lays to rest, that's what we'll call the JBoss AS installation
directory, or JBOSS_HOME.
$> unzip jboss-6.0.*.zip $> mv jboss-6.0.*/ jboss-as-6.0
In order for the build scripts to know where to deploy the example, you have to tell them where to find your
JBoss AS installation (i.e., JBOSS_HOME). Create a new file named local.build.properties
in the examples directory of the Weld distribution and assign the path of your JBoss AS installation to the
property key jboss.home, as follows:
jboss.home=/path/to/jboss-as-6.0
You're now ready to deploy your first example!
Switch to the examples/jsf/numberguess directory and execute the Ant
deploy target:
$> cd examples/jsf/numberguess $> ant deploy
If you haven't already, start JBoss AS. You can either start JBoss AS from a Linux shell:
$> cd /path/to/jboss-as-6.0 $> ./bin/run.sh
a Windows command window:
$> cd c:\path\to\jboss-as-6.0\bin $> run
or you can start the server using an IDE, like Eclipse.
If you are using Eclipse, you should seriously consider installing the JBoss Tools add-ons, which include a wide variety of tooling for JSR-299 and Java EE development, as well as an enhanced JBoss AS server view.
Wait a few seconds for the application to deploy (or the application server to start) and see if you can determine the most efficient approach to pinpoint the random number at the local URL http://localhost:8080/weld-numberguess.
The Ant build script includes additional targets for JBoss AS to deploy and undeploy the archive in either exploded or packaged format and to tidy things up.
ant restart - deploy the example in exploded format to JBoss AS
ant explode - update an exploded example, without restarting the deployment
ant deploy - deploy the example in compressed jar format to JBoss AS
ant undeploy - remove the example from JBoss AS
ant clean - clean the example
The second starter example, weld-translator, will translate your text into Latin. (Well,
not really, but the stub is there for you to implement, at least. Good luck!) To try it out, switch to the
translator example directory and execute the deploy target:
$> cd examples/jsf/translator $> ant deploy
The translator uses session beans, which are packaged in an EJB module within an ear. Java EE 6 will allow session beans to be deployed in war modules, but that's a topic for a later chapter.
Again, wait a few seconds for the application to deploy (if you're really bored, read the log messages), and visit http://localhost:8080/weld-translator to begin pseudo-translating.
Deploying to GlassFish should be easy, right? After all, it's the Java EE 6 reference implementation. Since it's the Java EE 6 reference implementation, that means it also bundles the JSR-299 reference implementation, Weld! So yes, it's very easy.
To deploy the examples to GlassFish, you'll need the final GlassFish V3 release (the preview release won't do). If the final
release isn't yet available, you can download a promoted build in the meantime. Select the b69
preview release or above that ends in either -unix.sh or -windows.exe
depending on your platform. After the download is complete, execute the installer. On Linux/Unix, you'll need
to first make the script executable.
$> chmod 755 glassfish-v3-b69-unix.sh $> ./glassfish-v3-b69-unix.sh
On Windows you can just click on the executable. Follow the instructions in the installer. It will create a
single domain named domain1. You'll use that domain to deploy the example. We recommend that
you choose 7070 as the main HTTP port to avoid conflicts with a running instance of JBoss AS
(or Apache Tomcat).
If you've deployed either of the starter examples, weld-numberguess or
weld-translator, to JBoss AS, then you already have the deployable artifact you need.
If not, switch to either of the two directories and build it.
$> cd examples/jsf/numberguess (or examples/jsf/translator) $> ant package
The deployable archive for the weld-numberguess, named weld-numberguess.war,
ends up in the example's target directory. The archive for the weld-translator
example, named weld-translator.ear, ends up in the example's ear/target directory.
All you need to do now is deploy them to GlassFish.
You deploy applications to GlassFish using the GlassFish Admin
Console. To get the Admin Console running, you need to start a GlassFish domain, in our case
domain1. Switch to the bin folder in the directory where you
installed GlassFish and execute the following command:
$> asadmin start-domain domain1
After a few seconds you can visit the Admin Console in the browser at the URL http://localhost:4848. In the tree on the left-hand side of the page, click on "Applications", then click on the "Deploy..." button under the heading "Applications" and select the deployable artifact for either of the two examples. The deployer should recognize that you have selected a Java EE artifact and allow you to start it. You can see the examples running at either http://localhost:7070/weld-numberguess or http://localhost:7070/weld-translator, depending on which example you deployed.
The reason the same artifact can be deployed to both JBoss AS and GlassFish, without any modifications, is because all of the features being used are part of the standard platform. And what a capable platform it has become!
Servlet containers are not required to support Java EE services like CDI. However, you can use CDI in a servlet container like Tomcat by embedding a standalone CDI implementation such as Weld.
Weld comes with a servlet listener which bootstraps the CDI environment, registers the BeanManager
in JNDI and provides injection into servlets. Basically, it emulates some of the work done by the Java EE
container. (But you don't get enterprise features such as session beans and container-managed transactions.)
Let's give the Weld servlet extension a spin on Apache Tomcat. First, you'll need to download Tomcat 6.0.18 or later from tomcat.apache.org and extract it.
$> unzip apache-tomcat-6.0.18.zip
You have two choices for how you can deploy the application to Tomcat. You can deploy it by pushing the artifact to the hot deploy directory using Ant or you can deploy to the server across HTTP using a Maven plugin. The Ant approach doesn't require that you have Maven installed, so we'll start there. If you want to use Maven, you can just skip ahead.
In order for Ant to push the artifact to the Tomcat hot deploy directory, it needs to know where the Tomcat
installation is located. Again, we need to set a property in the local.build.properties
file in the examples directory of the Weld distribution. If you haven't yet created this file, do so now.
Then assign the path of your Tomcat installation to the property key tomcat.home.
tomcat.home=/path/to/apache-tomcat-6
Now you're ready to deploy the numberguess example to Tomcat!
Change to the examples/jsf/numberguess directory again and run the Ant deploy
target for Tomcat:
$> cd examples/jsf/numberguess $> ant tomcat.deploy
The Ant build script includes additional targets for Tomcat to deploy and undeploy the archive in either exploded or packaged format. They are the same target names used for JBoss AS, prefixed with "tomcat.".
ant tomcat.restart - deploy the example in exploded format to Tomcat
ant tomcat.explode - update an exploded example, without restarting the deployment
ant tomcat.deploy - deploy the example in compressed jar format to Tomcat
ant tomcat.undeploy - remove the example from Tomcat
If you haven't already, start Tomcat. You can either start Tomcat from a Linux shell:
$> cd /path/to/apache-tomcat-6 $> ./bin/start.sh
a Windows command window:
$> cd c:\path\to\apache-tomcat-6\bin $> start
or you can start the server using an IDE, like Eclipse.
Wait a few seconds for the application to deploy (or the application server to start) and see if you can figure out the most efficient approach to pinpoint the random number at the local URL http://localhost:8080/weld-numberguess!
You can also deploy the application to Tomcat using Maven. This section is a bit more advanced, so skip it unless you're itching to use Maven natively. Of course, you'll first need to make sure that you have Maven installed on your path, similar to how you setup Ant.
The Maven plugin communicates with Tomcat over HTTP, so it doesn't care where you have installed Tomcat.
However, the plugin configuration assumes you are running Tomcat in its default configuration, with a hostname
of localhost and port 8080. The readme.txt file in the example directory
has information about how to modify the Maven settings to accommodate a different setup.
To allow Maven to communicate with Tomcat over HTTP, edit the conf/tomcat-users.xml file in
your Tomcat installation and add the following line:
<user username="admin" password="" roles="manager"/>
Restart Tomcat. You can now deploy the application to Tomcat with Maven using this command:
$> mvn compile war:exploded tomcat:exploded -Ptomcat
Once the application is deployed, you can redeploy it using this command:
$> mvn tomcat:redeploy -Ptomcat
The -Ptomcat argument activates the tomcat profile defined in the Maven POM
(pom.xml). Among other things, this profile activates the Tomcat plugin.
Rather than shipping the container off to a standalone Tomcat installation, you can also execute the application in an embedded Tomcat 6 container:
$> mvn war:inplace tomcat:run -Ptomcat
The advantage of using the embedded server is that changes to assets in src/main/webapp take effect
immediately. If a change to a webapp configuration file is made, the application may automatically redeploy
(depending on the plugin configuration). If you make a change to a classpath resource, you need to execute a
build:
$> mvn compile war:inplace -Ptomcat
There are several other Maven goals that you can use if you are hacking on the example, which are documented in
the example's readme.txt file.
Support for Jetty in the examples is a more recent addition. Since Jetty is traditionally used with Maven,
there are no Ant targets. You must invoke the Maven build directly to deploy the examples to Jetty out of the
box. Also, only the weld-numberguess example is configured for Jetty support at the time of
writing.
If you've read through the entire Tomcat section, then you're all ready to go. The Maven build parallels the embedded Tomcat deployment. If not, don't worry. We'll still go over everything that you need to know again in this section.
The Maven POM (pom.xml) includes a profile named jetty that activates the
Maven Jetty plugin, which you can use
to start Jetty in embedded mode and deploy the application in place. You don't need anything else installed
except to have the Maven command (mvn) on your path. The rest will be downloaded from the
internet when the
build is run.
To run the weld-numberguess example on Jetty, switch to the example directory and execute
the inplace goal of the Maven war plugin followed by the run goal of
the Maven Jetty plugin with the jetty profile enabled, as follows:
$> cd examples/jsf/numberguess $> mvn war:inplace jetty:run -Pjetty
The log output of Jetty will be shown in the console. Once Jetty reports that the application has deployed, you
can access it at the following local URL: http://localhost:9090/weld-numberguess. The port is
defined in the Maven Jetty plugin configuration within the jetty profile.
Any changes to assets in src/main/webapp take effect immediately. If a change to a webapp
configuration file is made, the application may automatically redeploy. The redeploy behavior can be fined-tuned
in the plugin configuration. If you make a change to a classpath resource, you need to execute a build and the
inplace goal of the Maven war plugin, again with the jetty profile enabled.
$> mvn compile war:inplace -Pjetty
The war:inplace goal copies the compiled classes and jars inside src/main/webapp,
under WEB-INF/classes and WEB-INF/lib, respectively, mixing source and compiled
files. However, the build does work around these temporary files by excluding them from the packaged war and cleaning
them during the Maven clean phase.
You have two options if you want to run the example on Jetty from the IDE. You can either install the m2eclispe[link] plugin and run the goals as described above. Your other option is to start the Jetty container from a Java application.
First, initialize the Eclipse project:
$> mvn clean eclipse:clean eclipse:eclipse -Pjetty-ide
Next, assemble all the necessary resources under src/main/webapp:
$> mvn war:inplace -Pjetty-ide
Now, you are ready to run the server in Eclipse. Import the project into your Eclipse workspace using "Import
Existing Project into Workspace. Then, find the start class in src/jetty/java and run its
main method as a Java Application. Jetty will launch. You can view the application at the following local URL: http://localhost:8080. Pay particular attention to the port in the URL and
the lack of a trailing context path.
Now that you have gotten the starter applications deployed on the server of your choice, you probably want to know a little bit about how they actually work.
It's time to pull the covers back and dive into the internals of Weld example applications. Let's start with the
simpler of the two examples, weld-numberguess.
In the numberguess application you get 10 attempts to guess a number between 1 and 100. After each attempt, you're told whether your guess was too high or too low.
The numberguess example is comprised of a number of beans, configuration files and Facelets (JSF) views, packaged as a war module. Let's start by examining the configuration files.
All the configuration files for this example are located in WEB-INF/, which can be found in
the src/main/webapp directory of the example. First, we have the JSF 2.0 version of
faces-config.xml. A standardized version of Facelets is the default view handler in JSF
2.0, so there's really nothing that we have to configure. Thus, the configuration consists of only the root
element.
<faces-config version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
</faces-config>
There's also an empty beans.xml file, which tells the container to look for beans in this
application and to activate the CDI services.
Finally, there's the familiar web.xml:
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>weld-jsf-numberguess-war</display-name>
ml_plain"> <description>Weld JSF numberguess example (war)</description>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
ml_plain"> </servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
ml_plain"> </servlet-mapping>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
ml_plain"> </context-param>
<session-config>
<session-timeout>10</session-timeout>
</session-config>
</web-app>
| Enable and initialize the JSF servlet |
|
Configure requests for URLs ending in |
|
Tell JSF that we will be giving our JSF views (Facelets templates) an
extension of |
| Configure a session timeout of 10 minutes |
This demo uses JSF 2 as the view framework, but you can use Weld with any servlet-based web framework, such as JSF 1.2 or Wicket.
Let's take a look at the main JSF view, src/main/webapp/home.xhtml.
<!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">
ml_plain">
<ui:composition template="/template.xhtml">
<ui:define name="content">
<h1>Guess a number...</h1>
ml_plain"> <h:form id="numberGuess">
<div style="color: red">
<h:messages id="messages" globalOnly="false"/>
<h:outputText id="Higher" value="Higher!"
rendered="#{game.number gt game.guess and game.guess ne 0}"/>
<h:outputText id="Lower" value="Lower!"
rendered="#{game.number lt game.guess and game.guess ne 0}"/>
</div>
ml_plain">
<div>
I'm thinking of a number between #{game.smallest} and #{game.biggest}.
You have #{game.remainingGuesses} guesses remaining.
</div>
<div>
ml_plain"> Your guess:
<h:inputText id="inputGuess" value="#{game.guess}"
ml_plain"> size="3" required="true" disabled="#{game.number eq game.guess}"
ml_plain"> validator="#{game.validateNumberRange}"/>
<h:commandButton id="guessButton" value="Guess"
action="#{game.check}" disabled="#{game.number eq game.guess}"/>
</div>
<div>
<h:commandButton id="restartButton" value="Reset" action="#{game.reset}" immediate="true"/>
</div>
</h:form>
</ui:define>
</ui:composition>
</html>
| Facelets is the built-in templating language for JSF. Here we are wrapping our page in a template which defines the layout. |
| There are a number of messages which can be sent to the user, "Higher!", "Lower!" and "Correct!" |
| As the user guesses, the range of numbers they can guess gets smaller - this sentence changes to make sure they know the number range of a valid guess. |
| This input field is bound to a bean property using a value expression. |
| A validator binding is used to make sure the user doesn't accidentally input a number outside of the range in which they can guess - if the validator wasn't here, the user might use up a guess on an out of bounds number. |
| And, of course, there must be a way for the user to send their guess to the server. Here we bind to an action method on the bean. |
The example exists of 4 classes, the first two of which are qualifiers. First, there is the
@Random qualifier, used for injecting a random number:
@Qualifier
@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
public @interface Random {}
There is also the @MaxNumber qualifier, used for
injecting the maximum number that can be injected:
@Qualifier
@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
public @interface MaxNumber {}
The application-scoped Generator class is responsible for creating the random number, via a
producer method. It also exposes the maximum possible number via a producer method:
@ApplicationScoped
public class Generator implements Serializable {
private java.util.Random random = new java.util.Random(System.currentTimeMillis());
private int maxNumber = 100;
java.util.Random getRandom() {
return random;
}
@Produces @Random int next() {
return getRandom().nextInt(maxNumber);
}
@Produces @MaxNumber int getMaxNumber() {
return maxNumber;
}
}
The Generator is application scoped, so we don't get a different random each time.
The package declaration and imports have been excluded from these listings. The complete listing is available in the example source code.
The final bean in the application is the session-scoped Game class. This is the primary
entry point of the application. It's responsible for setting up or resetting the game, capturing and validating
the user's guess and providing feedback to the user with a FacesMessage. We've used the
post-construct lifecycle method to initialize the game by retrieving a random number from the @Random
Instance<Integer> bean.
You'll notice that we've also added the @Named annotation to this class. This annotation is
only required when you want to make the bean accessible to a JSF view via EL (i.e., #{game}).
@Named
@SessionScoped
public class Game implements Serializable {
private int number;
private int guess;
private int smallest;
private int biggest;
private int remainingGuesses;
@Inject @MaxNumber private int maxNumber;
@Inject @Random Instance<Integer> randomNumber;
public Game() {}
public void check() {
if (guess > number) {
biggest = guess - 1;
}
else if (guess < number) {
smallest = guess + 1;
}
else if (guess == number) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
}
remainingGuesses--;
}
@PostConstruct
public void reset() {
this.smallest = 0;
this.guess = 0;
this.remainingGuesses = 10;
this.biggest = maxNumber;
this.number = randomNumber.get();
}
public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) {
if (remainingGuesses <= 0) {
FacesMessage message = new FacesMessage("No guesses left!");
context.addMessage(toValidate.getClientId(context), message);
((UIInput) toValidate).setValid(false);
return;
}
int input = (Integer) value;
if (input < smallest || input > biggest) {
((UIInput) toValidate).setValid(false);
FacesMessage message = new FacesMessage("Invalid guess");
context.addMessage(toValidate.getClientId(context), message);
}
}
public int getNumber() {
return number;
}
public int getGuess() {
return guess;
}
public void setGuess(int guess) {
this.guess = guess;
}
public int getSmallest() {
return smallest;
}
public int getBiggest() {
return biggest;
}
public int getRemainingGuesses() {
return remainingGuesses;
}
}
A couple of modifications must be made to the numberguess artifact in order to deploy it to Tomcat or Jetty.
First, Weld must be deployed as a Web Application library under WEB-INF/lib since the
servlet container does not provide the CDI services. For your convenience we provide a single jar suitable
for running Weld in any servlet container (including Jetty), weld-servlet.jar.
You must also include the jars for JSF, EL, and the common annotations
(jsr250-api.jar), all of which are provided by the Java EE platform (a Java EE
application server). Are you starting to appreciate why a Java EE platform is worth using?
Second, we need to explicitly specify the servlet listener in web.xml, again because the
container isn't doing this stuff for you. The servlet listener boots Weld and controls it's interaction with
requests.
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
When Weld boots, it places the javax.enterprise.inject.spi.BeanManager, the portable SPI
for obtaining bean instances, in the ServletContext under a variable name equal to the fully-qualified
interface name. You generally don't need to access this interface, but Weld makes use of it.
Weld includes a number of portable extensions for JSR-299, including an extension for Wicket, which allows you to inject beans into Wicket components and leverage the conversation context. In this section, we'll walk you through the Wicket version of the numberguess example.
You may want to review the Wicket documentation at http://wicket.apache.org/ before reading this section, if you aren't already familiar with the framework.
Wicket is another environment that relies on the Weld servlet extension. The use of Jetty is common in the Wicket community, and is thus chosen here as the runtime container. You've seen already that Jetty is perfectly capable of running CDI applications with Weld add-ons, and this environment is no different.
We'll also be using the Eclipse IDE in these examples. Instructions are provided later for running the example from the command line, but since you'll likely need to do more than just deploy examples, we'll get setup in this full development environment.
To use the Wicket example in Eclipse, you have one of two choices. You can either use a Maven plugin to generate a regular Eclipse Web project, or you can open the example natively using the m2eclipse plugin. Since the Weld source code relies so heavily on Maven, we encourage you to bite the bullet and adopt the m2eclipse plugin. Both approaches are described here for your convenience..
If you have m2eclipse installed, you can open any Maven project directly. From within Eclipse, select File -> Import... -> Maven Projects. Then, browse to the location of the Wicket numberguess example. You should see that Eclipse recognizes the existence of a Maven project.

This will create a project in your workspace called weld-wicket-numberguess.
You'll notice after importing, the project has a build error. That's because we need to enable a Maven
profile. Right-click on the project and select Properties, then select the
Maven tab in the window that appears. In the form field labeled "Active Maven
Profiles (comma separated):", type jetty. That will enable some extra dependencies
that allow the project to compile. Additionally, uncheck the box labeled "Skip Maven
compile plugin when processing resources (recommended)". That solves an incompatiblity between the
m2eclipse plugin and the Maven enforcer plugin that we use for the Weld project. Now, you're ready to
develop!
Be sure to uncheck the box "Skip Maven compile plugin when processing resources (recommended)" in the Maven properties screen or else the example might not run in Eclipse because beans.xml will be missing from the classpath! See the MNGECLIPSE-768 issue report for details.
If you are not using the m2eclipse plugin, you have to follow different steps to import the project. First, switch into the Wicket numberguess example, then execute the Maven Eclipse plugin with the jetty profile activated, as follows:
$> cd examples/wicket/numberguess mvn -Pjetty eclipse:eclipse
Then, from Eclipse, choose File -> Import... -> General -> Existing Projects into
Workspace, select the root directory of the numberguess example, and click Finish. This will
create a project in your workspace called weld-wicket-numberguess.

It's time to get the example running!
This project follows the wicket-quickstart approach of creating an instance of Jetty
in the Start class. So running the example is as simple as right-clicking on that
Start class in src/test/java in the Package Explorer and choosing
Run as Java Application. You should see console output related to Jetty starting up;
then visit able http://localhost:9090 to view the app. To debug
choose Debug as Java Application instead.
This example can also be deployed from the command line in a (similar to the other examples). Assuming
you have set up the local.build.properties file in the examples
directory to specify the location of JBoss AS or Tomcat, as previously described, you can run:
$> ant deploy
to deploy the example to JBoss AS, and:
$> ant tomcat.deploy
to deploy the example to Tomcat. You can then access application at http://localhost:8080/weld-numberguess-wicket.
Alternatively, you can run the application in place on an embedded Jetty container using the following Maven command:
$> mvn jetty:run -Pjetty
Enough toying with deployment, let's dive into the code.
The code in the wicket numberguess example is very similar to the JSF-based numberguess example. The business layer is identical! Where things differ is in view binding. JSF uses Unified EL expressions to bind XML-based view layer components in JSF views to beans. In contrast, Wicket defines its components in Java. These Java-based view components have a one-to-one mapping with HTML elements in an adjacent (pure) HTML file. All view logic, including binding of components to models and controlling the response of view actions, is handled in Java.
The integration of Weld with Wicket takes advantage of the same qualifier annotations used in your
business layer to provide injection into your WebPage subclass (or into other custom
Wicket component subclasses).
Here's where things differ from the JSF numberguess example:
Each wicket application must have a WeldApplication subclass. In our case, our
application class is NumberGuessApplication:
public class NumberGuessApplication extends WeldApplication {
@Override public Class getHomePage() {
return HomePage.class;
}
}
This class specifies which page Wicket should treat as our home page, in our case,
HomePage.class
In HomePage, we see typical Wicket code to set up page elements. The bit that is
interesting is the injection of the Game bean:
@Inject Game game;
The Game bean is can then be used, for example, by the code for submitting a
guess:
final Component guessButton = new AjaxButton("GuessButton") {
protected void onSubmit(AjaxRequestTarget target, Form form) {
if (game.check()) {
info("Correct!");
setVisible(false);
prompt.setVisible(false);
guessLabel.setVisible(false);
inputGuess.setVisible(false);
}
else if (game.getRemainingGuesses() == 0) {
info("Sorry, the answer was " + game.getNumber());
setVisible(false);
guessLabel.setVisible(false);
inputGuess.setVisible(false);
}
else if (game.getNumber() > game.getGuess()) {
info("Higher!");
}
else if (game.getNumber() < game.getGuess()) {
info("Lower");
}
target.addComponent(form);
}
};
All injections may be serialized; actual storage of the bean is managed by JSR-299. Note that
Wicket components, like the HomePage and it subcomponents, are
not JSR-299 beans.
Wicket components allow injection, but they cannot use interceptors,
decorators or lifecycle callbacks such as @PostConstruct or methods. The
components would need to delegate to actual beans to leverage these features.
The example uses AJAX for processing of button events, and dynamically hides buttons that are no longer relevant, for example when the user has won the game.
In order to activate Wicket for this webapp, the Wicket filter is added to web.xml,
and our application class is specified in web.xml:
<filter>
<filter-name>Wicket Filter</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>org.jboss.weld.examples.wicket.NumberGuessApplication</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Wicket Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The servlet listener is still required, as in the Tomcat example, to bootstrap CDI when Jetty
starts and to hook CDI into the Jetty servlet request and session lifecycles. However, rather than
putting it into the web.xml, it is placed into an override file,
src/main/webapp/WEB-INF/jetty-additions-to-web.xml, that is passed to Jetty as
an extra descriptor to be appended to the web.xml configuration.
<web-app version="2.4" ...>
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
</web-app>
This example shows how to use the Weld SE extension to in a
Java SE based Swing application with no EJB or servlet dependencies.
This example can be found in the examples/se/numberguess
folder of the Weld distribution.
To run the example:
Ensure that Maven 2 (version 2.0.10+) is installed and in your PATH
Ensure that the JAVA_HOME environment
variable is pointing to your JDK installation
Open a command line or terminal window in the
examples/se/numberguess directory
Execute the following command
mvn -Drun
Let's have a look at the significant code and configuration files that make up this example.
As usual, there is an empty beans.xml file in the root
package (src/main/resources/beans.xml), which
marks this application as a CDI application.
The game's main logic is located in Game.java.
Here is the code for that class, highlighting the ways in which this
differs from the web application version:
@ApplicationScoped
public class Game
{
public static final int MAX_NUM_GUESSES = 10;
private Integer number;
private int guess = 0;
private int smallest = 0;
@Inject
@MaxNumber
private int maxNumber;
private int biggest;
private int remainingGuesses = MAX_NUM_GUESSES;
private boolean validNumberRange = true;
@Inject
Generator rndGenerator;
public Game()
{
}...
public boolean isValidNumberRange()
{
return validNumberRange;
}
public boolean isGameWon()
{
return guess == number;
}
public boolean isGameLost()
{
return guess != number && remainingGuesses <= 0;}
public boolean check()
{
boolean result = false;
if (checkNewNumberRangeIsValid())
{
if (guess > number)
{
biggest = guess - 1;
}
if (guess < number)
{
smallest = guess + 1;
}
if (guess == number)
{
result = true;
}
remainingGuesses--;
}
return result;
}
private boolean checkNewNumberRangeIsValid()
{
return validNumberRange = ((guess >= smallest) && (guess <= biggest));}
@PostConstruct
public void reset()
{
this.smallest = 0;
this.guess = 0;
this.remainingGuesses = 10;
this.biggest = maxNumber;
this.number = rndGenerator.next();
}
}
| The bean is application scoped rather than session scoped, since an instance of a Swing application typically represents a single 'session'. |
| Notice that the bean is not named, since it doesn't need to be accessed via EL. |
|
In Java SE there is no JSF
This allows the Swing UI to query the state of the game,
which it does indirectly via a class called
|
|
Since there is no dedicated validation phase, validation of
user input is performed during the |
|
The |
The MessageGenerator class depends on the
current instance of Game and queries its
state in order to determine the appropriate messages to provide
as the prompt for the user's next guess and the response to the
previous guess. The code for MessageGenerator
is as follows:
public class MessageGenerator
{@Inject
private Game game;public String getChallengeMessage()
{
StringBuilder challengeMsg = new StringBuilder("I'm thinking of a number between ");
challengeMsg.append(game.getSmallest());
challengeMsg.append(" and ");
challengeMsg.append(game.getBiggest());
challengeMsg.append(". Can you guess what it is?");
return challengeMsg.toString();
}public String getResultMessage()
{
if (game.isGameWon())
{
return "You guessed it! The number was " + game.getNumber();
}
else if (game.isGameLost())
{
return "You are fail! The number was " + game.getNumber();
}
else if (!game.isValidNumberRange())
{
return "Invalid number range!";
}
else if (game.getRemainingGuesses() == Game.MAX_NUM_GUESSES)
{
return "What is your first guess?";
}
else
{
String direction = null;
if (game.getGuess() < game.getNumber())
{
direction = "Higher";
}
else
{
direction = "Lower";
}
return direction + "! You have " + game.getRemainingGuesses() + " guesses left.";
}
}
}
|
The instance of |
|
The |
| ... and again to determine whether to congratulate, console or encourage the user to continue. |
Finally we come to the NumberGuessFrame class
which provides the Swing front end to our guessing game.
public class NumberGuessFrame extends javax.swing.JFrame
{@Inject
private Game game;@Inject
private MessageGenerator msgGenerator;public void start(@Observes ContainerInitialized event)
{
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
initComponents();
setVisible(true);
}
});
}private void initComponents()
{
buttonPanel = new javax.swing.JPanel();
mainMsgPanel = new javax.swing.JPanel();
mainLabel = new javax.swing.JLabel();
messageLabel = new javax.swing.JLabel();
guessText = new javax.swing.JTextField();
...
mainLabel.setText(msgGenerator.getChallengeMessage());
mainMsgPanel.add(mainLabel);
messageLabel.setText(msgGenerator.getResultMessage());
mainMsgPanel.add(messageLabel);
...
}private void guessButtonActionPerformed( java.awt.event.ActionEvent evt )
{
int guess = Integer.parseInt(guessText.getText());
game.setGuess( guess );
game.check();
refreshUI();
}
private void replayBtnActionPerformed(java.awt.event.ActionEvent evt)
{game.reset();
refreshUI();
}
private void refreshUI() {
mainLabel.setText( msgGenerator.getChallengeMessage() );
messageLabel.setText( msgGenerator.getResultMessage() );
guessText.setText( "" );
guessesLeftBar.setValue( game.getRemainingGuesses() );
guessText.requestFocus();
}
// swing components
private javax.swing.JPanel borderPanel;
...
private javax.swing.JButton replayBtn;
}
| The injected instance of the game (logic and state). |
| The injected message generator for UI messages. |
|
This application is started in the prescribed Weld SE way,
by observing the |
|
This method initializes all of the Swing components. Note
the use of the |
|
|
|
|
The translator example will take any sentences you enter, and translate them to Latin. (Well, not really, but the stub is there for you to implement, at least. Good luck!)
The translator example is built as an ear and contains EJBs. As a result, it's structure is more complex than the numberguess example.
Java EE 6, which bundles EJB 3.1, allows you to package EJBs in a war, which will make this structure much simpler! Still, there are other advantages of using an ear.
First, let's take a look at the ear aggregator, which is located in the example's ear directory. Maven
automatically generates the application.xml for us from this plugin configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<modules>
<webModule>
<groupId>org.jboss.weld.examples.jsf.translator</groupId>
<artifactId>weld-jsf-translator-war</artifactId>
<contextRoot>/weld-translator</contextRoot>
</webModule>
</modules>
</configuration>
</plugin>
This configuration overrides the web context path, resulting in this application URL: http://localhost:8080/weld-translator.
If you weren't using Maven to generate these files, you would need
META-INF/application.xml:
<application version="5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application_5.xsd">
<display-name>weld-jsf-translator-ear</display-name>
<description>The Weld JSF translator example (ear)</description>
<module>
<web>
<web-uri>weld-translator.war</web-uri>
<context-root>/weld-translator</context-root>
</web>
</module>
<module>
<ejb>weld-translator.jar</ejb>
</module>
</application>
Next, lets look at the war, which is located in the example's war directory. Just as in the
numberguess example, we have a faces-config.xml for JSF 2.0 and a web.xml
(to activate JSF) under WEB-INF, both sourced from src/main/webapp/WEB-INF.
More interesting is the JSF view used to translate text. Just as in the numberguess example we have a template, which surrounds the form (ommitted here for brevity):
<h:form id="translator">
<table>
<tr align="center" style="font-weight: bold">
<td>
Your text
</td>
<td>
Translation
</td>
</tr>
<tr>
<td>
<h:inputTextarea id="text" value="#{translator.text}" required="true" rows="5" cols="80"/>
</td>
<td>
<h:outputText value="#{translator.translatedText}"/>
</td>
</tr>
</table>
<div>
<h:commandButton id="button" value="Translate" action="#{translator.translate}"/>
</div>
</h:form>
The user can enter some text in the left-hand textarea, and hit the translate button to see the result to the right.
Finally, let's look at the EJB module, which is located in the example's ejb directory. In
src/main/resources/META-INF there is just an empty beans.xml, used to
mark the archive as containing beans.
We've saved the most interesting bit to last, the code! The project has two simple beans,
SentenceParser and TextTranslator and two session beans,
TranslatorControllerBean and SentenceTranslator. You should be getting
quite familiar with what a bean looks like by now, so we'll just highlight the most interesting bits here.
Both SentenceParser and TextTranslator are dependent beans, and
TextTranslator uses constructor injection:
public class TextTranslator implements Serializable {
private SentenceParser sentenceParser;
@EJB private Translator translator;
@Inject public TextTranslator(SentenceParser sentenceParser) {
this.sentenceParser = sentenceParser;
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(translator.translate(sentence)).append(". ");
}
return sb.toString().trim();
}
}
TextTranslator uses the simple bean (really just a plain Java class!)
SentenceParser to parse the sentence and then calls on the stateless bean with the local
business interface Translator to perform the translation. That's where the magic happens.
Of course, we couldn't develop a full translator, but it's convincing enough to anyone who doesn't understand
Latin!
@Stateless
public class SentenceTranslator implements Translator {
public String translate(String sentence) {
return "Lorem ipsum dolor sit amet";
}
}
Finally, there is UI orientated controller. This is a request scoped, named, stateful session bean, which injects the translator. It collects the text from the user and dispatches it to the translator. The bean also has getters and setters for all the fields on the page.
@Stateful
@RequestScoped
@Named("translator")
public class TranslatorControllerBean implements TranslatorController {
@Inject private TextTranslator translator;
private String inputText;
private String translatedText;
public void translate() {
translatedText = translator.translate(inputText);
}
public String getText() {
return inputText;
}
public void setText(String text) {
this.inputText = text;
}
public String getTranslatedText() {
return translatedText;
}
@Remove public void remove() {}
}
That concludes our short tour of the Weld starter examples. For more information on Weld, please visit http://www.seamframework.org/Weld.
The first major theme of CDI is loose coupling. We've already seen three means of achieving loose coupling:
alternatives enable deployment time polymorphism,
producer methods enable runtime polymorphism, and
contextual lifecycle management decouples bean lifecycles.
These techniques serve to enable loose coupling of client and server. The client is no longer tightly bound to an implementation of an interface, nor is it required to manage the lifecycle of the implementation. This approach lets stateful objects interact as if they were services.
Loose coupling makes a system more dynamic. The system can respond to change in a well-defined manner. In the past, frameworks that attempted to provide the facilities listed above invariably did it by sacrificing type safety (most notably by using XML descriptors). CDI is the first technology, and certainly the first specification in the Java EE platform, that achieves this level of loose coupling in a typesafe way.
CDI provides three extra important facilities that further the goal of loose coupling:
interceptors decouple technical concerns from business logic,
decorators may be used to decouple some business concerns, and
event notifications decouple event producers from event consumers.
The second major theme of CDI is strong typing. The information about the dependencies, interceptors and decorators of a bean, and the information about event consumers for an event producer, is contained in typesafe Java constructs that may be validated by the compiler.
You don't see string-based identifiers in CDI code, not because the framework is hiding them from you using clever defaulting rules—so-called "configuration by convention"—but because there are simply no strings there to begin with!
The obvious benefit of this approach is that any IDE can provide autocompletion, validation and refactoring without the need for special tooling. But there is a second, less-immediately-obvious, benefit. It turns out that when you start thinking of identifying objects, events or interceptors via annotations instead of names, you have an opportunity to lift the semantic level of your code.
CDI encourages you develop annotations that model concepts, for example,
@Asynchronous,
@Mock,
@Secure or
@Updated,
instead of using compound names like
asyncPaymentProcessor,
mockPaymentProcessor,
SecurityInterceptor or
DocumentUpdatedEvent.
The annotations are reusable. They help describe common qualities of disparate parts of the system. They help us categorize and understand our code. They help us deal with common concerns in a common way. They make our code more literate and more understandable.
CDI stereotypes take this idea a step further. A stereotype models a common role in your application architecture. It encapsulates various properties of the role, including scope, interceptor bindings, qualifiers, etc, into a single reusable package. (Of course, there is also the benefit of tucking some of those annotations away).
We're now ready to meet some more advanced features of CDI. Bear in mind that these features exist to make our code both easier to validate and more understandable. Most of the time you don't ever really need to use these features, but if you use them wisely, you'll come to appreciate their power.
Producer methods let us overcome certain limitations that arise when a container, instead of the application, is responsible for instantiating objects. They're also the easiest way to integrate objects which are not beans into the CDI environment.
According to the spec:
A producer method acts as a source of objects to be injected, where:
the objects to be injected are not required to be instances of beans,
the concrete type of the objects to be injected may vary at runtime or
the objects require some custom initialization that is not performed by the bean constructor
For example, producer methods let us:
expose a JPA entity as a bean,
expose any JDK class as a bean,
define multiple beans, with different scopes or initialization, for the same implementation class, or
vary the implementation of a bean type at runtime.
In particular, producer methods let us use runtime polymorphism with CDI. As we've seen, alternative beans are one solution to the problem of deployment-time polymorphism. But once the system is deployed, the CDI implementation is fixed. A producer method has no such limitation:
@SessionScoped
public class Preferences implements Serializable {
private PaymentStrategyType paymentStrategy;
...
@Produces @Preferred
public PaymentStrategy getPaymentStrategy() {
switch (paymentStrategy) {
case CREDIT_CARD: return new CreditCardPaymentStrategy();
case CHECK: return new CheckPaymentStrategy();
case PAYPAL: return new PayPalPaymentStrategy();
default: return null;
}
}
}
Consider an injection point:
@Inject @Preferred PaymentStrategy paymentStrategy;
This injection point has the same type and qualifier annotations as the producer method, so it resolves to the producer method using the usual CDI injection rules. The producer method will be called by the container to obtain an instance to service this injection point.
The scope of the producer method defaults to @Dependent, and so it will be called
every time the container injects this field or any other field that resolves to the
same producer method. Thus, there could be multiple instances of the PaymentStrategy
object for each user session.
To change this behavior, we can add a @SessionScoped annotation to the method.
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy() {
...
}
Now, when the producer method is called, the returned PaymentStrategy will be bound to
the session context. The producer method won't be called again in the same session.
A producer method does not inherit the scope of the bean that declares the method. There are two different beans here: the producer method, and the bean which declares it. The scope of the producer method determines how often the method will be called, and the lifecycle of the objects returned by the method. The scope of the bean that declares the producer method determines the lifecycle of the object upon which the producer method is invoked.
There's one potential problem with the code above. The implementations of
CreditCardPaymentStrategy are instantiated using the Java new
operator. Objects instantiated directly by the application can't take advantage of dependency injection and
don't have interceptors.
If this isn't what we want, we can use dependency injection into the producer method to obtain bean instances:
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
CheckPaymentStrategy cps,
PayPalPaymentStrategy ppps) {
switch (paymentStrategy) {
case CREDIT_CARD: return ccps;
case CHEQUE: return cps;
case PAYPAL: return ppps;
default: return null;
}
}
Wait, what if CreditCardPaymentStrategy is a request-scoped bean? Then the producer
method has the effect of "promoting" the current request scoped instance into session scope. This is almost
certainly a bug! The request scoped object will be destroyed by the container before the session ends, but
the reference to the object will be left "hanging" in the session scope. This error will
not be detected by the container, so please take extra care when returning bean
instances from producer methods!
There's at least three ways we could go about fixing this bug. We could change the scope of the
CreditCardPaymentStrategy implementation, but this would affect other clients of that
bean. A better option would be to change the scope of the producer method to @Dependent
or @RequestScoped.
But a more common solution is to use the special @New qualifier annotation.
Consider the following producer method:
@Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps,
@New CheckPaymentStrategy cps,
@New PayPalPaymentStrategy ppps) {
switch (paymentStrategy) {
case CREDIT_CARD: return ccps;
case CHEQUE: return cps;
case PAYPAL: return ppps;
default: return null;
}
}
Then a new dependent instance of CreditCardPaymentStrategy will be
created, passed to the producer method, returned by the producer method and finally bound to the session
context. The dependent object won't be destroyed until the Preferences object is destroyed,
at the end of the session.
Some producer methods return objects that require explicit destruction. For example, somebody needs to close this JDBC connection:
@Produces @RequestScoped Connection connect(User user) {
return createConnection(user.getId(), user.getPassword());
}
Destruction can be performed by a matching disposer method, defined by the same class as the producer method:
void close(@Disposes Connection connection) {
connection.close();
}
The disposer method must have at least one parameter, annotated @Disposes, with the same
type and qualifiers as the producer method. The disposer method is called automatically when the context ends
(in this case, at the end of the request), and this parameter receives the object produced by the producer
method. If the disposer method has additional method parameters, the container will look for a bean that
satisfies the type and qualifiers of each parameter and pass it to the method automatically.
Interceptor functionality is defined in the Java Interceptors specification. CDI enhances this functionality with a more sophisticated, semantic, annotation-based approach to binding interceptors to beans.
The Interceptors specification defines two kinds of interception points:
business method interception, and
lifecycle callback interception.
In addition, the EJB specification defines timeout method interception.
A business method interceptor applies to invocations of methods of the bean by clients of the bean:
public class TransactionInterceptor {
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}
A lifecycle callback interceptor applies to invocations of lifecycle callbacks by the container:
public class DependencyInjectionInterceptor {
@PostConstruct
public void injectDependencies(InvocationContext ctx) { ... }
}
An interceptor class may intercept both lifecycle callbacks and business methods.
A timeout method interceptor applies to invocations of EJB timeout methods by the container:
public class TimeoutInterceptor {
@AroundTimeout
public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}
Suppose we want to declare that some of our beans are transactional. The first thing we need is an interceptor binding type to specify exactly which beans we're interested in:
@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}
Now we can easily specify that our ShoppingCart is a transactional object:
@Transactional
public class ShoppingCart { ... }
Or, if we prefer, we can specify that just one method is transactional:
public class ShoppingCart {
@Transactional public void checkout() { ... }
}
That's great, but somewhere along the line we're going to have to actually implement the interceptor that
provides this transaction management aspect. All we need to do is create a standard interceptor, and annotate
it @Interceptor and @Transactional.
@Transactional @Interceptor
public class TransactionInterceptor {
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}
Interceptors can take advantage of dependency injection:
@Transactional @Interceptor
public class TransactionInterceptor {
@Resource UserTransaction transaction;
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}
Multiple interceptors may use the same interceptor binding type.
By default, all interceptors are disabled. We need to enable our interceptor in the
beans.xml descriptor of a bean archive. This activation only applies to the beans in
that archive.
<beans
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>org.mycompany.myapp.TransactionInterceptor</class>
</interceptors>
</beans>
Whoah! Why the angle bracket stew?
Well, having the XML declaration is actually a good thing. It solves two problems:
it enables us to specify a total ordering for all the interceptors in our system, ensuring deterministic behavior, and
it lets us enable or disable interceptor classes at deployment time.
For example, we could specify that our security interceptor runs before our transaction interceptor.
<beans
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>org.mycompany.myapp.SecurityInterceptor</class>
<class>org.mycompany.myapp.TransactionInterceptor</class>
</interceptors>
</beans>
Or we could turn them both off in our test environment by simply not mentioning them in
beans.xml! Ah, so simple.
Suppose we want to add some extra information to our @Transactional annotation:
@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
boolean requiresNew() default false;
}
CDI will use the value of requiresNew to choose between two different interceptors,
TransactionInterceptor and RequiresNewTransactionInterceptor.
@Transactional(requiresNew = true) @Interceptor
public class RequiresNewTransactionInterceptor {
@AroundInvoke
public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}
Now we can use RequiresNewTransactionInterceptor like this:
@Transactional(requiresNew = true)
public class ShoppingCart { ... }
But what if we only have one interceptor and we want the container to ignore the value of
requiresNew when binding interceptors? Perhaps this information is only useful for the
interceptor implementation. We can use the @Nonbinding annotation:
@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {
@Nonbinding String[] rolesAllowed() default {};
}
Usually we use combinations of interceptor bindings types to bind multiple interceptors to a bean. For example,
the following declaration would be used to bind TransactionInterceptor and
SecurityInterceptor to the same bean:
@Secure(rolesAllowed="admin") @Transactional
public class ShoppingCart { ... }
However, in very complex cases, an interceptor itself may specify some combination of interceptor binding types:
@Transactional @Secure @Interceptor
public class TransactionalSecureInterceptor { ... }
Then this interceptor could be bound to the checkout() method using any one of the following
combinations:
public class ShoppingCart {
@Transactional @Secure public void checkout() { ... }
}
@Secure
public class ShoppingCart {
@Transactional public void checkout() { ... }
}
@Transactional
public class ShoppingCart {
@Secure public void checkout() { ... }
}
@Transactional @Secure
public class ShoppingCart {
public void checkout() { ... }
}
One limitation of the Java language support for annotations is the lack of annotation inheritance. Really, annotations should have reuse built in, to allow this kind of thing to work:
public @interface Action extends Transactional, Secure { ... }
Well, fortunately, CDI works around this missing feature of Java. We may annotate one interceptor binding type with other interceptor binding types (termed a meta-annotation). The interceptor bindings are transitive — any bean with the first interceptor binding inherits the interceptor bindings declared as meta-annotations.
@Transactional @Secure
@InterceptorBinding
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action { ... }
Now, any bean annotated @Action will be bound to both
TransactionInterceptor and SecurityInterceptor. (And even
TransactionalSecureInterceptor, if it exists.)
The @Interceptors annotation defined by the interceptor specification (and used by the
managed bean and EJB specifications) is still supported in CDI.
@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class})
public class ShoppingCart {
public void checkout() { ... }
}
However, this approach suffers the following drawbacks:
the interceptor implementation is hardcoded in business code,
interceptors may not be easily disabled at deployment time, and
the interceptor ordering is non-global — it is determined by the order in which interceptors are listed at the class level.
Therefore, we recommend the use of CDI-style interceptor bindings.
Interceptors are a powerful way to capture and separate concerns which are orthogonal to the application (and type system). Any interceptor is able to intercept invocations of any Java type. This makes them perfect for solving technical concerns such as transaction management, security and call logging. However, by nature, interceptors are unaware of the actual semantics of the events they intercept. Thus, interceptors aren't an appropriate tool for separating business-related concerns.
The reverse is true of decorators. A decorator intercepts invocations only for a certain Java interface, and is therefore aware of all the semantics attached to that interface. Since decorators directly implement operations with business semantics, it makes them the perfect tool for modeling some kinds of business concerns. It also means that a decorator doesn't have the generality of an interceptor. Decorators aren't able to solve technical concerns that cut across many disparate types. Interceptors and decorators, though similar in many ways, are complementary. Let's look at some cases where decorators fit the bill.
Suppose we have an interface that represents accounts:
public interface Account {
public BigDecimal getBalance();
public User getOwner();
public void withdraw(BigDecimal amount);
public void deposit(BigDecimal amount);
}
Several different beans in our system implement the Account interface. However, we have a
common legal requirement that; for any kind of account, large transactions must be recorded by the system in a
special log. This is a perfect job for a decorator.
A decorator is a bean (possibly even an abstract class) that implements the type it decorates and is annotated
@Decorator.
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
...
}
The decorator implements the methods of the decorated type that it wants to intercept.
@Decorator
public abstract class LargeTransactionDecorator
implements Account {
@Inject @Delegate @Any Account account;
@PersistenceContext EntityManager em;
public void withdraw(BigDecimal amount) {
...
}
public