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)
Related
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();
}
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).
How can I access the view parameters from a viewscoped bean?
I have a page almost with the same content as this:
<f:metadata>
<f:viewParam name="name" value="#{goToUserpageRequest.name}" />
</f:metadata>
<ui:define name="content">
<h:outputText value="#{user.name}" styleClass="text"></h:outputText>
<h:outputText value="#{user.description}" styleClass="text"></h:outputText>
</ui:define>
GoToUserpageRequest is a bean which I use to redirect to this page, so I can send the value for name.
User is my viewscoped bean. I want to pass the value of viewParam name to user.name. How can I do that?
Thanks in advance!
There is an easier way for your case which I have just figured out while looking for a solution for the same situation.
just use this in your xhtml together :
<f:metadata>
<f:viewParam name="name" value="#{goToUserpageRequest.name}" />
</f:metadata>
<f:event type="preRenderView" listener="#{MY_BEAN.setName(goToUserpageRequest.name)}"/>
so you can send the goToUserpageRequest.name value back to your redirected view's bean (I called MY_BEAN)
You can get this information using the external context from your context. See the request parameters.
However, I would try to use a request scope bean and inject the view and parameter scope values into that. You can then manipulate your view scoped object from there. This approach is easier to unit test.
EDIT:
Here is a sample implementation:
#ManagedBean #RequestScoped
public class NameUpdater {
#ManagedProperty("#{param.name}") private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
#ManagedProperty("#{user}") private User user;
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
#PostConstruct public void init() {
if(name != null) user.setName(name);
}
}
In order to create the request scoped bean, the binding expression would change to something like:
<h:outputText value="#{nameUpdater.user.name}" />
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}" />
I generated a new form using sean-gen (seam new-form) and added another field to it using an #In annotation:
#Stateful
#Name("dummy")
public class DummyBean implements Dummy
{
#Logger private Log log;
#In StatusMessages statusMessages;
#In private String bar;
private String foo;
public void doStuff()
{
String msg = "dummy.doStuff() action called with foo: #{dummy.foo} and bar: #{bar}. instance variable for bar:" + bar;
log.info(msg);
statusMessages.add(msg);
}
#Length(max = 10)
public String getFoo()
{
return foo;
}
public void setFoo(String value)
{
this.foo = value;
}
#Remove
public void destroy() {}
}
The interface is this one:
#Local
public interface Dummy
{
public void doStuff();
public String getFoo();
public void setFoo(String value);
public void destroy();
}
The problem is, when I try to access the properties I get:
javax.faces.FacesException: javax.el.ELException: /dummy.xhtml #22,52 value="#{dummy.foo}": Error reading 'foo' on type org.javassist.tmp.java.lang.Object_$$_javassist_seam_2
at javax.faces.component.UIOutput.getValue(UIOutput.java:187)
at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:201)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:284)
at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:154)
.
.
.
Caused by: javax.ejb.EJBTransactionRolledbackException: #In attribute requires non-null value: dummy.bar
at org.jboss.ejb3.tx.Ejb3TxPolicy.handleInCallerTx(Ejb3TxPolicy.java:115)
at org.jboss.aspects.tx.TxPolicy.invokeInCallerTx(TxPolicy.java:130)
My view is this:
<!DOCTYPE composition 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:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:a="http://richfaces.org/a4j"
template="layout/template.xhtml">
<ui:define name="body">
<h:form id="dummyForm">
<rich:panel>
<f:facet name="header">dummy header</f:facet>
<s:decorate id="fooField" template="layout/edit.xhtml">
<ui:define name="label">Foo</ui:define>
<h:inputText id="foo" required="true"
value="#{dummy.foo}"/>
</s:decorate>
<s:decorate id="barField" template="layout/edit.xhtml">
<ui:define name="label">Bar</ui:define>
<h:inputText id="bar" required="true"
value="#{bar}"/>
</s:decorate>
<div style="clear:both"/>
</rich:panel>
<div class="actionButtons">
<h:commandButton id="doStuff" value="doStuff"
action="#{dummy.doStuff}"/>
</div>
</h:form>
</ui:define>
</ui:composition>
If I remove either 'fooField' or 'barField' the view renders and works correctly, but if I try to use both at the same time I get the above exception.
I also noticed that if I use only #In annotations (remove the accessor methods from the bean) the page works.
Is this something expected and I should be doing my homework before asking?
I'm using JBoss 5.1.0.GA, Seam 2.2.0.GA and Java 6.
Turns out this is expected behavior, quoting an answer from the seam forum:
Use #In(required=false) if the Seam component you're injecting does not have the #AutoCreate annotation at the class level.
So, changing:
#In private String bar;
to:
#In (required=false) private String bar;
fixes the issue.