Why is an exception thrown when an #ManagedProperty is referenced? - jsf

I have a JSF web application with a view-scoped bean and a session-scoped bean. I'd like to modify the session bean's members from the view bean, and I followed this guide from a certain well-known JSF guy, but I can't seem to get it to work without a runtime exception. The reference to the managed session bean, "home" is null when referenced, similar to this question except I've already followed the advice of the accepted answer.
package brian.canadaShipping;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
#ManagedBean(name= "requestBean")
#ViewScoped
public class CpstcRequestBean implements Serializable {
#ManagedProperty(value="#{home}")
private CpstcHomeBean homeBean;
public CpstcHomeBean getHomeBean() {
return homeBean;
}
public void setHomeBean(CpstcHomeBean homeBean) {
this.homeBean = homeBean;
}
private static final long serialVersionUID = -5066913533772933899L;
public String testVar = "hello world";
private boolean displayOutput = false;
public boolean isDisplayOutput() {
return displayOutput;
}
public void setDisplayOutput(boolean displayOutput) {
this.displayOutput = displayOutput;
}
public String getTestVar() {
return testVar;
}
public void setTestVar(String testVar) {
this.testVar = testVar;
}
public CpstcRequestBean()
{
System.out.println("TEST: " + homeBean.toString());
System.out.println("Hello, ResuestBean!");
}
}
The first bit of my "home" bean is as follows:
#ManagedBean(name= "home")
#SessionScoped
public class CpstcHomeBean implements Serializable {
...
UPDATE: I've followed Jordan's suggestions and I have the following in my view-scoped bean:
#ManagedBean(name= "requestBean")
#ViewScoped
public class CpstcRequestBean implements Serializable {
#Inject #Named("home") CpstcHomeBean homeBean;
public CpstcHomeBean getHomeBean() {
return homeBean;
}
public void setHomeBean(CpstcHomeBean homeBean) {
this.homeBean = homeBean;
}
public CpstcRequestBean()
{
System.out.println("TEST: " + homeBean.toString());
System.out.println("Hello, ResuestBean!");
}
...
as well as this in my session-scoped bean:
#Named("home")
#SessionScoped
public class CpstcHomeBean implements Serializable {
...
yet my "home" bean reference is still null. Any ideas?
UPDATE 2: It turns out that you must use #Named in both classes, not just the injected class. My web app now loads but some elements are blank. In my console log, I see, "Target Unreachable, identifier 'home' resolved to null." I'm running on Tomcat 7, if that affects things. Any ideas?

You can either change your session bean's #ManagedBean to #Named and then just inject it into your view scoped bean OR you can reference the session bean as is like this:
FacesContext fc = FacesContext.getCurrentInstance()
private CpstcHomeBean homeBean = (CpstcHomeBean) fc.getApplication().evaluateExpressionGet(fc, "#{home}", CpstcHomeBean.class);

Related

Passing value between JSF Forms. I can't get it to work

I read the other posts about this subject but I still can't get it to work
This are my beans:
Bean1:
#ManagedBean()
#SessionScoped
public class Bean1 implements Serializable {
//Here are some important Properties
public String buttonPressed() {
return "bean2.xhtml";
}
}
<h:form>
<p:commandButton action="#{Bean1.buttonPressed}" value="Do Work"/>
</h:form>
Bean2:
#ManagedBean()
#SessionScoped
public class Bean2 implements Serializable {
#ManagedProperty(value = "#{Bean1}")
private Bean1 b1;
//getter/setter is here
public String doWorkOnSubmit() {
//Access important Properties from bean1
b1.getFoo()
}
}
Now I have two Problems
1.) How to call "doWorkOnSubmit" if the button in Bean1 is pressed? I can't use the constructor because it's SessionScoped and I don't know how to call doWorkOnSubmit un submit
2.)The managed property "b1" is sometimes null
Since on clicking of Do Work button you are calling Bean1.buttonPressed() action method you can call Bean2s doWorkOnSubmit() by injecting Bean2 in Bean1.
Here is your code altered:
#ManagedBean()
#SessionScoped
public class Bean1 implements Serializable {
//Here are some important Properties
/*
* Inject Bean2 here. since both beans are session scoped,
* there ain't gonna be any problem in injection.
*/
#ManagedProperty(value = "#{Bean2}")
private Bean2 b2;
//GETTER SETTER for b2
public String buttonPressed() {
//Here you will be invoking injected managed beans method.
b2.doWorkOnSubmit();
return "bean2.xhtml";
}
}

Can't I access session scope variable using #ManagedProperty?

I know I can put/get session scope variables like this.
FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().put(SESSION_KEY_SOME, some);
Then can't I access the value like this?
#ManagedBean
#SessionScoped
public class SomeOtherBean {
#ManagedProperty("#{sessionScope.some}")
private Some some;
}
The value is null.
#ManagedProperty runs during creation/instantiation of the #ManagedBean.
So, when the #ManagedBean is created before the #{sessionScope.some} is set for first time, then it will still remain null in the #ManagedBean. It will only work when #ManagedBean is created after the #{sessionScope.some} is set for the first time.
There are basically three ways to achieve the desired behavior.
Replace private Some some by externalContext.getSessionMap().get("some").
#ManagedBean
#SessionScoped
public class SomeOtherBean {
public void someMethod() {
Some some = (Some) FacesContext.getCurrentInstance()
.getExternalContext().getSessionMap().get("some");
// ...
}
}
Replace #SessionScoped by #RequestScoped.
#ManagedBean
#RequestScoped
public class SomeOtherBean {
#ManagedProperty("#{sessionScope.some}")
private Some some;
// ...
}
Replace externalContext.getSessionMap().put("some", some) by directly setting it as bean property.
#ManagedBean
public class SomeBean {
#ManagedProperty("#{someOtherBean}")
private SomeOtherBean someOtherBean;
public void someMethod() {
// ...
someOtherBean.setSome(some);
}
// ...
}
See also:
How to choose the right bean scope?

Why cant I get the value of a SessionScoped bean in the constructor of another bean?

I have this SessionScoped bean:
#ManagedBean
#SessionScoped
public class LoginBean implements Serializable {
/**
* Creates a new instance of LoginBean
*/
public LoginBean() {
this.usuario = new Usuario();
}
private Usuario usuario;
//getter & setter
}
The Usuario class:
public class Usuario {
public Usuario() {
}
private String password;
private String nombre;
private int idPlanta;
private int nivel;
private String idUsuario;
//getters & setters
}
And I want to get the value of the property idPlanta from the SessionScoped bean (LoginBean) here (in the constructor) see the comments:
#ManagedBean
#ViewScoped
public class PrincipalBean implements Serializable {
public PrincipalBean() {
System.out.println(this.login.getUsuario().getIdPlanta());
//AT THIS POINT THE VALUE OF idPlanta IS 0 but in the session I have 1...
//Method that uses the idPlanta value as a parameter
}
#ManagedProperty(value = "#{loginBean}")
private LoginBean login;
public LoginBean getLogin() {
return login;
}
public void setLogin(LoginBean login) {
this.login = login;
}
}
But when I show the value in the view it shows the value that really is in the Session idPlanta = 1. I dont understand why I cant get the value of that property in the constructor of that ViewScoped bean (PrincipalBean). I show the value in the view here(I know I can get it directly fron the LoginBean but this is just to show that the property login in PrincipalBean has the Session value):
<h:outputText class="titulo" value="Bienvenido(a) #{principalBean.login.usuario.nombre} Planta #{principalBean.login.usuario.idPlanta}" />
The value of idPlanta in PrincipalBean is very important because I use it as a method parameter to show more info when the view is showed.
Please help me. I still learning JSF.
You need to be using these values after the bean has been constructed. When your constructor is called, your bean has net yet been initialzed - therefore the injections have not yet happend. Using the #PostConstruct method you will be able to access the desired values from the injected objects.
For example :
#ManagedBean
#ViewScoped
public class PrincipalBean implements Serializable {
public PrincipalBean() {
}
#PostConstruct
public init() {
System.out.println(this.login.getUsuario().getIdPlanta());
//AT THIS POINT THE VALUE OF idPlanta IS 0 but in the session I have 1...
//Method that uses the idPlanta value as a parameter
}
#ManagedProperty(value = "#{loginBean}")
private LoginBean login;
public LoginBean getLogin() {
return login;
}
public void setLogin(LoginBean login) {
this.login = login;
}
}
See Also
Why use #PostConstruct?
Injecting Managed Beans In JSF 2.0
JSF injection with managed property, good pattern?

inject the same #SessionScoped Bean in different #Named Beans

I have a little javaee webproject and i need bean injection in it. i have a tomee server with cdi enabled. Here is a little test case.
Here is my #SessionScoped User object
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;
#SessionScoped
public class User implements Serializable {
String userName;
public User () {}
public User (String userName) { this.userName = userName; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
}
and here are my two nearly identical beans:
#Named
#RequestScoped
public class BeanOne {
private String message;
#Inject User user;
#PostConstruct
public void init() { user = new User("TestName"); }
public String getMessage() { return user.getUserName(); }
}
In this bean i create a new user. the method getMessage returns the correct user name. I thought the user should still exist in the second bean because its #SessionScoped. Here is my second bean.
#Named
#RequestScoped
public class BeanTwo {
private String message;
#Inject User user;
public String getMessage() { return user.getUserName(); }
}
But in this bean the user.getUserName() returns null. How am i supposed to inject a #SessionScoped bean?
This happens because you have manually initialized user object in BeanOne init method. The purpose of dependency injection is to let some container create instances of objects for you, so you should never initialize objects manually. So just set a name for this user and it will be visible during session for all other beans.
#PostConstruct
public void init() { user.setUserName("TestName"); }

How to call managed bean inside of stateless EJB bean?

I wanted to know, is there any option to call a managed bean inside of EJB bean. Imagine, we have the code:
#ManagedBean
#SessionScoped
public class MyManagedBean implements Serializable {
public String getUrl() {
return "http://www.google.com";
}
}
#Stateless
public class MyEJB {
#ManagedProperty(value = "#{myManagedBean}")
MyManagedBean myManagedBean;
public void setMyManagedBean(MyManagedBean myManagedBean) {
this.myManagedBean = myManagedBean;
}
public void call() {
// NullPointerException here
System.out.println(myManagedBean.getUrl());
}
}
I also tried this:
#Stateless
public class MyEJB {
#EJB
MyManagedBean myManagedBean;
...
}
... but it returns different MyManagedBean instance.
This is not right. With CDI managed beans instead of JSF managed beans it's possible, but it is just not right as in, bad design. The business service should not be aware about the front-end at all. It makes the business service unreusable on other front-ends than JSF.
You should do it the other way round. You should inject the EJB in the managed bean, not the other way round. The EJB should be kept entirely stateless. You should just directly pass the EJB the information it needs as method argument (and never assign it as instance variable of EJB afterwards).
E.g.
#ManagedBean
#SessionScoped // <-- Did you read https://stackoverflow.com/q/7031885?
public class MyManagedBean implements Serializable {
private String url = "http://www.google.com";
#EJB
private MyEJB myEJB;
public void submit() {
myEJB.call(url);
}
public String getUrl() {
return url;
}
}
and
#Stateless
public class MyEJB {
public void call(String url) {
// No NullPointerException here.
System.out.println(url);
}
}
See also:
JSF Service Layer

Resources