Java EE 6 has three different ways of defining “beans” that are “managed” in one way or another. Here is a quick recap.
JSF 2.0 introduced annotations to avoid the tedium of declaring managed beans in faces-config.xml:
@javax.faces.bean.ManagedBean(name="user") @javax.faces.bean.SessionScoped public class UserBean implements Serializable { ... }
That's certainly nicer than
<managed-bean> <managed-bean-name>user</managed-bean-name> <managed-bean-class>com.corejsf.UserBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean>
There is a second annotation for a rudimentary dependency injection mechanism:
public class EditBean { @javax.faces.bean.ManagedProperty(value="#{user}") private UserBean currentUser; }
When an EditBean
instance is constructed, the value expression #{user}
is evaluated, and the result is passed to the setCurrentUser
method (which you must also supply)
(It is a bit odd that the @ManagedProperty
annotation is applied to a field when in fact the property setter is invoked. That is not how injection works elsewhere in Java EE. Let's not dwell on this oddity.)
There is an annotation @javax.annotation.ManagedBean
, defined by JSR 316, that attempts to generalize JSF managed beans for use elsewhere in Java EE. There isn't much there. You can use the @PostConstruct
and @PreDestroy
annotations. You can use @Resource
for injecting EE resources. You can use interceptors. For example, if you define
@javax.annotation.ManagedBean("user") public class UserBean ...
then you can construct an instance by making a JNDI lookup for java:module/user
. But there is no interaction with an expression language, and there is no notion of scopes. So, perhaps this kind of managed bean isn't going to see a lot of love.
In an EE 6 container, you can use JSR 299 “contexts and dependency injection” (CDI), like this:
@javax.inject.Named("user") @javax.enterprise.context.SessionScoped public class UserBean implements Serializable { ... }
Now you refer to the bean as #{user}
in JSF, just like you would with JSF managed beans.
If you try this out, remember to put an empty beans.xml
into web/WEB-INF
to trigger the CDI implementation. This works today with GlassFish v3.
What is the advantage? Well, first off, @Named("user")
is shorter than @ManagedBean(name="user")
, so you are doing your part alleviating the global pixel shortage.
The advocates of CDI will tell you that they offer facilities for managing beans that go far beyond what JSF has to offer, and that is certainly true. For example, injection works with types, not EL expressions. You would use
@Inject private UserBean currentUser;
Then the CDI implementation automatically injects the UserBean
of the appropriate scope. You use annotations (which you define) to control this process, such as
@Inject @LoggedIn private UserBean currentUser;
I won't go into detail here. See the documentation of Weld, the CDI reference implementation, which is very well written. For a quick intro, check out this blog by Roger Kitain.
Dependency injection is all good and well, but here is a more immediate “selling point” for a JSF programmer. CDI supports the usual request, session, and application scope, but it also provides a conversation scope, a scope whose lifetime is controlled by the application. That's a sorely needed feature to deal with two separate problems: session bloat and multiple browser windows. Again, the Weld documentation describes this quite nicely.
So, should we ditch @javax.faces.bean.ManagedBean
before too many people get used to it? If you deploy in an EE 6 container, then there is really no reason to use @ManagedBean
. Just use @Named
and start using CDI—it's there, so why not take advantage of it? If you use Tomcat or another servlet runner, you can also get CDI by adding the Weld implementation to your web app. According to a recent conversation on the jsr-314-open mailing list (which, sadly, doesn't seem to be archived), Spring 3.0 supports @Named
as well, so that seems to be the way to go for consistent examples.
On the flip side, IDE support isn't quite there yet (see this bug—please vote for it), and there will always be some people who will want to use Tomcat without any additional libraries.
Why do I care? We have a very short window for replacing all @ManagedBean
with @Named
before the 3rd edition of Core JSF goes to print, and I wonder whether we should do it. Please comment! (But please, no flame wars on JSF or CDI—there is a better forum for those :-))