Inject CDI bean into JSF #ViewScoped bean - jsf

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

Related

Only First JSF Controller is Created. Others Are Ignored

My first time trying Java and this error is rather strange and I seem to be the only one having the problem on this planet.
I have two web pages:
<h:link outcome="index">Home</h:link>
<h:link outcome="about">About</h:link>
I have two controllers, shown below in the order I created them in package Controller:
HomeController.java
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class HomeController implements Serializable{
public HomeController() {
System.out.println("Home Controller Created......");
}
}
AboutController.java:
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class AboutController implements Serializable{
public AboutController() {
System.out.println("About Controller Created......");
}
}
If I visit home.xhtml, I see Home Controller Created...... but I don't see any message on about.xhtml. The Controller doesn't get called even when I Debug with NetBeans.
Your package declaration is wrong.
Firstly:
Use javax.faces package when playing with JSF, thus your #SessionScope package is wrong.
Secondly:
You need to use #ManagedBean instead of #Named. JSF automatically creates SessionScope bean for you with first reference to it. Don't put anything in constructor because JSF can create the bean when it wants and if the construction fails (Nullpointer etc.) then you have problem. JSF style is to use #PostConstruct annotation to initialise data after construction.
If in your xhtml you have for example <h:outputText value="#{aboutcontroller.someValue}then the AboutBean is created once/session.
(You can also use #ManagedBean(name="aboutController") and reference to it in xhtml with #{aboutController.someValue}
Btw: JSF is all about controllers, usually controllers are in #RequestScope. You can divide your session in those 2 #SessionScope beans, but in the end you only have 1 session. Consider removing the other SessionScope bean, and using #RequestScope beans to manipulate the data in #SessionScope bean. Another good option is to use #ViewScope bean if you are validating some fields and showing error messages with incorrect field values.

Can I put #ManagedBean in CDI scope?

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.

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'

Passing data between managed components in 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)

Resources