jsf custom converter does not work with view scope - jsf

Here is my code
Pojo
public class Deal implements Serializable {
private int id;
private String name;
private String description;
private Customer customer;
//getter setter omitted
}
public class Customer implements Serializable {
private int id;
private String name;
private String email;
private String phone;
//getter setter and equal hashcode omitted
}
Managed Bean
#ManagedBean(name="dealBean")
#ViewScoped
public class DealBean implements Serializable {
private List<Customer> customerList;
private List<Deal> dealList;
private Deal deal;
#PostConstruct
public void init() {
deal = new Deal();
dealList = new ArrayList<Deal>();
customerList = new ArrayList<Customer>();
customerList.add(new Customer(1, "MPRL", "mprl#mail.com", "1234455"));
customerList.add(new Customer(2, "Total", "total#mail.com", "3434323"));
customerList.add(new Customer(3, "Petronas", "petronas#mail.com", "8989876"));
}
//getter setter omitted
}
Customer Converter
#FacesConverter("customerConverter")
public class CustomerConverter implements Converter {
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String customerID) {
DealBean dealBean = (DealBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("dealBean");
if (dealBean != null) {
List<Customer> customerList = dealBean.getCustomerList();
for (Customer customer : customerList) {
if (customerID.equals(String.valueOf(customer.getId()))) {
return customer;
}
}
}
return null;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object obj) {
if (obj != null) {
return String.valueOf(((Customer)obj).getId());
}
return null;
}
}
XHTML
Customer : <h:selectOneMenu id="customer" value="#{dealBean.deal.customer}">
<f:converter converterId="customerConverter" />
<f:selectItems value="#{dealBean.customerList}" var="cus"
itemLabel="#{cus.name}" itemValue="#{cus}" />
</h:selectOneMenu>
When the managed bean is in request or session scope, the Customer pojo is set correctly to Deal pojo. The problem is when the managed bean is in View scope, the Customer pojo is set to Deal pojo as NULL.
I am using JSF 2.2.0
Thanks much for the help in advance.

It's not the converter, is the view scoped the one broken:
Since you're using JSF tags, you cannot use #ViewScoped annotation, because it was removed from specification and recovered only for CDI usage. You could use omnifaces view scoped or the components of apache myFaces (I personally recommend omnifaces).
You can confirm this creating a
System.out.print("Creating");
in the constructor and checking how is called each Ajax request, so the bean is not recovered and since is marked as view and is a partial request, the values are not setted again (unless you send all the form, which is not a nice solution), other workaround could be making the bean request and recover all the data each request, making it Session (but will be alive for the session), or the #ConvesationScoped, in which you'll have to destroy and start the conversation manually.
Again, my first recommendation could be change to a Java ee server compliant and use the CDI annotations since JSF are being depreciated and not updated anymore

Related

Show how many Users logged in with JSF

i trie to run this code
#ManagedBean
#ApplicationScoped
public class Controller implements Serializable {
private static final long serialVersionUID = 1L;
private Benutzer benutzer;
private List<Erfasst> bisherErfasst = new ArrayList<Erfasst>();
private EntityManagerFactory emf = Persistence
.createEntityManagerFactory("CP Kontrolle");
private static Controller instance = new Controller();
public Benutzer getBenutzer() {
return benutzer;
}
public boolean anmelden(String email, int kdnr) {
EntityManager em = emf.createEntityManager();
Query query = em
.createQuery("SELECT b FROM Benutzer b WHERE b.email = :email AND b.kdnr = :kdnr");
query.setParameter("email", email);
query.setParameter("kdnr", kdnr);
List<Benutzer> liste = query.getResultList();
em.close();
if (liste.size() == 1) {
benutzer = liste.get(0);
AngemeldeteBenutzer.getAb().hinzufuegen(benutzer);
return true;
} else {
return false;
}
}
public static Controller getInstance() {
return instance;
}
[....]
}
}
The above code is my ControllerBean. From the Login-Form, user data will be checked in the "anmelden" Class and return true or false if it was successfully.If successfully, the user will be store into a list, as you can see.
#ManagedBean
#ApplicationScoped
public class AngemeldeteBenutzer implements Serializable {
private static final long serialVersionUID = 1L;
private List<Benutzer> online = new LinkedList<Benutzer>();
private static AngemeldeteBenutzer ab = new AngemeldeteBenutzer();
public static AngemeldeteBenutzer getAb() {
return ab;
}
public List<Benutzer> getOnline() {
return online;
}
public void hinzufuegen(Benutzer benutzer) {
online.add(benutzer);
}
}
This is my other Bean, which store the successfully logged user into a list.
Now i want to list all user into my table, but my table is still empty. No errors!
<h:panelGrid columns="2" id="onlinePanel" >
<h:dataTable value="#{angemeldeteBenutzer.online}" var="on">
<h:column>
<f:facet name="header">Email</f:facet>
<h:outputText value="#{on.email}"></h:outputText>
</h:column>
</h:dataTable>
</h:panelGrid>
The mistake is here:
private static Controller instance = new Controller();
public static Controller getInstance() {
return instance;
}
private static AngemeldeteBenutzer ab = new AngemeldeteBenutzer();
public static AngemeldeteBenutzer getAb() {
return ab;
}
You seem to have missed the point of a bean management framework with dependency injection support. You seem to be expecting that #{angemeldeteBenutzer} in the JSF page is referring exactly the same instance as you manually created there with new operator and are filling with users.
This is Wrong! You have there two instances of the class, one automatically created by JSF and available via #{angemeldeteBenutzer} and another one manually created by yourself and available via that getAb() method only.
Get rid of all those static fields and methods. They don't belong there. Instead, use #ManagedProperty to let JSF inject managed beans in each other. Add this code to the Controller class.
#ManagedProperty("#{angemeldeteBenutzer}")
private AngemeldeteBenutzer ab;
public AngemeldeteBenutzer getAb() {
return ab;
}
public void setAb(AngemeldeteBenutzer ab) {
this.ab = ab;
}
And replace in the same Controller class this line
AngemeldeteBenutzer.getAb().hinzufuegen(benutzer);
by
ab.hinzufuegen(benutzer);
Note: if you're already on Java EE 7, consider using CDI #Named instead of JSF #ManagedBean. When injecting via #Inject instead of #ManagedProperty, you don't need those ugly getter/setter anymore.
#Named
#ApplicationScoped
public class AngemeldeteBenutzer {
}
#Named
#ApplicationScoped
public class Controller {
#Inject
private AngemeldeteBenutzer ab;
}
Unrelated to the concrete problem, the Controller doesn't seem to be a legit application scoped bean. It looks too much like a view scoped bean due that view-specific variables and business logic. Make sure you understand the scopes: 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?

Can I Put Extra Parameters in Backing Bean's Getters and Setters in JSF?

I'm playing around with genericizing some JSF pages. One of the features that's been requested is making them fieldname-agnostic -- passing in fieldnames as parameters rather than having them bound to specific getters/setters in the backing bean.
So instead of binding a specific field like this:
<custom:editor value="#{backingViewBean.editorValue}" />
... to the back-end methods like these:
public String getEditorValue() ...
public void setEditorValue(String editorValue) ...
... I'm trying to bind it to back-end methods like these:
public String getFieldValue(String fieldName) ...
public void setFieldValue(String fieldName, String fieldValue) ...
Is there some elegant way I can do this with the value attribute mimicking how getters and setters usually behave? Or does this approach require more complexity than that?
For me it looks like you are searching for a ways to set one pair of getter and setter for all your variables inside your bean so if you are to 'lazy' them for alle your data in your managed bean you can implement java.util.Map into the bean then you can overwrite the put and get Methode like this:
public class DataBean implements Serializable, java.util.Map {
public class DataBean implements Serializable, java.util.Map {
private static final long serialVersionUID = 1L;
private final HashMap<String, Object> BeanData;
public DataBean(){
BeanData = new HashMap<String,Object>();
}
#Override
public Object get(final Object key) {
if (key == null) {throw new IllegalArgumentException("Key cannot be null.");}
return BeanData.get(key);
}
#Override
public Object put(final Object key, final Object value) {
if (key == null) {throw new IllegalArgumentException("Key cannot be null.");}
BeanData.put(key.toString(), value);
return null;
}
This will allow you to store values in your bean without creating getter and setter for every var in your bean:
<h:inputText value="#{dataBean.key1}"></h:inputText>
<h:outputLabel value="#{dataBean.key1}"></h:outputLabel>
<h:inputText value="#{dataBean.key2}"></h:inputText>
<h:outputLabel value="#{dataBean.key2}"></h:outputLabel>

How to access property of one managed bean in another managed bean

I have a managed bean (SessionScope as follow)
#ManagedBean(name="login")
#SessionScoped
public class Login implements Serializable {
private String userSession;
public Login(){
}
}
In this managedbean, somewhere in the login function, i store the email as a session.
I have another managed bean called ChangePassword (ViewScoped). I need to access the value of the email which is stored in the userSession.
The reason of doing so is that i need to find out the current userSession(email) before i can complete the change password function. (Need change password for that specific email)
How do i do so? New to JSF, appreciate any help!
Just inject the one bean as a managed property of the other bean.
#ManagedBean
#ViewScoped
public class ChangePassword {
#ManagedProperty("#{login}")
private Login login; // +setter (no getter!)
public void submit() {
// ... (the login bean is available here)
}
// ...
}
See also:
Communication in JSF 2.0 - Injecting managed beans in each other
In JSF2, I usually use a method like this:
public static Object getSessionObject(String objName) {
FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext extCtx = ctx.getExternalContext();
Map<String, Object> sessionMap = extCtx.getSessionMap();
return sessionMap.get(objName);
}
The input parameter is the name of your bean.
if your session scoped bean is like this :
#ManagedBean(name="login")
#SessionScoped
public class Login implements Serializable {
private String userSession;
public Login(){
}
}
you can access the values of this bean like :
#ManagedBean(name="changePassword")
#ViewScoped
public class ChangePassword implements Serializable {
#ManagedProperty(value="#{login.userSession}")
private String userSession;
public ChangePassword (){
}
}
public static Object getSessionObj(String id) {
return FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(id);
}
public static void setSessionObj(String id,Object obj){
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(id, obj);
}
Add them in your managed bean :

ManagedProperty not injected in #FacesConverter

I'm trying to inject a ManagedBean in my FacesConverted the following way:
#ManagedBean
#RequestScoped
#FacesConverter(forClass = Group.class)
public class GroupConverter implements Converter {
#ManagedProperty("#{groupService}")
private GroupService groupService;
#Override
public Group getAsObject(FacesContext context, UIComponent arg1,
String groupName) {
return groupService.findGroupByName(groupName);
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object group) {
return ((Group) group).getName();
}
public GroupService getGroupService() {
return groupService;
}
public void setGroupService(GroupService groupService) {
this.groupService = groupService;
}
}
The problem is that groupService isn't being injected and I get a NullPointerEx. Shouldn't it be autowired automatically since it's also a ManagedBean? It all works when I change "getAsObject" to "return new Group();" obviously.
Any ideas?
It is likely that you are not resolving the managed bean name.
#ManagedBean(name = "myConverter")
#RequestScoped
#FacesConverter(value = "myConverter")
public class MyConverter implements Converter {
For example, consider these two components:
<h:inputText converter="myConverter" value="#{foo.prop}" />
<h:inputText converter="#{myConverter}" value="#{bar.prop}" />
When the converter is set on the first component, it will be created by Application.createConverter. A converter is not a managed bean. The same rules apply if you match a converter by type.
In the second component, a value expression is used to return a class that implements Converter. This uses the usual managed bean mechanisms. In this case, the #FacesConverter annotation is irrelevant.

Resources