JSF injection with managed property, good pattern? - jsf

I'm quite new to JSF and not really "used" to the different thinking so I'm struggling on what (I assume) is basic.
Lets say I have a class User, which is a session bean.
Lets say I have a controller of 10000 objects, say Factory, that needs to be able to set some of them as "locked", in our case it means that the "locked" field does not become null anymore but reference a "LockedItem" object.
This is where I can't get things working : LockedItem, when you instanciate it, is supposed to reference the user currently logged in. How am I supposed to do that ?
I tried injection with #managedproperty, but it is null in LockedItem.constructor (which is normal I assume) then I tried in a #PostConstruct method, but that method is never called (why ? Even if I make it a managedbean... are the postconstruct methods only called when the object is created by the ".xhtml" ?)
Or should I use a "java se" trick, like making the User static ?
Code to clarify why is a #PostConstruct not called (the one of "Seat") :
.xhtml
<h:outputLabel id="user" value="Hello #{user.name}" />
<h:outputLabel id="car" value="you have #{car.brand}" />
User
package test;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class User implements Serializable {
private String name ;
public User()
{
name = "toto";
System.out.println("User constructor");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Car
package test;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
#ManagedBean
public class Car implements Serializable {
private String brand ;
private Seat seat ;
public Car()
{
brand = "audi" ;
seat = new Seat();
System.out.println("Car constructor") ;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
Seat
package test;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
#ManagedBean
public class Seat implements Serializable {
private int nb ;
private String userName ;
#ManagedProperty("#{user}")
private User user ;
public Seat()
{
nb = 4 ;
userName="na";
System.out.println("! Seat constructor ") ;
}
#PostConstruct
public void init()
{
System.out.println("!! Seat postconstruct : "+user.getName());
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public int getNb() {
return nb;
}
public void setNb(int nb) {
this.nb = nb;
}
}
Thanks !

The #PostConstruct is the right way.
It's not called if you instantiate the bean yourself using new operator (obviously). It's only called if JSF instantiates and manages the bean itself whenever it's referenced for the first time in EL context like so #{bean}. This indeed usually happens in the view side, but this can also happen in model/controller side by #ManagedProperty("#{bean}") or Application#evaluateExpressionGet().
You should absolutely not make the User static. It would be shared applicationwide, not sessionwide.
An alternative is to just pass the current User as constructor argument of LockedItem, or to invoke the initialization method yourself, for sure if that class does not represent a legit JSF backing bean at all.

Related

CDI Injected Bean from super class has null fields in child

I'm pretty new to the general procedure of bean injection. I've googled a lot but haven't found a solution to my problem.
Additional Information
Running Wildfly 9.0.1 final
EJB Vers. : 3.1
CDI Vers. : 2.2.16 (SP1)
JSF Vers. : 2.2
import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import javax.inject.Named;
#Named
#ViewScoped
public class UserEmailSettingsBean extends UserModuleSettingsBean {
private List<String> store;
private List<String> selectedStore;
//getters and setters, some fancy stuff...
#Override
public boolean saveProperties() {
LOG.info("Save called");
LOG.info(selectedStore.toString());
LOG.info(store.toString());
for(String prop : store) {
getProperties().setProperty(prop, String.valueOf(false));
}
for(String selectedProp : selectedStore){
LOG.info("selected: " + selectedProp + ":" + getProperties().getProperty(selectedProp) + " -> true");
getProperties().setProperty(selectedProp, String.valueOf(true));
}
super.saveProperties();
return true;
}
}
2nd Class:
public abstract class UserModuleSettingsBean implements ModuleSettings {
private static final long serialVersionUID = 459417872482285085L;
protected abstract List<String> getPropertiesName();
#Inject
private SettingsRepository settingsRepository;
#Inject
private SettingsService settingsService;
private Properties properties = new Properties();
#Override
public boolean saveProperties() {
String username = SecurityContextHolder.getContext().getAuthentication().getName();
settingsService.store(getProperties(), username);
return (true);
}
}
The problem is, that the settingsService is constructed, however its field "settingsRepository" is null in my child class.
On the call of my save method from UserEmailSettings, getProperties().setProperty() is called with the right values, however its never stored, as the settingsRepository is null. I believe that is due to a wrong Injection for some reason.
Let me know if I need to provide more information ☺
Here is the needed part of SettingsRepository:
#Stateless
#TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class SettingsService implements Serializable {
private static final long serialVersionUID = 1695882717866085259L;
#Inject
SettingsRepository settingsRepository;
//...
}
And here the information SettingsRepository
#Stateless
public class SettingsRepository extends AbstractBaseRepository<Settings, Long> {
/**
* Instantiates a new settings repository.
*/
public SettingsRepository() {
super(Settings.class);
}
}
wanted to say my problem was that I didn't called an init() function on the settingsService to create the propertys, so getProperties was empty

how to access one managedbean from another in jsf

I have two managedbean class(UserBean.java & HelloBean.java) and one index.xhthl class. In HelloBean.java class, I have used #ManagedProperty anotation for accessing the property of UserBean.java and I have a method within HelloBean.java class.
here, my classes:
UserBean.java
package com.bean;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name="ubean", eager=true)
#SessionScoped
public class UserBean {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
HelloBean.java
package com.bean;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
#ManagedBean(name="hellobean", eager=true)
#RequestScoped
public class HelloBean {
#ManagedProperty(value="#{ubean}")
private UserBean mbean;
private String username;
public String getUsername() {
if(mbean!=null){
username=mbean.getUsername();
}
return username;
}
public void setMbean(UserBean mbean) {
this.mbean = mbean;
}
public UserBean getMbean() {
return mbean;
}
public void showMsg(){
System.out.println("UserName :"+username);
}
}
And, index.xhtml
<body>
<h:form>
<h:inputText id="username" value="#{ubean.username}"></h:inputText>
<h:commandButton value="submit" action="#{hellobean.showMsg}"></h:commandButton>
</h:form>
</body>
I want to invoke the showMsg() method from index.xhtml class. The method is fired by clicking commandButton, but it always returns null instead of inputText value. What's the problem in my codes. Someone, helps...
Thanks in advance..
Here username is the property of UserBean.java class. As a result, you must have to call the username variable through a object of the parent(UserBean.java) class.So, try it, mbean.getUsername() instead of only username.

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"); }

Target Unreachable, 'null' returned null in JSF2

I am quite new to JSF and I have this problem. I was reading some posts about that but I could found answer( or I didnt understood one...).
I have following user bean:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name="user")
#SessionScoped
public class User implements Serializable {
private String login;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
}
and login bean:
#ManagedBean(name="login")
#SessionScoped
public class Login implements Serializable{
private static final long serialVersionUID = 1L;
#ManagedProperty("#{user}")
private User user;
#PostConstruct
public void init() {
System.out.println("Init called");
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
And my view looks like this:
<h:inputText id="login" value="#{login.user.login}" required="true"/>
<h:commandButton value="Login" action="#{login.user.login}"/><br/>
I want access to user fields in few classess and this how I am trying to achieve this. Unfortunately I keep got this error.
I have found some information that I need beans.xml. Is that true? Where can I find sample? I am using JSF2.
Answer
My fault was that I choose same name for field and for login method. Because of that I was using login.login( before implementing User class) for geting login, and login.login as a action of commandButton. After I implemented User class I changed both login.login to login.user.login.
Thanks again for help.
You are binding a method User#login() to your CommandButton, which does not exist. There is only a property login (get/set).
You need a proper action method in your User bean:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name="user")
#SessionScoped
public class User implements Serializable {
private String login;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public void doLogin() {
// whatever you want to do here
}
}
and bind to the doLogin() method:
<h:commandButton value="Login" action="#{login.user.doLogin}"/>
beans.xml is required to enable CDI, which you don't use here. You are using jsf managed beans. CDI is a more powerful alternative.

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

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);

Resources