Jsf2 view parameters and viewscoped beans - java

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}" />

Related

selectOneMenu value null when using selectItems from a different backing bean

I have a form where I create a user. In my form, I have multiple properties for that user (I actually use a User object for the retainment of data on submit to the backing bean)
create.xhtml
<h:form>
<h:outputLabel for="user_name" value="Name:" />
<h:inputText id="user_name" value="#{createUserView.newUser.username}" />
<br/><br/>
<h:outputLabel for="user_password" value="Default Password*:" />
<h:inputSecret id="user_password" value="#{createUserView.newUser.password}"></h:inputSecret><br/><br/>
<h:outputLabel for="user_organization" value="Organization:" />
<h:selectOneMenu id="user_organization" disabled="true" value="#{createUserView.newUser.organizationId}">
<f:selectItems
value="#{organizationBean.allOrganizations}"
var="org"
itemLabel="#{org.organizationName}"
itemValue="#{org.id}" />
</h:selectOneMenu><br/><br/>
<h:commandButton value="Create" action="#{createUserView.createNewUser}" />
</h:form>
CreateUserView
#ManagedBean(name = "createUserView")
#RequestScoped
public class CreateUserView {
private UserServices userSerivces;
private User newUser;
#ManagedProperty(value="#{organizationBean}")
private OrganizationBean organizationBean;
public CreateUserView() {
newUser = new User();
userSerivces = new UserServices();
}
public void createNewUser() {
userSerivces.createNewUser(newUser);
}
// Getters and Setters
}
OrganizationBean
#ManagedBean(name = "organizationBean")
#RequestScoped
public class OrganizationBean {
private List<Organization> allOrganizations;
private OrganizationServices orgServices;
public OrganizationBean() {
orgServices = new OrganizationServices();
allOrganizations = orgServices.retrieveAllOrganizations();
}
// Getters and Setters
}
The issue here is that when I reference the newUser object in the backing bean, the organizationId value is null.
I assume this is because OrganizationBean (excuse the confusing in naming, refactoring) is either not rendered for my current view or I need to somehow inject.
I've tried a managed property in the CreateUserView backing bean that references the OrganizationBean, but no luck. The organizationID value in the newUser object is null.
Do I need to populate a list in the CreateUserView bean using the OrganizationBean injection, so that it has it's own list it can render?
What am I missing? Feeling foolish.
JSF 2.0
The problem, as stated in the comments is that you don't have a Converter for your Organization class.
You must have it in order to know what Organization matches every SelectItem. The converter must be something like:
#FacesConverter(forClass = Organization.class, value = "organizationConverter")
public class OrganizationConverter implements Converter
{
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String id)
{
if (StringUtils.isEmpty(id))
{
return null;
}
// Convert id to an Organizacion
return organization;
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object o)
{
if (o instanceof Organization)
{
return ...;//Convert organization to id
}
return null;
}
}
And then in your selectonemenu:
<h:selectOneMenu id="user_organization" disabled="true" value="#{createUserView.newUser.organizationId}"
converter="organizationConverter">

get variables from jsf query sql db display results on another jsf page [duplicate]

I have started learning JSF, but sadly most tutorials out there present only a log in or a register section.
Can you point me to some more in depth examples? One thing I'm interested in is a page presenting a list of products. I'm on page home and I press on page products so that I can see the latest products added. And every time I visit the page, the product list will be created from the latest entries in the database. How can I handle this?
One way to solve this would be to create a session scoped managed bean in which I would place different entities updated through other managed beans. I found this kind of approach in some tutorials, but it seems quite difficult and clumsy.
Which would be the best approach to solve a thing like this? What is the correct usage of session scope in two-page master-detail user interface?
What is the correct usage of session scope
Use it for session scoped data only, nothing else. For example, the logged-in user, its settings, the chosen language, etcetera.
See also:
How to choose the right bean scope?
And every time I visit the page, the product list will be created from the latest entries in the database. How can I handle this?
Typically you use the request or view scope for it. Loading of the list should happen in a #PostConstruct method. If the page doesn't contain any <h:form>, then the request scope is fine. A view scoped bean would behave like a request scoped when there's no <h:form> anyway.
All "view product" and "edit product" links/buttons which just retrieve information (i.e. idempotent) whould be just plain GET <h:link> / <h:button> wherein you pass the entity identifier as a request parameter by <f:param>.
All "delete product" and "save product" links/buttons which will manipulate information (i.e. non-idempotent) should perform POST by <h:commandLink>/<h:commandButton> (you don't want them to be bookmarkable/searchbot-indexable!). This in turn requires a <h:form>. In order to preserve the data for validations and ajax requests (so that you don't need to reload/preinitialize the entity on every request), the bean should preferably be view scoped.
Note that you should basically have a separate bean for each view and also note that those beans doesn't necessarily need to reference each other.
So, given this "product" entity:
#Entity
public class Product {
#Id
private Long id;
private String name;
private String description;
// ...
}
And this "product service" EJB:
#Stateless
public class ProductService {
#PersistenceContext
private EntityManager em;
public Product find(Long id) {
return em.find(Product.class, id);
}
public List<Product> list() {
return em.createQuery("SELECT p FROM Product p", Product.class).getResultList();
}
public void create(Product product) {
em.persist(product);
}
public void update(Product product) {
em.merge(product);
}
public void delete(Product product) {
em.remove(em.contains(product) ? product : em.merge(product));
}
// ...
}
You can have this "view products" on /products.xhtml:
<h:dataTable value="#{viewProducts.products}" var="product">
<h:column>#{product.id}</h:column>
<h:column>#{product.name}</h:column>
<h:column>#{product.description}</h:column>
<h:column>
<h:link value="Edit" outcome="/products/edit">
<f:param name="id" value="#{product.id}" />
</h:link>
</h:column>
</h:dataTable>
#Named
#RequestScoped
public class ViewProducts {
private List<Product> products; // +getter
#EJB
private ProductService productService;
#PostConstruct
public void init() {
products = productService.list();
}
// ...
}
And you can have this "edit product" on /products/edit.xhtml:
<f:metadata>
<f:viewParam name="id" value="#{editProduct.product}"
converter="#{productConverter}" converterMessage="Unknown product, please use a link from within the system."
required="true" requiredMessage="Bad request, please use a link from within the system."
/>
</f:metadata>
<h:messages />
<h:form rendered="#{not empty editProduct.product}>
<h:inputText value="#{editProduct.product.name}" />
<h:inputTextarea value="#{editProduct.product.description}" />
...
<h:commandButton value="save" action="#{editProduct.save}" />
</h:form>
#Named
#ViewScoped
public class EditProduct {
private Product product; // +getter +setter
#EJB
private ProductService productService;
public String save() {
productService.update(product);
return "/products?faces-redirect=true";
}
// ...
}
And this converter for <f:viewParam> of "edit product":
#Named
#RequestScoped
public class ProductConverter implements Converter {
#EJB
private ProductService productService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
Long id = Long.valueOf(value);
return productService.find(id);
} catch (NumberFormatException e) {
throw new ConverterException("The value is not a valid Product ID: " + value, e);
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
}
if (value instanceof Product) {
Long id = ((Product) value).getId();
return (id != null) ? String.valueOf(id) : null;
} else {
throw new ConverterException("The value is not a valid Product instance: " + value);
}
}
}
You can even use a generic converter, this is explained in Implement converters for entities with Java Generics.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
JSF Controller, Service and DAO
JSF Service Layer
How to inject #EJB, #PersistenceContext, #Inject, #Autowired, etc in #FacesConverter?
Communication in JSF 2.0 - Contains several examples/hints
As a small improvement to what BalusC recommended, sometimes you can remove the required / requiredMessage part from the <f:viewParam> of your "details" screen and instead use the conditional rendering of the editing form (as BalusC did) with a reverse condition for recommending a specific link for the "list/master" screen or, even use a viewAction that would test the param and force a redirect to that list.

JSF AJAX - Class doesn't have property

I have been trying to run AJAX example in JSF. But I am getting "class does not have the property login". But in all the examples in various websites, code is same the same.
My index.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>JSF AJAX Calls</title>
</h:head>
<h:body>
<h2>AJAX Example</h2>
<h:form>
<h:inputText id="inputName" value="#{userData.name}"></h:inputText>
<h:commandButton value="Login">
<f:ajax execute="inputName" render="outputMsg" />
</h:commandButton>
<br />
<hr />
<h2><h:outputText id="outputMsg" value="#{userData.login}" /></h2>
</h:form>
</h:body>
</html>
UserData.java
package com.cyb3rh4wk.test;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name = "userData", eager = true)
#SessionScoped
public class UserData implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String login() {
if ("".equals(name) || name == null)
return "";
else
return "Logged in as " + name;
}
}
This is my error,
/index.xhtml value="#{userData.login}": The class 'com.cyb3rh4wk.test.UserData' does not have the property 'login'.
How do I resolve this error ?
Value and Method Expressions
The EL defines two kinds of expressions: value expressions and method expressions. Value expressions can either yield a value or set a value. Method expressions reference methods that can be invoked and can return a value.
Example of a value expression according to the above definition in your code is:
userData.name
In the following tag definition:
<h:outputText id="outputMsg" value="#{userData.login}" />
you are not using a value expression but rather a method expression because login is not a simple JavaBean getter returning the value of a bean property.
So you have to change the above line as:
<h:outputText id="outputMsg" value="Logged in as : #{userData.name}" />
And remove your login or use it for navigation purpose (that is why it is there).
Here is the reason (taken from JSF 2.0 specification) why you have to pass a value expression to an output component instead of a method expression:
4.1.10 UIOutput
UIOutput (extends UIComponentBase; implements ValueHolder) is a component that has a value, optionally retrieved from a model tier bean via a value expression (see Section 5.1 “Value Expressions”), that is displayed to the
user. The user cannot directly modify the rendered value; it is for display purposes only:

Loaded Records not showing in view

So to make it relatively simple: I have some Primefaces-Page, which is supposed to represent database records in a table-structure.
I keep these records in a List<Customer> which resides in a #ConversationScoped backing bean. I have verified via debugging, that the List gets correctly filled with records from the Database (hibernate db FWIW). This is accomplished with the help of a "businessInterface" Distributor class, that is in fact nothing but a decoupling mask for (Database)Service-Classes.
As mentioned, I have verified that the Database, as well as the Distributor correctly return the expected values. Unfortunately in the View there are no records present and instead the emptyMessage is displayed.
The application is running on a jBoss 7.1.1-Final Application Server.
For better readability I have excluded the h:head, as well as h:body, ui:composition, ui:define and h:form around the provided code, as well as shortened the columns to the two different usages (property display and action exposition)
The View (shortened and truncated):
<ui:define name="inhalt">
<p:growl id="msgGrowl" autoUpdate="true" showDetail="true" />
<h:form onkeypress="if (event.keyCode == 13) {return false; }">
<p:dataTable var="customeritem" id="customerTable"
rowkey="#{customeritem.id}" value="#{customerListController.customerList}"
paginator="true" rows="13" autoUpdate="true"
filteredValue="#{customerListController.filteredCustomers}"
emptyMessage="no customers found!"
sortFunction="#{customerListController.filteredCustomers}">
<p:column sortBy="name" filterBy="name" headerText="Kunde"
filterMatchMode="contains">
<h:outputText value="#{customeritem.name}" />
</p:column>
<p:column>
<f:facet name="header">
<p:commandButton value="Neuer Kunde"
action="${customerListController.addCustomer()}"
icon="ui-icon-plus" />
</f:facet>
<p:commandButton id="doViewDetailsButton" icon="ui-icon-clipboard"
action="${customerListController.viewDetails(customeritem.getId())}" />
<p:tooltip for="doViewDetailsButton" value="Details ansehen" />
</p:column>
</p:dataTable>
</h:form>
</ui:define>
The Backing Bean:
#Named
#ConversationScoped
public class CustomerListController implements Serializable {
private static final long serialVersionUID = -5961625401284927892L;
private List<Customer> customerList = new ArrayList<Customer>();
private List<Customer> filteredCustomers = new ArrayList<Customer>();
#Inject
CustomerEditController customerEditController;
#Inject
CustomerDetailsController customerDetailsController;
#Inject
CustomerDistributor businessInterface;
public String addCustomer() {
return editCustomer(0l);
}
public String editCustomer(long customerId) {
setFilteredCustomers(null);
customerEditController.recieveCustomerById(customerId);
return Pages.CUSTOMER_EDIT;
}
public String viewDetails(long customerId) {
setFilteredCustomers(null);
customerDetailsController.recieveCustomerById(customerId);
return Pages.CUSTOMER_DETAILS;
}
public String deleteCustomer(long customerIdToDelete) {
businessInterface.delete(customerIdToDelete);
setFilteredCustomers(null);
fillCustomerList();
return Pages.CUSTOMER_LIST;
}
#PostConstruct
public void fillCustomerList() {
customerList.clear();
customerList.addAll(businessInterface.loadAll());
}
public List<Customer> getCustomerList() {
return customerList;
}
public List<Customer> getFilteredCustomers() {
return filteredCustomers;
}
public void setFilteredCustomers(List<Customer> filteredCustomers) {
this.filteredCustomers = filteredCustomers;
}
}
This used to work, when I had the Backing Bean in #SessionScoped, but as that required hackish workarounds to produce intuitive (and expected) behavior I decided to move the Backing Bean to a smaller scope. I therefore chose the #ConversationScoped, because the BackingBean needs to stay longer than the request lifecycle... (Also running a query against a db for every request is damn expensive...)
A short explanation on the CustomerEditController and CustomerDetailsController. They are the responsible ones for Editing and Showing further information on the single records if they are requested by clicking one of the Buttons.
The non-working stuff is the #PostConstruct public void fillCustomerList(). Everything else works as expected...
If you need any further information, please ask, I will provide context as needed ;)
I have found a successful workaround for this, but it's extremely hackish and I really dislike the approach, as it introduces additional behavior in a getter. I modified the Backing Bean as follows:
public List<Customer> getCustomerList() {
if (customerList.size() == 0) {
fillCustomerList();
}
return customerList;
}
But let me state this again,
this is definitely not the desired behavior and not a good approach at solving this problem.
EDIT:
I found a different fix after a little more digging and a lucky link. I modified the backing bean as follows:
#Inject
Conversation conversation;
#PostConstruct
public void init() {
if(conversation.isTransient()) {
conversation.end();
}
conversation.setTimeout(120000);
conversation.start();
}
and now It works even without the hackish behavior in the getter (as demonstrated above).

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