Friday, April 9, 2010

4 areas of possible confusion in JEE 6

The JEE specification is released and maintained through the Java Community Process, which defines the different API’s that will be included in each release, and how they relate to each other. Due to the technical and political factors involved in the process, besides the time constraint, is no surprise that some areas of the specification may be confusing to new developers, especially with the rising number of annotations introduced by each API.

In this post, I will try to explain four areas where developers might find themselves confused when working with JEE 6.

1. Managed Beans and EL access

The following two annotations from the JEE 6 API are both used to access a bean from the Expression Language (i.e. using the #{} notation):

  • @javax.faces.bean.ManagedBean – Defined in the JSF 2.0 Managed Bean Annotations specification (JSR-314), it provides an alternative to the declaration of managed beans in the faces-config.xml descriptor file.
  • @javax.inject.Named – Defined in the Dependency Injection (JSR-330) specification, is one of the built-in qualifier types of CDI (JSR-299) used to provide a name to a bean, making it accessible through EL.

So, which one to use? Always use the @Named annotation, unless you are working in a JSF 2.0 environment without CDI (a very unlikely scenario). There is just no reason to use JSF Managed Beans if CDI is present. You can check this article for more information.

Furthermore, there is another @ManagedBean annotation you might also get confused with:

  • @javax.annotation.ManagedBean – Defined by the Commons Annotations specification (JSR-250), it is used to declare a managed bean as specified in the Managed Beans specification (JSR-316).

Most likely, you will never need to use this annotation. Let’s look why.

First, don’t confuse Managed Beans with JSF Managed Beans, they are different things. The Managed Beans specification, a subset of the JSR-316, is an effort to provide services like dependency injection, lifecycle callbacks and interceptors to POJO’s (Plain Old Java Objects), which is really cool! So, why not to use it?

CDI treats all POJO’s as Managed Beans! There is no need to explicitly annotate the POJO with @javax.annotation.ManagedBean. Nothing stops you from doing it though.

2. Duplicated @…Scoped annotations

The following annotations are duplicated in the JEE 6 API:

  • @javax.faces.bean.RequestScoped and @javax.enterprise.context.RequestScoped.
  • @javax.faces.bean.SessionScoped and @javax.enterprise.context.SessionScoped.
  • @javax.faces.bean.ApplicationScoped and @javax.enterprise.context.ApplicationScoped.

The @javax.faces.bean… annotations are defined in the JSF Managed Beans specification (JSR-314) and the @javax.enterprise.context… annotations are defined in the CDI specification (JSR-299). 

So, which ones to use? Always use the CDI annotations, unless you are working in a JSF 2.0 environment without CDI (a very unlikely scenario). As discussed above, there is no reason to use JSF Managed Beans if CDI is present.

One scope that is missing in CDI is the @ViewScoped of JSF. However, the problem is solved by creating a portable extension which will be included in the Seam 3 Faces Module.

3. Defining a Singleton

There are four annotations that provide very similar functionality:

  • @javax.ejb.Singleton – A new type of EJB from the JSR-318 specification, it is used to maintain a single shared instance; it’s thread safe and transactional.
  • @javax.inject.Singleton – From the Dependency Injection specification (JSR-330), marks a type the injector will only instantiate once.
  • @javax.enterprise.inject.ApplicationScoped – One of the built-in scopes from the Contexts and Dependency Injection specification (JSR-299), specifies that a bean is application scoped.
  • @javax.faces.bean.ApplicationScoped – Defined in the JSF 2.0 (JSR-314) Managed Beans specification, specifies that a JSF managed bean is application scoped.

They all guarantee a single instance of the class. But, which one to use?

We have already discussed the duplicated @ApplicationScoped annotations above, so we will just dismiss @javax.faces.bean.ApplicationScoped to move on. That leaves us with just 3 options.

@javax.ejb.Singleton is the only one that will give you out-of-the-box “enterprise” services such as concurrency and transaction management. So, if you need these features, this is the annotation to use. You can optionally add the @javax.enterprise.inject.ApplicationScoped annotation but you will not feel the difference, although, CDI will treat it differently. You can check this forum thread for more information.

Note: even though it is possible to use @javax.enterprise.inject.ApplicationScoped with a Stateful Session Bean, I can’t find any good reason to use it given that EJB 3.1 has introduced the Singleton Beans.

If you want to use POJO’s (called Managed Beans in the JEE world), instead of EJB’s, you can also annotate them with @javax.enterprise.inject.ApplicationScoped to guarantee that the class is instantiated only once. Be aware that you will lose all of the services provided by EJB’s such as concurrency and transaction management.

I would not suggest using @javax.inject.Singleton unless you are working in a JS2E environment without CDI support. You can check the Weld documentation and this forum thread for more information about how this annotation is handled in CDI.

Note: none of the annotations discussed above will guarantee a shared single instance in a clustered environment. Usually, you will have one singleton instance per JVM.

4. @Inject or @EJB

They are both used for injection. @Inject is from the Dependency Injection specification (JSR-330) and @EJB from the EJB specification (JSR-318).

So, which one to use?

In most of the cases you will use @Inject over @EJB unless you are working on an environment with EJB’s but no CDI (very unlikely since JEE 6), or if you need to define an EJB resource. You can check the this forum thread for more information.

Conclusion

  1. If you need to access a bean through EL (i.e. from a JSF page), annotate the bean with @Named.
  2. Usually, you will never need none of the @ManagedBean annotations.
  3. Always use the @…Scoped annotations from the javax.enterprise.context package (CDI).
  4. To define a singleton, use the @ApplicationScoped annotation. If you need the EJB services such as concurrency and transaction, add the @javax.ejb.Singleton annotation.
  5. Always use @Inject instead of @EJB, unless you really have a motive to do so.

12 comments:

Anonymous said...

nice article - I hope a book or more articles on CDI come out soon.

Germán Escobar said...

Thanks! Yes, I hope that too ;)

Jan Halasa said...

Thank you Germán for clarification, I was also little confused about these annotations :)

Kai Wähner said...

Very good article! Actually, these problems confused me a lot looking at JEE 6.

But one extension should be made:
Always use @Inject instead of @EJB, if you need a local instance. You still need @EJB for Remote EJBs.

I think this is a little bit unclear... Or do you disagree?

Best regards, Kai.

Germán Escobar said...

Kai,

I agree. @EJB only if you need a remote EJB or need to define a resource. Is anybody still using remote EJB's? ;)

Anonymous said...

Thank you!

Anonymous said...

Nice article.
thanks.

Unknown said...

hmmm... using the POJO+@Inject-approach in JBoss 6.1.0.Final, I repeatedly get an Exception:

ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Start: name=vfs:///C:/Programme/jboss-6.1.0.Final/server/default/deploy/myapp.war_WeldBootstrapBean state=Create: java.lang.RuntimeException: Service class org.jboss.kernel.weld.plugins.weld.McBeanRegistryObserver didn't implement the Extension interface

This does not happen in another, smaller JEE6 project, though. Any tips on this exception? I only found one entry on pastebin using Google...

Anonymous said...

ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Start: name=vfs:///C:/Programme/jboss-6.1.0.Final/server/default/deploy/myapp.war_WeldBootstrapBean state=Create: java.lang.RuntimeException: Service class org.jboss.kernel.weld.plugins.weld.McBeanRegistryObserver didn't implement the Extension interface


Getting the same error, did you solve it?

Wei Wei said...

Very nice summary. Thanks.

Ant Kutschera said...

Nice article.

@Gérman: "Is anybody still using remote EJBs"? Sure, if you have an enterprisy landscape (i.e. large) and want to scale, while at the same time getting the container to handle distributed transactions and security. SOA with Web Services makes life harder (compensation & recovery rather than transactions) and so remote EJBs is a good alternative.

Anna said...

Great and Useful Article.

J2EE Training

Java EE course

Java EE training

J2EE training in chennai

Java J2EE Training Institutes in Chennai

Java J2EE Training in Chennai

Java EE training

Java Interview Questions

Post a Comment