Passing data between managed components in JSF - jsf

Is it actually possible to pass any data between managed components in JSF? If yes, how to achieve this?
Could anyone provide any sample?

There are several ways. If the managed beans are related to each other, cleanest way would be injection. There are different ways depending on JSF version and whether CDI is available.
CDI
Just use #Inject.
#Named
#SessionScoped
public class Bean1 {
// ...
}
#Named
#RequestScoped
public class Bean2 {
#Inject
private Bean1 bean1; // No getter/setter needed.
}
Other way around can also, the scope doesn't matter because CDI injects under the covers a proxy.
JSF 2.x
Use #ManagedProperty.
#ManagedBean
#SessionScoped
public class Bean1 {
// ...
}
#ManagedBean
#RequestScoped
public class Bean2 {
#ManagedProperty("#{bean1}")
private Bean1 bean1; // Getter/setter required.
}
Other way around is not possible in this specific example because JSF injects the physical instance and not a proxy instance. You can only inject a bean of the same or broader scope into a bean of a particular scope.
JSF 1.x
Use <managed-property> in faces-config.xml.
public class Bean1 {
// ...
}
public class Bean2 {
private Bean1 bean1; // Getter/setter required.
}
<managed-bean>
<managed-bean-name>bean1</managed-bean-name>
<managed-bean-class>com.example.Bean1</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>bean2</managed-bean-name>
<managed-bean-class>com.example.Bean2</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>bean1</property-name>
<value>#{bean1}</value>
</managed-property>
</managed-bean>
See also:
Backing beans (#ManagedBean) or CDI Beans (#Named)?
How to choose the right bean scope?
Get JSF managed bean by name in any Servlet related class

To add to BalusC's answer, if you are using a dependency-injection framework (spring, guice, etc.), or if using JSF 2.0, you can have one managed bean set into the other using just:
#Inject
private Bean2 bean2;
(or the appropriate annotation based on your DI framework)

Related

Injecting a view scoped bean into another view scoped bean

A view scoped bean remains alive as long as the user interacts with the same view (or until it is navigated to a different view).
Suppose a view scoped managed bean is injected into another view scoped bean like so,
#ManagedBean
#ViewScoped
public final class SharableManagedBean implements Serializable
{
private static final long serialVersionUID = 1L;
#EJB
private SharableBean sharableService;
//...Do something.
}
#ManagedBean
#ViewScoped
public final class TestManagedBean implements Serializable
{
private static final long serialVersionUID = 1L;
#EJB
private TestBean testBean;
#ManagedProperty(value="#{sharableManagedBean}")
private SharableManagedBean sharableManagedBean ;
//... Do something with the injected bean.
}
In this case, is it necessary for the SharableManagedBean to have a view scoped bean?
What happens, if it is a request scoped bean (SharableManagedBean)? Is it initialized only once, when TestManagedBean comes into picture and destroyed, when TestManagedBean is destroyed?
Even it's technically possible to do that (JSF allows you to inject beans which are at the same or wider scope) I don't see the point of doing that with #ViewScoped beans. From my point of view, a well designed JSF web application should have a single #ViewScoped bean tied to each specific view. Then, how to solve your issue? You can do it in two ways:
If SharableManagedBean is a utility bean which contain static methods which are not tied to JSF, just define this class as abstract and statically invoke its methods everytime you need.
If SharableManagedBean itself has to be a managed bean which access the FacesContext and has common code that is shared along all the view beans, just create an abstract class and make your #ViewScoped beans extend it.
For your last question (SharableManagedBean being #RequestScoped), JSF doesn't allow you doing that. You'll get an exception because of trying to inject a narrower scoped managed bean.
According to the Oracle docs:
Another important point about managed beans referencing each other is that a managed bean can only refer to other beans provide their scope is equal or has a longer lifespan than the calling object.
Update
If using CDI, it's possible to inject a #RequestScoped bean into a #ViewScoped one too, using the Proxy pattern. Have it a look.

What makes a bean a CDI bean?

In the top answer to this question for example : Java EE 6 #javax.annotation.ManagedBean vs. #javax.inject.Named vs. #javax.faces.ManagedBean I read that:
To deploy CDI beans, you must place a file called beans.xml in a
META-INF folder on the classpath. Once you do this, then every bean in
the package becomes a CDI bean.
And also it is said that:
If you want to use the CDI bean from a JSF page, you can give it a
name using the javax.inject.Named annotation.
I have a sample code that goes like this:
#ManagedBean
#ViewScoped
public class SignUpPage {
private User user;
#PostConstruct
public void init() {
user = new User();
}
#Inject
private UserDao userDao;
// rest of the class
So as far as I understand, my bean is still a JSF Managed Bean, it is not a CDI bean(or is it?). By the way, I have a beans.xml in my WEB-INF folder.
And #Inject works just fine in here. Also, I can access the bean with EL just fine(which makes me think it is still a JSF Managed Bean)
The UserDao class looks something like this:
#Stateless
public class UserDao {
EntityManager em;
#PostConstruct
public void initialize(){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Persistence");
em = emf.createEntityManager();
}
So, it is as far as I know an EJB..
So do I have any CDI beans in this example? How does #Inject work here?
Hope my question is clear, Regards!
By CDI specification, every JavaBean is a Managed Bean (do not confuse it with JSF #ManagedBean, this is a different one) in project where the beans.xml is present. So every class is also eligible for dependency injection. Note that default scope of this class is Dependent.

Inject Bean that uses #Named with value

how can I Inject a Bean, that uses a #Named annotation along with a value?
#Named
public class LanguageService{
...
}
public class SomeOtherBean{
#Inject
private LanguageService languageService
}
works without Problem - but how to inject, if i'm using:
#Named("lang")
public class LanguageService{
...
}
#Inject can't have a value as #ManagedProperty does. (But I wan't to stay with CDI)
Edit:
I noticed that it doesn't matter how the bean is named. My Fault that leads to an NPE was simple that i created SomeOtherBean manually, and ofc. no Injection was done. My fault.
CDI selects injectable beans by type (and qualifiers) and not by the annotation parameter. The name is used to address a CDI bean from views, e.g. facelets.

#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.

Resources