#Named("cc") not being constructed when referenced in JSF page - jsf

I have a JSF file (characters.xhtml) that is not rendering properly, and I suspect it has to do with the backing bean (CharactersController) not being instantiated. I can render the page (meaning all the HTML code is generated), but without any details contained by the bean, such as my "msg" property data being displayed. At minimum, "msg" should display "hello", or ideally "list size is: 0".
Ultimately, I want to pull data from my database with this bean (the DAO itself works separately in a REST resource, so I don't think that is the problem). But as it stands, my CharactersController bean does not appear to be instantiating. I have a #PostConstruct that should log an output when the bean is created, but it is not appearing anywhere, which is why I suspect issue there.
On a related note, I have another managed bean for a different JSF file that does load correctly. It is also ViewScoped. I am able to see the log from its respective #PostConstruct. (From other older posts, ViewScoped may have been a culprit, but it doesn't seem to be here since it does work for my other bean.)
Lastly, I get a null pointer error if I try creating a component referencing any methods. I bring this up because I tried loading my data via <f:viewAction> tag.
Other details:
I'm using Jakarta EE 9, Glassfish 6.1 RC1, Java 11, IntelliJ, Maven build.
I do have getters and setters for all fields in CharactersController except for "dao". I omitted the code for brevity.
CharactersController - Managed Bean
import jakarta.annotation.PostConstruct;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import xxx.dao.CharactersDao;
import xxx.CharactersEntity;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
#Named("cc")
#ViewScoped
public class CharactersController implements Serializable {
private static final long serialVersionUID = 1L;
public CharactersController() {
}
#Inject
private CharactersDao dao;
private List<CharactersEntity> chars;
private CharactersEntity newChar;
private String msg = "hello";
private static final Logger logger = Logger.getLogger("CharactersController");
#PostConstruct
public void init(){
chars = dao.getAll();
msg = "list size is: " + chars.size();
logger.log(Level.INFO, "CC constructed: " + msg);
}
characters.xhtml - facelet
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
>
<h:head>
</h:head>
<h:body>
<ui:composition template="/WEB-INF/templates/adminTemplate.xhtml">
<ui:define name="dataTable">
<h3>Msg: <h:outputText value="#{cc.msg}"/></h3>
<h:form>
<h:dataTable value="#{cc.chars}" var="char">
<f:facet name="header">
<h:outputText value="Characters"/>
</f:facet>
<h:column>
<f:facet name="header">
<h:outputText value="ID"/>
</f:facet>
<h:outputText value="#{char.characterId}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Avatar"/>
</f:facet>
<h:outputText value="#{char.avatar}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:outputText value="#{char.name}"/>
</h:column>
</h:dataTable>
</h:form>
</ui:define>
</ui:composition>
</h:body>
</html>
HTML output
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head id="j_idt2">
<title>RPG Admin</title></head><body>
<header>
<h1>admin</h1>
</header>
<nav>
<div class="admin-nav-row">
<div>Home
</div>
<div>Characters
</div>
</div>
</nav>
<main>
<h3>Msg: </h3>
<form id="j_idt13" name="j_idt13" method="post" action="/rpg_xe/admin/characters.xhtml" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_idt13" value="j_idt13" />
<table>
<thead>
<tr><th colspan="3" scope="colgroup">Characters</th></tr>
<tr>
<th scope="col">ID</th>
<th scope="col">Avatar</th>
<th scope="col">Name</th>
</tr>
</thead>
<tbody>
<tr><td></td><td></td><td></td></tr></tbody>
</table>
<input type="hidden" name="jakarta.faces.ViewState" id="j_id1:jakarta.faces.ViewState:0" value="-7288672771663122896:-6269118426931924221" autocomplete="off" />
</form>
</main>
<footer>footer</footer></body>
</html>

Ok, now that you have confirmed:
"cc" cannot be used as a managed bean name because there is a conflict with builtin object "cc" (Composite Component).
"The word cc in JavaServer Faces is a reserved word for composite components."
https://javaee.github.io/tutorial/jsf-facelets005.html

Related

Commandbuttons problems

I have very strange problem. I can't use function in second button.
Steps:
1. Write forename and surename.
2. Click "find" button. Result: items in datatable.
3. Click "TEMPPP" only refresh page.
I have to use function sendUserInformation()
Administrator.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ace="http://www.icefaces.org/icefaces/components"
template="/WEB-INF/templates/template.xhtml">
<ui:define name="menuItems">
</ui:define>
<ui:define name="logedContent">
<h:form id="form1t">
<center><h:outputLabel value="#{msg.find_employee}"/></center>
<table class="tableGeneral">
<tr>
<td><h:outputLabel value="#{msg.forename}*"/></td>
<td>
<h:inputText id="name1" value="#{administrationController.forename}">
<f:validator validatorId="DefaultStringValidator"/>
</h:inputText>
</td>
<td>
<h:message styleClass="error" for="name1"/>
</td>
</tr>
<tr>
<td><h:outputLabel value="#{msg.surename}*"/></td>
<td>
<h:inputText id="name2" value="#{administrationController.surename}">
<f:validator validatorId="DefaultStringValidator"/>
</h:inputText>
</td>
<td>
<h:message styleClass="error" for="name2"/>
</td>
</tr>
<tr>
<td colspan="2">
<h:commandButton styleClass="buttonGeneral" value="#{msg.find}" >
<!-- <f:ajax event="click" execute="name1 name2" render=":form1t:form2:tab" listener="#{administrationController.find_employee()}"/> -->
<f:ajax event="click" execute="name1 name2" render="#all" listener="#{administrationController.find_employee()}"/>
</h:commandButton>
</td>
</tr>
</table>
</h:form>
<hr/>
<br/>
<h:form id="form2">
<center><h:outputLabel value="#{msg.found}"/></center>
<h:dataTable id="tab" value="#{administrationController.foundUsers}" styleClass="tableGeneral" var="o">
<h:column>
<f:facet name="header"><h:outputLabel value="#{msg.forename}"/></f:facet>
<h:outputText value="#{o.forename}"/>
</h:column>
<h:column>
<f:facet name="header"><h:outputLabel value="#{msg.surename}"/></f:facet>
<h:outputText value="#{o.surename}"/>
</h:column>
<h:column>
<f:facet name="header"><h:outputLabel value="#{msg.job}"/></f:facet>
<h:outputText value="#{o.job}"/>
</h:column>
<h:column>
<f:facet name="header"><h:outputLabel value="#{msg.user}"/></f:facet>
<h:outputText value="#{o.login}"/>
</h:column>
<h:column>
<f:facet name="header"><h:outputLabel value="#{msg.activated}"/></f:facet>
<h:outputText value="#{msg.yes}" rendered="#{o.activated}"/>
<h:outputText value="#{msg.no}" rendered="#{!o.activated}"/>
</h:column>
<h:column>
<!-- <h:commandButton value="TEMPPP #{o.id}" action="#{administrationController.sendUserInformation(o.id)}"/> -->
<!--
<h:commandButton value="TEMPPP #{o.id}" action="#{administrationController.sendUserInformation()}">
<f:param name="id" value="#{o.id}"/>
</h:commandButton>
-->
<h:commandButton value="TEMPPP #{o.id}" action="#{administrationController.sendUserInformation(o.id)}" styleClass="buttonGeneral" >
</h:commandButton>
<!--
<h:button value="TEMPPP #{o.id}" outcome="userInformation.xhtml">
<f:param name="id" value="#{o.id}"/>
</h:button>
-->
</h:column>
</h:dataTable>
</h:form>
</ui:define>
</ui:composition>
AdministrationController
package controller;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.context.FacesContext;
import others.MenuBars;
import database.Queries;
import users.User;
public class AdministrationController implements Serializable {
private static final long serialVersionUID = -2151888463865423931L;
private Queries queries = (Queries) FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().get("queries");
private MenuBars menubars = (MenuBars)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("menuBars");
private List<User> users = new ArrayList<User>();
private List<User> foundUsers = new ArrayList<User>();
private String forename = "";
private String surename = "";
public AdministrationController(){
System.out.println("AdministrationController()");
users = queries.getAllUsers();
}
/*
public void tempUser(ValueChangeEvent event){
System.out.println(event.getNewValue().getClass());
User u = (User) event.getNewValue();
//TODO
System.out.println("idz do informacji o uzytkowniku"+u.name());
}*/
public String getForename() {
return forename;
}
public void setForename(String forename) {
this.forename = forename;
}
public String getSurename() {
return surename;
}
public void setSurename(String surename) {
this.surename = surename;
}
public void find_employee(){
System.out.println("find_employee()");
foundUsers.clear();
for(User u: users){
if(u.getForename().equalsIgnoreCase(getForename()) && u.getSurename().equalsIgnoreCase(getSurename())){
foundUsers.add(u);
}
}
}
public List<User> getFoundUsers() {
return foundUsers;
}
public void setFoundUsers(List<User> foundUsers) {
this.foundUsers = foundUsers;
}
public String sendUserInformation(String id){
System.out.println("sendUserInformation; id = "+id);
menubars.addToMap("id", id);
return "userInformation.xhtml";
}
}
SOLVED!
f:ajax was needed (and probably viewscope)
<h:commandButton action="#{administrationController.sendUserInformation(o.id)}" styleClass="buttonGeneral" value="TEMP #{o.id}">
<f:ajax/>
</h:commandButton>
Assuming that your AdministrationController bean is #RequestScoped (since you haven't specified it's scope), then the data in your <h:dataTable> will be reloaded per every request in the same view. This means, when you select
<h:commandButton value="TEMPPP #{o.id}" action="#{administrationController.sendUserInformation(o.id)}"/>
This will fire a new AdministrationController and the data in the List will be lost, which will break your action since o.id is not available anymore.
To solve this, use a wider scope like #ViewScoped at least.
#ManagedBean
#ViewScoped
public class AdministrationController implements Serializable {
//rest of your code
}

Form behaviour when using ajax to include a XHTML file

I'm learning about JSF and am trying to do a tabbed pane following this tutorial:
Tab manager using Ajax and JSF
I have managed to get the tab switch working. Now I want to include a form defined in another XHTML file as tab for this tabbed pane in which there's a dataTable with a commandButton to delete the selected row, called clientes.xhtml. If I navigate directly to this page then delete button works as expected. But when I include this page within contentForm it shows as expected but delete button doesn't do what is supposed to do, it just refresh the current page but no row is deleted.
This is what I have so far:
welcome.xhtml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns="http://www.w3.org/1999/xhtml"
template="./templates/BasicTemplate.xhtml">
<ui:define name="menu_bar">
<h:form id="formMenu">
<ul id="menu-list">
<li><h:commandLink value="Home">
<f:ajax event="click" render=":contentForm" listener="#{tabViewManagedBean.setTabIndex(0)}" />
</h:commandLink></li>
<li><h:commandLink value="Clientes">
<f:ajax event="click" render=":contentForm" listener="#{tabViewManagedBean.setTabIndex(1)}" />
</h:commandLink></li>
<li><h:commandLink value="Proveedores">
<f:ajax event="click" render=":contentForm" listener="#{tabViewManagedBean.setTabIndex(2)}" />
</h:commandLink></li>
</ul>
</h:form>
</ui:define>
<ui:define name="content">
<h:form id="contentForm">
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 0}">
<h1>Hi there!</h1>
<hr />
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 1}">
<ui:include src="clientes.xhtml" />
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 2}">
<ui:include src="proveedores.xhtml" />
</h:panelGroup>
</h:form>
</ui:define>
</ui:composition>
clientes.xhtml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns="http://www.w3.org/1999/xhtml">
<h:form>
<h:dataTable id="dataTable" value="#{clientesManagedBean.listaClientes}" var="cliente">
<h:column>
<f:facet name="header">
<h:outputText value="Id" />
</f:facet>
<h:outputText value="#{cliente.idCliente}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Fecha de ingreso" />
</f:facet>
<h:outputText value="#{cliente.fechaIngreso}">
<f:convertDateTime pattern="dd/MM/yyyy"/>
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Nombre" />
</f:facet>
<h:outputText value="#{cliente.nombre}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Domicilio" />
</f:facet>
<h:outputText value="#{cliente.domicilio}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Teléfono" />
</f:facet>
<h:outputText value="#{cliente.telefono}" />
</h:column>
<h:column>
<f:facet name="header" />
<h:commandButton image="./resources/css/delete_16.png" action="#{clientesManagedBean.eliminarCliente(cliente)}"/>
</h:column>
</h:dataTable>
</h:form>
</ui:composition>
Edit 1
Here is the ClientesManagedBean code:
ClientesManagedBean.java
import beans.interfaces.IClientesBeanLocal;
import domain.entities.ClienteJpa;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.view.ViewScoped;
#ManagedBean
#ViewScoped
public class ClientesManagedBean {
#EJB(beanName = "ClientesBeanJpa")
private IClientesBeanLocal clientesBeanLocal;
private List<ClienteJpa> listaClientes;
private ClienteJpa cliente;
#PostConstruct
public void init() {
listaClientes = new ArrayList<>();
listaClientes.addAll(clientesBeanLocal.getTodos());
}
public List<ClienteJpa> getListaClientes() {
return listaClientes;
}
public ClienteJpa getCliente() {
return cliente;
}
public void eliminarCliente(ClienteJpa cliente) {
if(clientesBeanLocal.eliminar(cliente) == IClientesBeanLocal.EXITO) {
listaClientes.remove(cliente);
}
}
}
And ClientesBeanJpa session bean, just in case:
ClientesBeanJpa.java
import beans.interfaces.IClientesBeanLocal;
import domain.entities.ClienteJpa;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#Stateless(name = "ClientesBeanJpa")
public class ClientesBeanJpa implements IClientesBeanLocal {
#PersistenceContext(unitName = "CursoJ2eePU")
private EntityManager entityManager;
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public int eliminar(ClienteJpa cliente) {
if(entityManager == null) {
String error = "Error al inyectar EntityManager en la clase " + getClass().getCanonicalName();
throw new ExceptionInInitializerError(error);
} else {
ClienteJpa clienteAEliminar = entityManager.getReference(ClienteJpa.class, cliente.getIdCliente());
entityManager.remove(clienteAEliminar);
return EXITO;
}
}
}
Edit 2
Based on #Luiggi's suggestion I've tested if ClientesManagedBean#eliminar(cliente) method is even called and I've found this out:
If tabIndex property is set to 1 by default, then clientes.xhtml is rendered and it works as expected.
If tabIndex property is set to another value and then navigate to tab 1, then eliminar(cliente) is not even called.
Including TabViewManagedBean code just in case.
TabViewManagedBean.java
import javax.faces.bean.ManagedBean;
import javax.faces.view.ViewScoped;
#ManagedBean
#ViewScoped
public class TabViewManagedBean {
private Integer tabIndex = 0;
/*
* If I set tabIndex to 1 then clientes.xhtml is rendered by default
* and everithing works as expected.
* But if I set this property to 0 and then navigate to tab 1 then it
* behaves as described.
*/
public TabViewManagedBean() {
super();
}
public Integer getTabIndex() {
return tabIndex;
}
public void setTabIndex(Integer tabIndex) {
this.tabIndex = tabIndex;
}
}
The problem is that you're nesting <form>, which is invalid HTML. This can be noted by this code:
welcome.xhtml:
<ui:define name="content">
<h:form id="contentForm">
<!-- code here... -->
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 1}">
<!-- including source of clientes.xhtml page -->
<ui:include src="clientes.xhtml" />
</h:panelGroup>
<!-- code here... -->
</h:form>
</ui:define>
And in clientes.xhtml you have:
<h:form>
<h:dataTable id="dataTable" value="#{clientesManagedBean.listaClientes}" var="cliente">
<!-- more code... -->
</h:dataTable>
<h:form>
Which ends in this way:
<h:form id="contentForm">
<!-- code here... -->
<h:panelGroup layout="block" rendered="#{tabViewManagedBean.tabIndex == 1}">
<h:form>
<h:dataTable id="dataTable" value="#{clientesManagedBean.listaClientes}" var="cliente">
<!-- more code... -->
</h:dataTable>
<h:form>
</h:panelGroup>
<!-- code here... -->
</h:form>
Decide where to define the <h:form> to not have nested forms. IMO you should define the <h:form> in the narrowest possible scope, which in this case will be in clientex.xhtml page only (and in the pages to include).
More info:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated (your scenario resembles case 2 of the accepted answer)

Error due to same client ID of components in JSF Data Table

I have a JSF application with a Data Table. Each row has a 'commandLink'. When the commandLink of a row is clicked then row data must be displayed on console.
I am getting an error when I click on the commandLink, the error is as follows:
component with duplicate id "dataTable1:col1" found
viewId=/UserHome.xhtml
location=E:\workspaces_eclipse\webService\.metadata\.plugins \org.eclipse.wst.server.core\tmp2\wtpwebapps\JSF_Demo\UserHome.xhtml
phaseId=RENDER_RESPONSE(6)
Caused by:
java.lang.IllegalStateException - component with duplicate id "dataTable1:col1" found
at org.apache.myfaces.view.facelets.compiler.CheckDuplicateIdFaceletUtils.checkIds(CheckDuplic ateIdFaceletUtils.java:100)
The error shows that components have same IDs, however I tried to give different 'id' to each element of the data table.
The source code of JSF file 'UserHome.xhtml' is as follows:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org /TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Resource Net 1.0</title>
<h:outputStylesheet library="css" name="table-style.css"></h:outputStylesheet>
</h:head>
<h:body>
<div align="center">
<table width="90%" height="100%" border="0" style="cellspacing:0; border-radius:10px ;box-shadow: 0px 0px 15px 10px #888888">
<tr>
<td>
<h2><div align="center">Resource Net 1.0</div></h2>
</td>
</tr>
<tr>
<td>
2. Generated by Map :
<h:selectOneMenu value="#{userHomeListener.favCoffee2}">
<f:selectItems value="#{userHomeListener.allDomains}" />
</h:selectOneMenu>
</td>
</tr>
<tr>
<td>
<h:dataTable value="#{userHomeListener.documents}" var="doc"
binding="#{userHomeListener.documentsTable}"
id="dataTable1"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row"
border="1">
<h:column id="col1">
<f:facet name="header1">Document ID</f:facet>
#{doc.docID}
</h:column>
<h:column id="col2">
<f:facet name="header2">Document Name</f:facet>
#{doc.docName}
</h:column>
<h:column id="col3">
<f:facet name="header3">Document Link</f:facet>
<h:form id="form1">
<h:commandLink id="link" value="#{doc.docLink}" action="#{userHomeListener.getRowData}"></h:commandLink>
</h:form>
</h:column>
<h:column id="col4">
<f:facet name="header4">Upload Date</f:facet>
#{doc.uploadDate}
</h:column>
</h:dataTable>
<h:commandButton value="get row data" ></h:commandButton>
</td>
</tr>
</table>
</div>
</h:body>
Is there some problem with my code? Kindly suggest solutions to this issue.
Thanks in advance.
The binding attribute of the <h:dataTable> is the suspect here. It may lead to this kind of problems when the bean is in a too broad scope and/or when you're doing "wrong things" in the getter/setter of that attribute.
Putting the bean in the request scope and/or looking for alternative ways so that you can get rid of the binding altogether should solve this problem.
The combination of the binding attribute and the name of the command link action method getRowData suggests that you're merely using it to get the current table row. This was indeed the way when using the old JSF 1.x, but not anymore when using the new JSF 2.x. This can be done much better and simpler when you're running a Servlet 3.0 / EL 2.2 capable container (Tomcat 7, Glassfish 3, etc).
<h:dataTable value="#{userHomeListener.documents}" var="doc">
<h:column>
<h:form>
<h:commandLink value="#{doc.docLink}" action="#{userHomeListener.getRowData(doc)}" />
</h:form>
</h:column>
</h:dataTable>
with
public void getRowData(Document doc) {
// ...
}
You see, you can just pass the #{doc} straight as method argument.
See also:
How can I pass selected row to commandLink inside dataTable?
Recommended JSF 2.0 CRUD frameworks

JSTL c:forEach doesn't work inside a JSF h:dataTable

I have a problem with a JSF project.
GlassFish Server 3.1.2
Mojarra 2.1.6
I'm trying to show a table containing the request header fields. Therefor I've written this managed bean:
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
#ManagedBean
#RequestScoped
public class RequestHeader extends LinkedHashMap<String, List<String>> {
private List<String> keys;
#PostConstruct
public void init() {
final HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
keys = Collections.list(request.getHeaderNames());
for (final String key : keys) {
final List<String> value = Collections.list(request.getHeaders(key));
final List<String> oldValue = get(key);
if (oldValue == null) {
put(key, value);
} else {
oldValue.addAll(value);
}
}
}
public List<String> keys() {
return keys;
}
}
This is my JSF page:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>HTTP request headers</title>
</h:head>
<h:body>
<h:dataTable value="#{requestHeader.keys()}" var="k" border="1">
<f:facet name="header">HTTP request headers</f:facet>
<h:column>
<f:facet name="header">Key</f:facet>
<h:outputText value="#{k}" />
</h:column>
<h:column>
<f:facet name="header">Value</f:facet>
<!-- This forEach seems to be ignored. -->
<c:forEach items="#{requestHeader[k]}" var="v">
<h:outputText value="#{v}" /><br />
</c:forEach>
</h:column>
</h:dataTable>
</h:body>
</html>
Instead of having the values in the second column of the table, the cells are empty:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTTP request headers</title>
</head>
<body>
<table border="1">
<thead>
<tr><th colspan="2" scope="colgroup">HTTP request headers</th></tr>
<tr>
<th scope="col">Key</th>
<th scope="col">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>user-agent</td>
<td></td>
</tr>
<tr>
<td>host</td>
<td></td>
</tr>
<tr>
<td>accept</td>
<td></td>
</tr>
<tr>
<td>accept-language</td>
<td></td>
</tr>
<tr>
<td>accept-encoding</td>
<td></td>
</tr>
<tr>
<td>cache-control</td>
<td></td>
</tr>
<tr>
<td>connection</td>
<td></td>
</tr>
</tbody>
</table>
</body>
</html>
I did several tests. <h:outputText value="#{requestHeader[k]}" /> and c:forEach on other lists will work.
Why won't it work this way?
Taghandlers like JSTL tags runs during view build time, while the UI components like JSF <h:xxx> tags runs during view render time. So they doesn't run in sync as you'd expect from the coding. In your code, at the moment the <c:forEach> runs, the <h:dataTable> hasn't run at all and thus its var attribute is not been set and thus #{k} is not available when the <c:forEach> runs and thus it retrieves an empty/non-existent collection.
You need an UI component instead if you want a nested iteration inside another UI component. One of them is Facelets <ui:repeat>.
<ui:repeat value="#{requestHeader[k]}" var="v">
<h:outputText value="#{v}" /><br />
</ui:repeat>
In case you're still on JSF 1.x, use Tomahawk's <t:dataList> instead, or simply another <h:dataTable>.
See also:
JSTL in JSF2 Facelets... makes sense?
JSTL c:if doesn't work inside a JSF h:dataTable
Unrelated to the concrete problem: you don't need a backing bean here at all. All request headers are already as a Map available by the implicit EL object #{header}.
All with all, your approach can be simplified as follows, without any backing bean:
<h:dataTable value="#{header.keySet().toArray()}" var="headerName" border="1">
<f:facet name="header">HTTP request headers</f:facet>
<h:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#{headerName}" />
</h:column>
<h:column>
<f:facet name="header">Value</f:facet>
<ui:repeat value="#{header[headerName]}" var="headerValue">
<h:outputText value="#{headerValue}" /><br />
</ui:repeat>
</h:column>
</h:dataTable>
See also:
Implicit EL objects
Try to use ui:repeat tag instead of c:forEach.See this link for why ui:repeat use instead of c:forEach.

jsf immediate="true" regarding binding to session bean

I have a listing page that goes to an add page. The add page has a name textbox whose value is bound to a session scoped bean.
The listing page has an add button that goes via an action method to the add page. This action method clears the object that the name textbox is bound to.
I also have a cancel button on the add page, which is bound to an action method that again clears the value that the name textbox is bound to.
If nothing is set to immediate, this all works fine.
However, if I set the cancel button to immediate, if I enter values in the name field, and then click cancel, the action method is fired and clears the object in the backing bean and goes to the listing page. If I then click add, the action method clears the object again (ignore if it's best method or not) and then goes to the add page. I would now expect the add page's name textbox to be empty, but it's not?! Surely, since the add button is not immediate, the values should be re-bound and empty?
Below is the relevant XHTML for the add button on the listing page
<h:commandButton id="addButton"
value="Add"
action="#{myBean.gotoAdd}"/>
Below is the relevant XHTML for the input box on the add page (myBean is session scoped), followed by that of the cancel button on the add page.:
<h:inputText id="newName"
value="#{myBean.newObject.name}"
binding="#{myBean.newNameInput}"
styleClass="name" />
<h:commandButton id="cancelButton"
value="Cancel" immediate="true"
action="#{myBean.cancelAdd}"
onclick="return confirm('You sure?');"/>
I almost never use the binding property of tags, except for when I need to identify which item of a list has had an action fired on it, so I am not particularly well-informed about its uses. But I know that without using binding your code would most likely work as you expected, so my expectation is that whatever javax.faces.component.UIxxx object you are binding to isn't getting reset correctly.
I'm having very similar problems right now.
Besides removing the binding and/or immediate attribute, try calling setSubmittedValue() on component with binding from action called upon click on 'add' button.
Alas, even if it helps you, you would still have to do it in any action that can lead to displaying same component after cancel.
That's why I'm still trying to figure out some better solution...
If you use immediate="true" then the value will be kept, this is how the parameter works. You should take a look at the following links:
http://wiki.apache.org/myfaces/How_The_Immediate_Attribute_Works
http://wiki.apache.org/myfaces/ClearInputComponents
Ok, here's an example that I did from scratch. I have two cancel buttons, one that is immediate, and one that isn't. Example of steps to reproduce:
Go to james-list page and click Add
The add page displays with empty fields. Enter values for all fields and click Add.
The listing page displays and is updated to include the new person. Click Add.
The add page displays with empty fields. Enter values for all fields and Click Cancel (Immediate)
The listing page displays and is unchanged. Click Add.
The add page displays however the fields are not empty as I would expect. Click Cancel.
The listing page displays and is unchanged. Click Add.
The add page displays and NOW the fields are not empty.
James.java:
package com.jamiebarrow;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
#ManagedBean
#SessionScoped
public class James {
private UIComponent idComponent;
private UIComponent firstNameComponent;
private UIComponent lastNameComponent;
public UIComponent getIdComponent() {
return idComponent;
}
public void setIdComponent(UIComponent idComponent) {
this.idComponent = idComponent;
}
public UIComponent getFirstNameComponent() {
return firstNameComponent;
}
public void setFirstNameComponent(UIComponent firstNameComponent) {
this.firstNameComponent = firstNameComponent;
}
public UIComponent getLastNameComponent() {
return lastNameComponent;
}
public void setLastNameComponent(UIComponent lastNameComponent) {
this.lastNameComponent = lastNameComponent;
}
private List<Person> personResults;
private Person person;
public James() {
personResults = new ArrayList();
personResults.add(new PersonBuilder(1, "Bob", "Uncle").build());
personResults.add(new PersonBuilder(2, "Jack", "Black").build());
}
public List<Person> getPersonResults() {
return personResults;
}
public void setPersonResults(List<Person> personResults) {
this.personResults = personResults;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
private void clearPerson() {
person = new PersonBuilder().build();
}
public String gotoList() {
return "james-list";
}
public String gotoAdd() {
clearPerson();
return "james-add";
}
public String cancelAdd() {
clearPerson();
return gotoList();
}
public String addPerson() {
personResults.add(person);
return gotoList();
}
}
james-list.xhtml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>list page</title>
</h:head>
<body>
<div class="container">
<div class="content">
<h:messages showSummary="true" showDetail="false" errorClass="error" infoClass="info"
warnClass="warn"/>
<h:form>
<h:dataTable value="#{james.personResults}" var="person">
<h:column>
<f:facet name="header">Id</f:facet>
<h:outputText value="#{person.id}"/>
</h:column>
<h:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#{person.firstName}"/>
</h:column>
<h:column>
<f:facet name="header">Surname</f:facet>
<h:outputText value="#{person.lastName}"/>
</h:column>
</h:dataTable>
<h:panelGroup layout="block">
<h:commandButton value="Add" action="#{james.gotoAdd}"/>
</h:panelGroup>
</h:form>
</div>
</div>
<ui:debug hotkey="L" rendered="true"/>
</body>
</html>
james-add.xhtml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>add page</title>
</h:head>
<body>
<div class="container">
<div class="content">
<h:messages showSummary="true" showDetail="false" errorClass="error" infoClass="info"
warnClass="warn"/>
<h:form>
<fieldset>
<legend>Add Person</legend>
<h:panelGrid columns="2">
<h:outputLabel for="PersonId" value="Id:"/>
<h:inputText id="PersonId" value="#{james.person.id}" binding="#{james.idComponent}"/>
<h:outputLabel for="PersonFirstName" value="First Name:"/>
<h:inputText id="PersonFirstName" value="#{james.person.firstName}" binding="#{james.firstNameComponent}"/>
<h:outputLabel for="PersonLastName" value="Last Name:"/>
<h:inputText id="PersonLastName" value="#{james.person.lastName}" binding="#{james.lastNameComponent}"/>
</h:panelGrid>
<h:panelGroup layout="block">
<h:commandButton value="Add" action="#{james.addPerson}"/>
<h:commandButton value="Cancel (immediate)" action="#{james.cancelAdd}" immediate="true"/>
<h:commandButton value="Cancel" action="#{james.cancelAdd}"/>
</h:panelGroup>
</fieldset>
</h:form>
</div>
</div>
<ui:debug hotkey="L" rendered="true"/>
</body>
</html>

Resources