Can I put #ManagedBean in CDI scope? - jsf

I'm using GlassFish 3.0.1. I want to know if I can use:
#ManagedBean
#ConversationScoped
Instead of #Named?

#ManagedBean is a JSF annotation while #ConversationScoped is a CDI annotation, I can't think of any valid scenario to combine them.
In general #Named will cover almost all you needs and it make your bean available to EL thus the JSF pages.

Related

Inject CDI bean into JSF #ViewScoped bean

I have a problem with JSF, CDI project. I did a lot of research and I found that in CDI there is no #ViewedScoped annotation. I solving problem with ajax based page with dialog. I want to pass variable to dialog from datatable. For this purpose, I can't use #RequestedScoped bean because value is discard after end of request. Can anyone help me to solve it? I can't use #SessionScoped but it's a bad practice IMHO. Or maybe save only this one variable into session who knows. Can you guys give me any hints how to solve this problem elegantly?
import javax.enterprise.context.ApplicationScoped;
#ApplicationScoped
public class ServiceBean implements Serializable {
...
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class SomeBean {
#Inject
ServiceBean serviceBean;
#Postconstruct ...
Here is the error message:
com.sun.faces.mgbean.ManagedBeanCreationException: An error occurred performing resource injection on managed bean warDetailBean
First, If you are attempting to use CDI, you need to activate it by putting a WEB-INF/beans.xml file in your application (note that this file can be empty), more informations about that file could be found in the Weld - JSR-299 Reference Implementation.
As you are using Tomcat, please be sure to respect all the configuration requirements by following the steps in How to install CDI in Tomcat?
Second, Even if you can use #Inject inside a JSF managed bean, It's preferable that you don't mix JSF managed beans and CDI, please see BalusC's detailed answer regarding Viewscoped JSF and CDI bean.
So if you want to work only with CDI #Named beans, you can use OmniFaces own CDI compatible #ViewScoped:
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#Named
#ViewScoped
public class SomeBean implements Serializable {
#Inject
ServiceBean serviceBean;
}
Or, if you want to work only with JSF managed beans, you can use #ManagedProperty to inject properties:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class SomeBean{
#ManagedProperty(value = "#{serviceBean}")
ServiceBean serviceBean;
}
See also:
ManagedProperty in CDI #Named bean returns null
Omnifaces CDI ViewScoped

Setting view scope on JSF 2.2

On JSF 2.2 we don't have the option to set the View Scope on faces-config.xml .
So how should it be done? Is the view scope missing on JSF 2.2 ?
Thank you!
Use #ViewScoped annotation on managed bean:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class AViewScopedBean {
//managed bean contents...
}
If you don't like the annotations configuration (really odd), you can just set the view scope on faces-config.xml
<managed-bean>
<managed-bean-name>aViewScopedBean<managed-bean-name>
<managed-bean-class>some.package.AViewScopedBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
Note that this only works on JSF 2. Check that your faces-config file is configured to handle JSF 2.x version:
<!-- relevant part of faces-config.xml file for this Q/A -->
<faces-config ... version="2.1">
Note: Warning make sure its Serializable
The error message is pretty straightforward:
java.io.NotSerializableException: com.bean.StatusBean2
This means that your com.bean.StatusBean2 must also implement the Serializable interface. From java.io.Serializable documentation:
When traversing a graph, an object may be encountered that does not support the Serializable interface. In this case the NotSerializableException will be thrown and will identify the class of the non-serializable object. (this is the error you're getting)
You can learn more about Java Serialization here: Java Serialization
From your question: is it necessary to implement serializable?, BalusC already posted a good answer/explanation: JSF backing bean should be serializable?
Thanks for #Luiggi Mendoza

#javax.faces.bean.ManagedProperty in CDI #Named bean returns null

I'm trying to deal with #javax.faces.bean.ManagedProperty but without success !
I've been following this guide, and it not seems that hard.
But my code simply won't work!
Here's a little snippet
#ManagedBean
#SessionScoped
public class LoginBean {
private User user;
// ...
}
#Named
#RequestScoped
public class MessagesBean {
#ManagedProperty(value = "#{loginBean}")
private LoginBean loginBean;
public String getUser() {
System.err.println(loginBean == null);
return loginBean.getUser().getUsername();
}
// ...
}
This code gives me a NullPointerException, saying that loginBean is null!
Any suggestion?
You are mixing JSF managed beans with CDI beans. Your LoginBean is a JSF managed bean (it has the #ManagedBean annotation). Your MessageBean is a CDI bean (it has the #Named annotation). If you changed the Message bean to a JSF managed bean (replacing #Named with #ManagedBean) then the problem should be solved (It should work with two CDI beans as well). Or if you're using JSF 2.3 or newer, then use javax.faces.annotation.ManagedProperty instead in the CDI bean.
Here is a short overview of how injection works between both bean types:
CDI #Named --> CDI #Named (works)
CDI #Named --> JSF #ManagedBean (works only if scope of injected bean is broader)
JSF #ManagedBean --> JSF #ManagedBean (works only if scope of injected bean is broader)
JSF #ManagedBean --> CDI #Named (won't work)
But take care of the scope import classes. There are different classes for #SessionScoped and #RequestScoped depending on the bean type.
javax.faces.bean.SessionScoped for #ManagedBeans
javax.enterprise.context.SessionScoped for CDI #Named beans
In addition, for #Named (CDI) use #Inject and for #ManagedBean use #ManagedProperty. There is one thing that does not work in CDI. Your #ManagedProperty(value = "#{loginBean}") gets a full bean, but #ManagedProperty(value = "#{loginBean.user}") to get a 'property' of a bean works to. This is not directly possible in CDI with #Inject. See CDI Replacement for #ManagedProperty for a 'solution'

Correct way of retrieving another bean instance from context [duplicate]

This question already has answers here:
Get JSF managed bean by name in any Servlet related class
(6 answers)
Closed 2 years ago.
We are using the following code to get the managed bean instance from the context.
FacesUtils.getManagedBean("beanName");
Is it the correct way of doing it?. If multiple users access the same bean what will happen?
How the bean instances are managed?
Since FacesUtils is not part of standard JSF implementation, it's unclear what it is actually doing under the covers.
Regardless, when you're already inside a managed bean, then the preferred way is to inject the other bean as managed property. I'll assume that you're already on JSF 2.0, so here's a JSF 2.0 targeted example.
#ManagedBean
#SessionScoped
public void OtherBean {}
#ManagedBean
#RequestScoped
public void YourBean {
#ManagedProperty("#{otherBean}")
private void OtherBean;
#PostConstruct
public void init() {
otherBean.doSomething(); // OtherBean is now available in any method.
}
public void setOtherBean(OtherBean otherBean) {
this.otherBean = otherBean;
}
// Getter is not necessary.
}
But when you're still on JSF 1.x, then you need to do it by <managed-property> entry in faces-config.xml as explained in this question: Passing data between managed beans.
If you happen to use CDI #Named instead of JSF #ManagedBean, use #Inject instead of #ManagedProperty. For this, a setter method is not required.
See also:
Communication in JSF2
Get JSF managed bean by name in any Servlet related class
Backing beans (#ManagedBean) or CDI Beans (#Named)?
As to your concern
If multiple users access the same bean what will happen? How the bean instances are managed?
They are managed by JSF. If a bean is found, then JSF will just return exactly this bean. If no bean is found, then JSF will just auto-create one and put in the associated scope. JSF won't unnecessarily create multiple beans.

Are #ManagedBeans obsolete in JavaEE6 because of #Named in CDI/Weld?

Because of CDI (and its implementation Weld), every POJO in JEE6 can be annotated with #Named, which makes the POJO accessible to the view.
Does that mean that ManagedBeans are completely obsolete now?
Or did I miss something where #ManagedBean still makes sense?
In short, #ManagedBean makes sense for applications that use JSF but do not use JSR 299 (whatever the reason is). Below a longer explanation from Gavin King:
Re: Comparisons to #ManagedBean annotations in JSF2?:
While looking through the Weld examples, and the older WebBeans
documentation, it looks like a
competitor to the new #ManagedBean JSF
2.0 annotations. Is there any information on when we'd want to use
one over the other?
It's a good question, and I'm not
really in full agreement with the
answers that have been posted so far.
The new EE Managed Beans specification
defines a base component model for
Java EE, together with a very basic
set of container services (#Resource,
#PostConstruct, #PreDestroy).
The idea is that other specifications
(beginning with EJB, CDI, JSF and the
new Java Interceptors spec) build upon
this base component model and layer
additional services, for example
transaction management, typesafe
dependency injection, interceptors. So
at this level, the managed beans, CDI,
interceptors and EJB specifications
all work hand-in-hand and are highly
complementary.
Now, the Managed Beans specification
is quite open-ended with respect to
identifying exactly which classes are
managed beans. It does provide the
#ManagedBean annotation as one
mechanism, but it also allows other
specifications to define different
mechanisms. So, for example:
The EJB specification says that a class obeying certain programming
restrictions with a #Stateless or
#Stateful annotation deployed in an
EJB jar is a managed bean.
The CDI specification says that any class with an appropriate constructor
deployed in a "bean deployment
archive" is a managed bean.
Given that EJB and CDI provide
arguably more convenient ways to
identify a managed bean, you might
wonder precisely what #ManagedBean is
needed for. The answer, as alluded to
by Dan, is that if you have CDI
available in your environment (for
example, if you are using EE6), then
#ManagedBean is just not really
needed. #ManagedBean is really there
for use by people who are using JSF2
without CDI.
OTOH, if you do annotate a bean
#ManagedBean, and you do have CDI in
your environment, you can still use
CDI to inject stuff into your bean.
It's just that the #ManagedBean
annotation is not required in this
case.
To summarize, if you do have CDI
available to you, it provides a far
superior programming model to the
#ManagedBean/#ManagedProperty model
that JSF2 inherits from JSF1. So
superior, in fact, that the EE 6 web
profile does not require support for
#ManagedProperty etc. The idea being
that you should just use CDI instead.
You have a choice. Either use the #ManagedBean from JSF2 to bind beans into your forms, or use the #Named annotation from CDI. If you plan on only doing JSF, you can stick to #ManagedBean, but if you want to integrate with EJB's, or make use of CDI's #ConversationScoped, then go the CDI route.
Personally I feel the next version of JSF should deprecate the #ManagedBean, and standardize on CDI. The duality is confusing to newcomers.
CDI has no view scope, because it doesn't have the notion of a view, so if you need that scope, CDI in its pure form can't do it. View scope basically means request scope + being AJAX-ready. It's not a JSF view, like a page named xyz.xhtml, even though you see JSF <f:viewParam> and the likes. A frequent use case with view-scoped beans is how to get GET parameters into a such a bean. Also read this.
Note that CDI rather lives at the EJB/service layer than the JSF/presentation layer. This blog has a nice overview.
As such #ManagedBean cannot be fully replaced by CDI, again if you're using #ViewScoped beans - at least not without extending CDI or using the Seam 3 Faces module. Using view-scoped beans is almost always going to happen when using AJAXed JSF 2-based GUI toolkits like RichFaces, PrimeFaces, IceFaces etc.
Mixing annotations from the wrong Java EE 6 packages can get you in trouble unexpectedly, again when using RichFaces or a similar API:
#javax.faces.bean.ManagedBean
#javax.faces.bean.[Jsf]Scoped
are for components used solely at the presentation layer, here by RichFaces, PrimeFaces, etc. Some rich components seem to have problems with CDI-annotated and JSF-annotated helper beans. If you get strange behavior from your beans (or beans that seem to do nothing) the wrong mix of annotations might be the cause.
Mixing JSF and CDI, like
#javax.inject.Named
#javax.faces.bean.[Jsf]Scoped
is possible and works in most cases when referenced from JSF pages, however there are some little-known issues/drawbacks, e.g. when using a JSF scope which CDI doesn't have:
Also the combination #Named #ViewScoped won't work as intended. The JSF-specific #ViewScoped works in combination with JSF-specific #ManagedBean only. Your CDI-specific #Named will behave like #RequestScoped this way. Either use #ManagedBean instead of #Named or use CDI-specific #ConversationScoped instead of #ViewScoped.
Then
#javax.inject.Named
#javax.faces.bean.[Cdi]Scoped
can be used for CDI beans directly referenced from your JSF pages AFAIK. I haven't had any problems with the above combinations so far, so you could consider #ManagedBean obsolete here.
What's left is the service layer, here mostly transactional EJB service beans declared as
#javax.ejb.*
mostly #javax.ejb.Stateless. You can even annotate and use EJBs directly from JSF pages - though I'm not sure if this design is desirable. To reference (inject) any components annotated with #javax.ejb.*, e.g. #Stateless, prefer #Inject over #EJB as described here. (Probably an ancestor of this answer...)
Finally, a very nice overview of Java EE 6 annotations can be found here:
http://www.physics.usyd.edu.au/~rennie/javaEEReferenceSheet.html
Note: the above info is not from an expert, but simply my own take/sight from a newcomers perspective on this ridiculously confusing Java EE 6 annotations spaghetti. More insight has yet to be developed. I hope this answer can endure to be a general, practical answer to this confusion - even though it has gone a little overboard in the context of the original question.
As i Just read in the Weld Reference (p. 12), #ManagedBean is now superflous:
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.

Resources