JSF 2.0 h:selectManyListbox f:selectItems - always empty - java

I've got a JSF creation form using a selectManyListbox with selectItems inside (it should contain all tags available for projects). The selectItems list though is always empty - when the page renders, there's nothing in the Listbox. Still, the list in the backing bean contains 3 entries (checked that). What am I doing wrong?
The backing bean:
#ManagedBean(name = "createProjectBean")
#RequestScoped
public class CreateProjectBean {
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
private Project project;
private IProjectService projectService;
private FacesContext facesContext;
private MessageFactory mf;
private List<Tag> tags;
public CreateProjectBean() {
project = new Project();
projectService = (IProjectService)ServiceFinder.getInstance()
.findBean("projectService");
mf = new MessageFactory("properties.projects.messages");
tags = projectService.getTags();
}
/* should be the source of tags */
public void setTags(List<Tag> tags) {
this.tags = tags;
}
public List<Tag> getTags() {
return tags;
}
}
And the page:
<f:view>
<h:outputText id="error" rendered="false" />
<h:message styleClass="errorMessage" for="error" />
<h:form id="creationForm" >
<h:panelGrid columns="2" width="420">
/* blah, blah, set name and stuff */
<h:selectManyListbox id="box" value = "#{createProjectBean.project.tags}">
<f:converter converterId="tag" />
<f:selectItems value="#{createProjectBean.tags}"
var="tag"
itemValue="#{tag}"
itemLabel="${tag.name}" />
</h:selectManyListbox>
<f:verbatim><br/></f:verbatim>
<h:commandButton value="Create" styleClass="formButton" action="#{createProjectBean.create}"/>
</h:panelGrid>
</h:form>
</f:view>
I tried to do it per analogia to this page:
http://digitaljoel.wordpress.com/2010/01/11/jsf-2-custom-converter/
The converter I've written is yet to be tested.

Your EL is bogus. You should use the #{} notation everywhere. Replace
<f:selectItems value="#{createProjectBean.tags}"
var="tag"
itemValue="#{tag}"
itemLabel="${tag.name}" />
by
<f:selectItems value="#{createProjectBean.tags}"
var="tag"
itemValue="#{tag}"
itemLabel="#{tag.name}" />

Related

Use of #ManagedProperty in backing component

How can I use #ManagedProperty in backing component?
This is partner selector composite component. The component checks the typed partner code in the database and fills the partner name if code is valid.
The component:
<cc:interface componentType="partnerSelComp">
<cc:attribute name="value" type="java.lang.Long"/>
</cc:interface>
<cc:implementation>
<span id="#{cc.clientId}" style="white-space:nowrap">
<p:inputText id="id" type="hidden" binding="#{cc.partnerId}"/>
<p:inputText id="code" binding="#{cc.code}">
<p:ajax event="blur" update="id code name" listener="#{cc.validate}" />
</p:inputText>
<p:inputText id ="name" disabled="true" binding="#{cc.name}" />
<p:message for="code"/>
</span>
</cc:implementation>
In encodeBegin() I got NPE because service is null:
#FacesComponent("partnerSelComp")
public class PartnerSelComp extends UIInput implements NamingContainer {
private InputText partnerId;
private InputText code;
private InputText name;
#ManagedProperty("#{partnerService}")
private PartnerService service;
#Override
public void encodeBegin(FacesContext context) throws IOException {
Partner p=null;
Long i = (Long) getValue();
if (i != null) {
p = findPartnerById(service.getList(), i);
}
fill( (i==null) , p); // fills the code and name fields
}
...
}
This is the bean I'd like to access. (later it will replaced with a JPA query.)
#ManagedBean(name = "partnerService")
#ApplicationScoped
public class PartnerService {
private List<Partner> list;
public PartnerService() {
list = new ArrayList<>();
list.add( new Partner(1, "A", "Partner A"));
list.add( new Partner(2, "B", "Partner B"));
list.add( new Partner(3, "C", "Partner C"));
list.add( new Partner(4, "D", "Partner D"));
list.add( new Partner(5, "E", "Partner E"));
list.add( new Partner(6, "E", "Partner F"));
}
public List<Partner> getList() {
return list;
}
public void setList(List<Partner> list) {
this.list = list;
}
}
The solution:
The use of the component:
<my:PartnerSelComp value="#{myBean.partnerId}" service="#{partnerService}"/>
The component xhtml:
<cc:interface componentType="partnerSelComp">
<cc:attribute name="value" type="java.lang.Long"/>
<cc:attribute name="service"/>
</cc:interface>
<cc:implementation>
<span id="#{cc.clientId}" style="white-space:nowrap">
<p:inputText id="id" type="hidden" binding="#{cc.partnerId}"/>
<p:inputText id="code" binding="#{cc.code}">
<p:ajax event="blur" update="id code name" listener="#{cc.validate}" />
</p:inputText>
<p:inputText id ="name" disabled="true" binding="#{cc.name}" />
<p:message for="code"/>
</span>
</cc:implementation>
I note, I tried it to pass the reference as attribute default value: <cc:attribute name="service" default="#{partnerService}"/> and <my:PartnerSelComp value="#{myBean.partnerId}"/> I don't know why but it didn't worked me, I had to set service attribute in my:PartnerSelComp as you see above.
And the backing component:
#FacesComponent("partnerSelComp")
public class PartnerSelComp extends UIInput implements NamingContainer {
private InputText partnerId;
private InputText code;
private InputText name;
#ManagedProperty("#{partnerService}")
private PartnerService service;
#Override
public void encodeBegin(FacesContext context) throws IOException {
Partner p=null;
Long i = (Long) getValue();
PartnerService service = getAttributeValue("service", null );
if (i != null) {
p = findPartnerById(service.getList(), i);
}
fill( (i==null) , p); // fills the code and name fields
}
#SuppressWarnings("unchecked")
private <T> T getAttributeValue(String key, T defaultValue) {
T value = (T) getAttributes().get(key);
return (value != null) ? value : defaultValue;
}
...
}
I have to use getAttributes().get(key) to get the reference and cast it to PartnerService.
Thanks for the answers.
Try to load it using the html configuration interface:
<cc:interface componentType="partnerSelComp">
<cc:attribute name="value" type="java.lang.Long"/>
<cc:attribute name="service" default="#{partnerService}"/>
</cc:interface>
This is mostly for the usage inside of html implementation as inside of the bean class you would have to get it manually anyway:
FacesContext.getCurrentInstance().getAttributes().get("service");
Regarding the direct injection into #FacesComponent it is not possible until next version of JSF (2.3).
A possible workaround would be to use "#Named instead of #FacesComponent or if you cannot do that, then try out some of the features of the http://omnifaces.org/ library. It enables injection into #FacesConverter so maybe you could also apply it for this annotation.

Passing parameter from one page to another - The scope of the object referenced by expression is shorter than the referring managed beans error

I am trying to pass a parameter from one page to another, but when i press the button "Details" it gives me this error: "Unable to create managed bean agencyDetailBean. The following problems were found: - The scope of the object referenced by expression #{agency}, request, is shorter than the referring managed beans (agencyDetailBean) scope of session"
This is part from my .xhtml page:
<p:dataGrid var="agency" value="#{agencyBean.agencyList}" columns="1"
rows="5" paginator="true" paginatorPosition="bottom">
<p:growl id="growl" showDetail="true" />
<p:fieldset legend="${agency.tUser.name}" toggleable="true">
<p:ajax event="toggle" listener="#{fieldsetBean.handleToggle}"
update="growl" />
<h:panelGrid columns="2" cellpadding="3" cellspacing="1">
<h:panelGrid columns="2" cellpadding="3" cellspacing="1">
Name: <h:outputText value="${agency.tUser.name}" />
Phone: <h:outputText value="${agency.tUser.phone}" />
</h:panelGrid>
<h:commandButton value="Details" action="agencyDetail">
<f:setPropertyActionListener target="#{agencyBean.tAgency}"
value="${agency}" />
</h:commandButton>
</h:panelGrid>
</p:fieldset>
</p:dataGrid>
My 1st bean:
#ManagedBean(name = "agencyBean")
#SessionScoped
public class AgencyBean implements Serializable {
private TAgency tAgency = new TAgency();
private List<TAgency> agencyList;
public List<TAgency> getAgencyList() {
return agencyList;
}
public void setAgencyList(List<TAgency> agencyList) {
this.agencyList = agencyList;
}
#PostConstruct
public void init() {
EntityManager em = HibernateUtil.getEntityManager();
Query q = em.createQuery("select u from TAgency u");
agencyList = q.getResultList();
}
public TAgency gettAgency() {
return tAgency;
}
public void settAgency(TAgency tAgency) {
this.tAgency = tAgency;
}
}
My 2nd bean class:
#ManagedBean(name = "agencyDetailBean", eager = true)
#SessionScoped
public class AgencyDetailBean implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty(value = "#{tAgency}")
private AgencyBean agencyBean;
private TAgency tAgency;
public TAgency gettAgency() {
if (agencyBean != null) {
tAgency = agencyBean.gettAgency();
}
return tAgency;
}
public void setAgencyBean(AgencyBean agency) {
this.agencyBean = agency;
}
}
Initially, the .xhml page was like this and it worked.
<p:growl id="growl" showDetail="true" />
<c:forEach items="#{agencyBean.agencyList}" var="agency">
<p:fieldset legend="${agency.tUser.name}" toggleable="true">
...
<h:commandButton value="Details" action="agencyDetail">
<f:setPropertyActionListener target="#{agencyDetailBean.agency}"<br/>
value="${agency}" />
</h:commandButton>
</h:panelGrid>
</p:fieldset>
</c:forEach>
Any suggestion what is the problem and how to fix it?
Thanks in advance!
Using #ManagedBean, you cannot inject beans with smaller scope into beans with bigger scope. For your case, inject the #SessionScoped into the #RequestScoped. Then you can update any properties of the #SessionScoped from the #RequestScoped bean.
Regarding your update, in the 2nd bean, you cannot get tAgency from a getter like that. The following function would do the job.
#PostConstruct
public void init() {
tAgency = agencyBean.gettAgency();
}

Set an ENUM with setPropertyActionListener

I'm trying to set a enum property with setPropertyActionListener but I'm not sure how to do it. Here's the entity:
#Entity
public class Invoice {
public enum InvoiceStatus { ACTIVE, CANCELED }
...
#Enumerated(EnumType.STRING)
private InvoiceStatus status;
...
public InvoiceStatus getStatus() {
return status;
}
public void setStatus(InvoiceStatus status) {
this.status = status;
}
And here's the command button which is suppose to set the status to ACTIVE with setPropertyActionListener
...
<h:form id="invoiceCreatedSuccessfully">
<p:dialog header="#{msg['title.success']}" widgetVar="invoiceCreatedSuccessfullyDialog" resizable="false" showEffect="fade" hideEffect="fade">
<h:panelGrid columns="2" rows="3" style="margin-bottom: 10px">
<h:outputText value="#{msg['message.invoiceCreatedSuccessfully']}" />
</h:panelGrid>
<p:commandButton value="#{msg['label.acknowledged']}" actionListener="#{invoiceManager.reload}" action="viewInvoices">
<f:setPropertyActionListener target="#{invoiceManager.invoice.status}" value="ACTIVE" />
</p:commandButton>
</p:dialog>
</h:form>
No errors are reported but the field 'status' in the DB is not being set. Can someone tell me why?
Strings are not directly converted to Enums in EL , you would need to a custom converted in your faces-config , jsf has one enum converter that should work for you,
<converter>
<converter-for-class>java.lang.Enum</converter-for-class>
<converter-class>javax.faces.convert.EnumConverter</converter-class>
</converter>
Now looking into the source code of EnumConverter , it seems like it works only if targetClass is available in converter.
So you would need to extend it to work with your enum ,
public class MyEnumConverter extends EnumConverter {
public MyEnumConverter () {
super(MyEnum.class);
}
}
<converter>
<converter-id>MyEnum</converter-id>
<converter-class>com.test.MyEnumConverter</converter-class>
</converter>
add <f:converter converterId="MyEnum"/> in your component.
If you have many Enums and to make things easy , you can have a look into omnifaces http://showcase.omnifaces.org/converters/GenericEnumConverter

Stateful Session Bean updates(?) on buttonclick

I'm fairly new to Java EE and I'm building a simple webshop using maven web application . I have a problem with my Stateful Session Bean. I've been searching the net and tried different sollutions(most of them for using servlets) but it doesn't seem to work.
Anyway, my problem is that I'm trying to use my session bean to keep track of what's in the shopping cart. I am using an arrayList to store the items. However, when I add a new item it just replaces the old item instead of adding it to the list. I'm guessing the session bean somehow updates or a new instance of it is created but I just can't seem to find any sollution or information about this.
The stateful session bean
#Stateful
#LocalBean
public class CartSessionBean{
private List contents;
public CartSessionBean(){
contents= new ArrayList();
}
public List getContents() {
return contents;
}
public void addProduct(String title) {
contents.add(title);
}
}
The Managed Bean
#ManagedBean
#RequestScoped
public class ProductController {
private List cartList = new ArrayList();
private int nrOfCartItems=0;
#EJB private CartSessionBean cart;
public String doAddCart(String title)
{
cart.addProduct(title);
setCartList(cart.getContents());
setNrOfCartItems(cart.getContents().size());
return "products.xhtml";
}
}
The Facelet
<h:form>
<p>
your cart contains <h:outputLabel class="" value="#{productController.nrOfCartItems}" /> items.
<ui:repeat value="#{productController.cartList}" var="cart">
<h:outputLabel value="#{cart}" />
</ui:repeat>
<h:commandButton value="go to checkout"/>
</p>
</h:form>
<h:form>
<h:dataTable value="#{productController.productList}" var="pr" border="0">
<h:column>
<h:graphicImage value="images/#{pr.picture}" />
</h:column>
<h:column>
<h2><h:outputText value="#{pr.product_name}"/></h2>
<p> in stock: <h:outputText value="#{pr.stock}"/><br/>
price: <h:outputText value="#{pr.price}"/> SEK<br/><br/>
<h:outputText value="#{pr.description}"/><br/></p>
<h:commandButton value="add to cart" action="#{productController.doAddCart(pr.product_name)}"/>
</h:column>
</h:dataTable>
</h:form>
Your managed bean should be SessionScope to live during the session.
In your case you always creating new ProductController bean for each request and because of that you always inject different CartSessionBean (there is no way how could container know that it should inject the same SessionBean into your RequestScope Managed Bean).

Injecting #Named managed bean into another reusing JSF page?

I'm trying to reuse a jsf page by including using facelets into another jsf page, since this page will be used by a lot of other pages. But the problem is that i can't get the atributes os the managed bean reposible for this page into the managed beans that includes this page.
The page, pessoa.xhtml, some of the repetitive and header code has been removed:
<h:body>
<div id="pessoa">
<h:form id="formPessoa">
<h:messages for="formPessoa"/>
<h:panelGrid columns="3">
<h:outputLabel for="id" value="Código: " />
<h:inputText id="id" value="#{pessoaMB.pessoa.id}"/>
<h:message for="id" />
<h:outputLabel for="apelidoNomeFantasia" value="Apelido/Nome Fantasia: " />
<h:inputText id="apelidoNomeFantasia" value="#{pessoaMB.pessoa.apelidoNomeFantasia}"/>
<h:message for="apelidoNomeFantasia" />
<h:outputLabel for="rgIe" value="RG/Inscrição Estadual: " />
<h:inputText id="rgIe" value="#{pessoaMB.pessoa.rgIe}"/>
</h:panelGrid>
</h:form>
</div>
</h:body>
The #Named managed PessoaMB
#Named
#SessionScoped
public class PessoaMB implements Serializable {
private Pessoa pessoa;
public PessoaMB() {
this.pessoa = new Pessoa();
} //fim do construtor
public Pessoa getPessoa() {
return pessoa;
}
public void setPessoa(Pessoa pessoa) {
this.pessoa = pessoa;
}
}
Here is the code of one of the pages that includes the pessoa.xhtml.
empresa.xhtml
<ui:composition template="/resources/template.xhtml">
<ui:define name="title">
<h:outputText value="Cadastro de Empresa"/>
</ui:define>
<ui:define name="content">
<h:form id="formEmpresa">
<ui:include src="/cadastro/pessoa/pessoa.xhtml" />
<h:commandButton id="novo" action="#{empresaMB.newEmpresa}" value="Novo" />
<h:commandButton id="salvar" action="#{empresaMB.insert}" value="Salvar" />
</h:form>
</ui:define>
</ui:composition>
And the #Named managed bean EmpresaMB.
#Named
#SessionScoped
public class EmpresaMB implements Serializable {
#EJB
private EmpresaEJBRemote empresaEJB;
private Empresa empresa;
#Inject
private PessoaMB pessoaMB;
public String insert() {
pessoaMB = this.getPessoaMB();
empresa.setId(pessoaMB.getPessoa().getId());
empresaEJB.insert(empresa);
return "/cadastro/empresa/empresa";
}
public String newEmpresa() {
pessoaMB = new PessoaMB();
return "/cadastro/empresa/empresa";
}
//both empresa and pessoaMB getters and setters has been added to the code
}
I think that the #Inject anotation would do the job, but it doesn't.
What is exactly the problem? Does the pessoaMB instance variable remains null in EmpresaMB? (i.e. does the initial injection fails?)
Or is the problem that you think that doing the new PessoaMB() will have any effect on the session scoped instance?
This last construct doesn't seem to make sense. Namely, CDI is injecting the EmpresaMB instance with an instance of PessoaMB. This is the exact instance used in the session. However, when you create a new instance in newEmpresa() you are simply overwriting the reference with another instance. This has no connection with the session scoped version whatsoever.
If you want the 'master' bean to produce other beans that gets inserted in its scope, you need to annotate the instance field with the #Named #Produces annotations:
#Named
#SessionScoped
public class EmpresaMB implements Serializable {
#EJB
private EmpresaEJBRemote empresaEJB;
private Empresa empresa;
#Named
#Produces
private PessoaMB pessoaMB;
}
See Reza Rahman's article for some additional details about this: Dependency Injection in Java EE 6: Conversations (Part 4)

Categories

Resources