JSF composite button reinitiliazes view scoped managed bean - jsf

As soon as a composite which encapsulates a commandButton is included in my .xhtml, the viewscoped bean is reinitialized no matter which commandButton is used. Is my composite wrong? Please let me know because I realy would like to use composites for my buttons.
Simplyfied testcase:
#ManagedBean
#ViewScoped
public class Test implements Serializable {
private static final long serialVersionUID = 123456L;
private static int i = 0;
private int counter;
private String table;
private transient DataModel<String> model;
#PostConstruct
public void test() {
System.out.println(".......... PostConstruct");
i++;
List<String> modelData = new ArrayList<String>();
modelData.add("hello");
modelData.add("world");
model = new ListDataModel<String>(modelData);
}
public int getCounter() {
return counter;
}
public String getTable() {
return table;
}
public DataModel<String> getModel() {
return model;
}
public void tableListener() {
String data = model.getRowData();
table = data.toUpperCase();
}
}
No matter which button is clicked (2nd or 3th column), the postConstruct method is called over and over again
<h:form>
<h:dataTable style="width: 40em" var="line" value="#{test.model}">
<h:column>
<f:facet name="header">string</f:facet>
#{line}
</h:column>
<h:column>
<f:facet name="header">actie...1</f:facet>
<h:commandButton value="toUpper" immediate="true" >
<f:ajax event="click" execute="#form" render=":testTable" listener="#{test.tableListener}" />
</h:commandButton>
</h:column>
<h:column>
<f:facet name="header">actie...2</f:facet>
<cmp:rowAction managedBean="#{test}" label="button" listener="tableListener"
tooltip="test via composite" img="stop.png" render=":testTable"/>
</h:column>
</h:dataTable>
</h:form>
As soon as the last column (header actie...2) is removed, then the #PostConstruct is called only once, as expected.
Why does the presence of my composite forces to reinitialize the viewscoped bean? What's wrong with my composite, it works, but it shouldn't reinitialize the managed bean:
<?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:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<!-- INTERFACE -->
<cc:interface>
<cc:attribute name="label" required="true"/>
<cc:attribute name="render"/>
<cc:attribute name="tooltip"/>
<cc:attribute name="img"/>
<cc:attribute name="listener" required="true"/>
<cc:attribute name="managedBean" required="true"/>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<h:commandButton id="btn_#{cc.attrs.label}" title="#{cc.attrs.tooltip}" immediate="true"
image="/resources/img/#{cc.attrs.img}">
<f:ajax event="click" execute="#form" render="#{cc.attrs.render}" listener="#{cc.attrs.managedBean[cc.attrs.listener]}" />
</h:commandButton>
</cc:implementation>

based on this post, JSF 2 - How can I add an Ajax listener method to composite component interface? i've found a solution. The problem was the declaration of the listener attribute cc:attribute name="listener" required="true"/> it should be cc:attribute name="listener" method-signature="void listener()" required="true"/>
There is still one (in my case minor) problem as mentioned by BalusC in the previously mentioned post: I can't us the AjaxBehvaiorEvent. I'm using Netbeans 6.9.1, Gfish3.1 and Mojarra2.1.1

Related

h:dataTable composite component, cc.attrs.var, IllegalArgumentException

I'm trying to create my own dataTable like the primefaces one. The problem is that cc.attrs.var when used throws a IllegalArgumentException. So I'm wondering how I can have the var attribute like Primefaces.
<cc:interface>
<cc:attribute name="value"/>
<cc:attribute name="var"/>
<cc:attribute name="styleClass"/>
</cc:interface>
<cc:implementation>
<div>Previous</div>
<div>Next</div>
<h:dataTable value="#{cc.attrs.value}" var="#{cc.attrs.var}" styleClass="#{cc.attrs.styleClass}">
<ui:insert/>
</h:dataTable>
</cc:implementation>
As per the UIData#setValueExpression() javadoc, it's not allowed to have an EL expression in var attribute.
Throws:
IllegalArgumentException - if name is one of id, parent, var, or rowIndex
Your best bet is to create a backing component wherein you manually evaluate and set the var attribute of the UIData component bound to <h:dataTable> during the postAddToView event.
<cc:interface componentType="yourTableComposite">
<cc:attribute name="value" />
<cc:attribute name="var" />
</cc:interface>
<cc:implementation>
<f:event type="postAddToView" listener="#{cc.init}" />
<h:dataTable binding="#{cc.table}" value="#{cc.attrs.value}">
<cc:insertChildren />
</h:dataTable>
</cc:implementation>
#FacesComponent("yourTableComposite")
public class YourTableComposite extends UINamingContainer {
private UIData table;
public void init() {
table.setVar((String) getAttributes().get("var"));
}
public UIData getTable() {
return table;
}
public void setTable(UIData table) {
this.table = table;
}
}
Note that I fixed the <ui:insert> to be <cc:insertChildren>. The <ui:insert> can only be used in <ui:composition>/<ui:decorate>.
See also:
Initialize a composite component based on the provided attributes
How does the 'binding' attribute work in JSF? When and how should it be used?

Updating components inside a custom ui:component when it is used multiple times on same page

I am building a simple component in JSF (Mojarra 2.1.x) where I have to access parent ui components to update them, currently I'm using binding to achieve this, but it only works as long as I don't use the component more than once on the same page.
So I need a solution that would allow me to use the component multiple times on same page.
In the following code I'm updating commandButton with binding="#{msButton}" and panel with binding="#{msPanel}":
<?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:component xmlns="http://www.w3.org/1999/xhtml"
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:c="http://java.sun.com/jsp/jstl/core"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:layout="http://sterz.stlrg.gv.at/jsf/layout"
xmlns:p="http://primefaces.org/ui">
<cc:interface>
<cc:attribute name="controller" required="true" />
<cc:attribute name="converter" required="true" />
</cc:interface>
<cc:implementation>
<p:commandButton id="msButton#{cc.attrs.controller.class.getSimpleName()}" binding="#{msButton}" value="#{msg.mehr} (#{cc.attrs.controller.itemList.size()})" type="button" />
<p:overlayPanel id="msOverlayPanel" for=":#{msButton.clientId}" hideEffect="fade" my="right top" at="right bottom">
<p:panel id="msPanel#{cc.attrs.controller.class.getSimpleName()}" binding="#{msPanel}" styleClass="ui-panel-fit">
<ui:repeat id="repeat" value="#{cc.attrs.controller.itemList}"
var="item">
<p:commandButton id="removeButton"
actionListener="#{cc.attrs.controller.removeItem(item)}"
icon="ui-icon-trash" update=":#{msPanel.clientId} :#{msButton.clientId}" ajax="true"
process="#this" disabled="#{cc.attrs.controller.itemList.size() == 1}"/>
<p:selectBooleanButton id="value1" value="#{item.exclude}"
offLabel="und" onLabel="und nicht" style="width:80px;">
<p:ajax event="change" process="#this" />
</p:selectBooleanButton>
<p:autoComplete converter="#{cc.attrs.converter}"
readonly="#{cc.attrs.readonly}" value="#{item.from}"
dropdown="true"
completeMethod="#{cc.attrs.controller.autocomplete}" var="gp"
itemLabel="#{gp.displayName}" itemValue="#{gp}">
<p:ajax event="itemSelect" process="#this" />
</p:autoComplete>
<h:outputText value=" #{msg.bis} " />
<p:autoComplete converter="#{cc.attrs.converter}"
readonly="#{cc.attrs.readonly}" value="#{item.to}" dropdown="true"
completeMethod="#{cc.attrs.controller.autocomplete}" var="gp"
itemLabel="#{gp.displayName}" itemValue="#{gp}">
<p:ajax event="itemSelect" process="#this" />
</p:autoComplete>
<br />
</ui:repeat>
<hr />
<p:commandButton id="addButton" actionListener="#{cc.attrs.controller.addItem}"
icon="ui-icon-plus" value="#{msg.zufuegen}" update="#parent :#{msButton.clientId}"
ajax="true" process="#this"/>
</p:panel>
</p:overlayPanel>
</cc:implementation>
</ui:component>
Any help is much apprecieted.
The solution is to use the faces component bean
#FacesComponent("com.xxx.MultiselectorIdComponent")
public class MultiselectorIdComponent extends UINamingContainer
{
UIComponent msPanel;
// getters/settter and other ui compunents
}
tell the component interface what faces component bean to use
<cc:interface componentType="com.xxx.MultiselectorIdComponent">
bind the JSF component to the one in the faces component bean
<p:panel binding="#{cc.msPanel}"/>
and to access the components, for example to update the component, we use the binding
<p:commandButton value="My Button" update=":#{cc.msPanel.clientId}"/>
ALSO:
A good practice is to use a parent container (like <div>) with the following ID
<div id="#{cc.clientId}">
Hope this helps,
Regards
You could target the components for update by their style class
<p:commandButton styleClass="msButton" ... />
<p:panel styleClass="msPanel" ... />
And I guess you update them from addButton, which would look like this
<p:commandButton id="addButton" update="#(.msButton, .msPanel)" ... />
It should have no problems working with many cc instances on the same page.
UPDATE
You can try with update="#composite", which should refresh the whole custom component. Or, the cumbersome update="#parent #parent:#parent:#parent:#child(1)" which should target panel and button respectively. Or update="#parent #parent:#parent:#previous", which should do the same. Take a look at chapter 4.3 in Primefaces User Guide for more examples and supported keywords.
I solve similar problem by common bean "bindingBean" stored in ViewContext. BindingBean holds all binded component in internal MAP of component records. The key of hash map is an EL expression - it is factory of the component. EL is used for components creating. Components are hold in records stored in MAP in bind bean.
Example:
<h:panel binding="#{bindBean.get('msPanelFactory.getPanel()').component}"/>
Record:
public class BindingRecord {
private Object component;
private String compExpr;
public BindingRecord(String compExpr) {
this.compExpr = compExpr;
}
public Object getComponent() {
if (component == null) {
component = getValueExprValue("#{" + compExpr + "}");
}
return component;
}
public void setComponent(Object component) {
this.component = component;
}
public Object getStoredComponent() {
return component;
}
}
Binding bean:
public class BindingBean {
private final Map<String, BindingRecord> bindingMap = new HashMap<>();
public BindingRecord get(String key) {
BindingRecord result = bindingMap.get(key);
if (result == null) {
result = new BindingRecord(key);
bindingMap.put(key, result);
}
return result;
}
}
In you case you can use:
<h:panel binding="#{bindingBean.get('panelFactory.create()').component}"/>
Inside composite component you can use trick - Pass component name by composite parameter:
<h:panel binding="#{bindingBean.get('panelFactory.create('.concate(cc.attrs.componentName).concate(')')).component}"/>

Can't get view Scoped bean value on another jsf page?

I am developing a project using JSF. In an opening popup window, i want to show some details about a product but can not get view scoped bean' s value on a datatable.
Can you help me?
Thanks.
Here is my UrunuDenetlemeSayfasi.xhtml code snippet:
<h:commandLink onclick="window.open('UruneGozAt.xhtml',
'Ürün İçeriği', config='width=700, height=400, top=100, left=100,
scrollbars=no, resizable=no');"
action="#{uruneGozAtBean.urunIdsineGoreUrunIcerigiGetir}" value="Ürün İçeriğine Göz At">
<f:param name="urunid" value="#{urun.urunID}" />
</h:commandLink>
Here is UrunuGozAt.xhtml:
<!DOCTYPE html>
<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:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:dataTable class="table table-striped"
value="#{uruneGozAtBean.urunIcerik}" var="urun">
<h:column>
<f:facet name="header">
<h:outputText value="barkod no" />
</f:facet>
<h:outputText value="#{urun.barkodNo}" />
</h:column>
</h:dataTable>
</h:body>
</html>
Here is UruneGozAtBean.java
UrunDenetlemeSayfasiBean urunDenetle = new UrunDenetlemeSayfasiBean();
UrunDenetleService urunService = new UrunDenetleService();
private UrunIcerik urunIcerik = new UrunIcerik();
private Long urunIdParametre;
public UrunIcerik getUrunIcerik() {
return urunIcerik;
}
public void setUrunIcerik(UrunIcerik urunIcerik) {
this.urunIcerik = urunIcerik;
}
public Long getUrunIdParametre() {
return urunIdParametre;
}
public void setUrunIdParametre(Long urunIdParametre) {
this.urunIdParametre = urunIdParametre;
}
public void urunIdsineGoreUrunIcerigiGetir() {
setUrunIcerik(urunService.urunIdsineGoreUrunIcerigiGetir(urunIdEldeEt()));
}
public Long urunIdEldeEt(){
FacesContext fc = FacesContext.getCurrentInstance();
setUrunIdParametre(getUrunIdParametre(fc));
return getUrunIdParametre();
}
public Long getUrunIdParametre(FacesContext fc){
Map<String, String> parametre = fc.getExternalContext().getRequestParameterMap();
return Long.valueOf(parametre.get("urunid")).longValue();
}
EDIT:
This is now my current implementation, it returns null.
i am developing a project using JSF. In an opening popup window, i want to show some details about a product but can not get view scoped bean' s value on a datatable.
Can you help me?
Thanks.
Here is my UrunuDenetlemeSayfasi.xhtml code snippet:
<h:commandLink onclick="window.open('UruneGozAt.xhtml','Ürün İçeriği',
config='width=700, height=400, top=100, left=100, scrollbars=no, resizable=no');"
value="Ürün İçeriğine Göz At"> <f:param name="urunId" value="#{urun.urunID}" />
</h:commandLink>
Here is UruneGozAt.xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:metadata>
<f:viewParam name="urunId" value="#{uruneGozAtBean.urunId}"
required="false" />
<f:viewAction action="#{uruneGozAtBean.urunIdsineGoreUrunIcerigiGetir()}" />
</f:metadata>
<h:head>
<title>Ürün İçeriği</title>
<!-- add this always, even if it's empty -->
</h:head>
<h:body>
<h:dataTable class="table table-striped"
value="#{uruneGozAtBean.urunIcerik}" var="urun">
<h:column>
<f:facet name="header">
<h:outputText value="barkod no" />
</f:facet>
<h:outputText value="#{urun.barkodNo}" />
</h:column>
</h:dataTable>
</h:body>
</html>
Here is UruneGozAtBean.java
#ManagedBean
#ViewScoped
public class UruneGozAtBean {
public UrunDenetlemeSayfasiBean urunDenetle = new UrunDenetlemeSayfasiBean();
public UrunDenetleService urunService = new UrunDenetleService();
private ArrayList<UrunIcerik> urunIcerik = new ArrayList<UrunIcerik>();
private Long urunId;
public Long getUrunId() {
return urunId;
}
public void setUrunId(Long urunId) {
this.urunId = urunId;
}
public ArrayList<UrunIcerik> getUrunIcerik() {
return urunIcerik;
}
public void setUrunIcerik(ArrayList<UrunIcerik> urunIcerik) {
this.urunIcerik = urunIcerik;
}
public void urunIdsineGoreUrunIcerigiGetir() {
setUrunIcerik(urunService.urunIdsineGoreUrunIcerigiGetir(urunIdEldeEt()));
System.out.print("aaa");
}
public Long urunIdEldeEt() {
FacesContext fc = FacesContext.getCurrentInstance();
setUrunId(getUrunId(fc));
return getUrunId();
}
public Long getUrunId(FacesContext fc) {
Map<String, String> parametre = fc.getExternalContext().getRequestParameterMap();
return Long.valueOf(parametre.get("urunId")).longValue();
}
}
#ViewScoped beans are alive per view. If you open a popup window from your current view, then you're opening a new view, so even if it uses the same managed bean to display the data, since they're different views, they use different instances of the same class.
In cases like this, you should pass a parameter through query string, then receive it in your view and process it to load the desired data. In this case, your code would be like this (note: make sure you send the parameter with name "urunId"):
UrunuGozAt.xhtml:
<!DOCTYPE html>
<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:ui="http://java.sun.com/jsf/facelets">
<h:head>
<!-- add this always, even if it's empty -->
<f:metadata>
<f:viewParam name="urunId" value="#{uruneGozAtBean.urunId}"
required="false" />
<f:viewAction action="#{uruneGozAtBean.loadData}" />
</f:metadata>
</h:head>
<h:body>
<h:dataTable class="table table-striped"
value="#{uruneGozAtBean.urunIcerik}" var="urun">
<h:column>
<f:facet name="header">
<h:outputText value="barkod no" />
</f:facet>
<h:outputText value="#{urun.barkodNo}" />
</h:column>
</h:dataTable>
</h:body>
</html>
UruneGozAtBean managed bean:
#ViewScoped
#ManagedBean
public class UruneGozAtBean {
//your current fields, getters and setters...
private Long urunId;
//getter and setter for this field...
public void loadData() {
if (urunId != null) {
//load the data for the table...
}
}
}
More info:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to choose the right bean scope?
DataTable expects a list to iterate through, but as far as I can see you return an UrunIcerik object.

In JSF, how to update a page dynamically and partially with ajax and with out form validation?

I have a JSF 2 form like this:
<h:form>
<h:panelGrid columns="2">
<a4j:repeat value="#{dialog.departments}" var="depart">
<h:inputText value="#{depart.name}"/>
<h:selectOneRadio value="#{depart.hasSubdepartment}">
<f:ajax render="#form" execute="#form" immediate="true"/>
<f:selectItem itemValue="#{true}"/>
<f:selectItem itemValue="#{false}"/>
</h:selectOneRadio>
<a4j:repeat value="#{depart.subdepartments}" var="sub" rendered="#{depart.hasSubdepartment}">
<h:inputText value="#{sub.name}"/>
<h:outputText value=" " />
</a4j:repeat>
</a4j:repeat>
</h:panelGrid>
</h:form>
I have simply the form. As you could see, this form displays data structure of departments like a tree.
What I want to implements is that if user switch the radio button to true, the sub-departments will be displayed, if switch to false, the sub-departments will be hidden.
The problem is that:
If the execute value of the f:ajax tag is set to #form, the validation of the backing beans such as #NotNull and #Size will be called. But we don't want to call the validation now since we do not want to save the data now.
If the execute value of the f:ajax tag is set to #this, it seems that the after the ajax request, the value of the radio reverts. For example, if the radio value is false, and we click true, then after the ajax request, the value go back to false, and the sub-department part is not rendered. This will not happen if execute is set to #form.
Thanks very much if you have any idea or hint.
I don't have a Richfaces integrated testing environment, however I've achieved what you want in plain JSF (that's why it could be an ajax4jsf specific issue). Here you have a test case which works and follows SSCCE standards. Tested with Mojarra 2.1.26 & Tomcat 6:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
<h:form>
<h:panelGrid columns="2">
<ui:repeat value="#{dialog.departments}" var="depart">
<h:inputText value="#{depart.name}" />
<h:selectOneRadio value="#{depart.hasSubdepartments}">
<f:ajax render="#form" immediate="true" />
<f:selectItem itemValue="#{true}" />
<f:selectItem itemValue="#{false}" />
</h:selectOneRadio>
<h:panelGroup id="subdepartmentPanel"
rendered="#{depart.hasSubdepartments}">
<ui:repeat value="#{depart.subdepartments}" var="sub">
<h:inputText value="#{sub.name}" />
</ui:repeat>
</h:panelGroup>
</ui:repeat>
</h:panelGrid>
</h:form>
</h:body>
</html>
#ManagedBean
#ViewScoped
public class Dialog {
public class Department {
private String name;
private List<Department> subdepartments = new ArrayList<Dialog.Department>();
private boolean hasSubdepartments;
public Department(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Department> getSubdepartments() {
return subdepartments;
}
public boolean isHasSubdepartments() {
return hasSubdepartments;
}
public void setHasSubdepartments(boolean hasSubdepartments) {
this.hasSubdepartments = hasSubdepartments;
}
public void setName(String name) {
this.name = name;
}
public void setSubdepartments(List<Department> subdepartments) {
this.subdepartments = subdepartments;
}
}
private List<Department> departments = new ArrayList<Dialog.Department>();
public Dialog() {
// Create departments and subdepartments
departments.add(new Department("First Department"));
Department d = new Department("Second department");
d.getSubdepartments().add(new Department("Subdepartment"));
departments.add(d);
}
public List<Department> getDepartments() {
return departments;
}
}

#Inject to pass params to a CDI #Named bean via URL

If I cannot use the #ManagedProperty annotation with #Named, because #ManagedProperty doesn't work in CDI(?), then how do you pass params in the URL to the facelets client? In my code, I want to pass javax.mail.getMessageNumber() to details.xhtml through the "back" and "forward" buttons.
I understand that #Inject should be used, but what is being injected and how, please?
From the glassfish logs, id is always 0, which is quite odd. Even when "forward" is clicked, id never gets above 1 no matter how many times the button is clicked. Of course, that's merely a symptom of the problem. The desired output, of course, is to advance to the next Message.
Perhaps put the Message, or at least the int, into the session?
The client as so:
<?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://java.sun.com/jsf/facelets"
template="./template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core">
<ui:define name="top">
<h:form>
<h:form>
<h:outputLink id="link1" value="detail.xhtml">
<f:param name="id" value="#{detail.back()}" />
<h:outputText value="back" />
</h:outputLink>
</h:form>
</h:form>
<h:form>
<h:outputLink id="link1" value="detail.xhtml">
<f:param name="id" value="#{detail.forward()}" />
<h:outputText value="forward" />
</h:outputLink>
</h:form>
</ui:define>
<ui:define name="content">
<h:outputText value="#{detail.content}"></h:outputText>
</ui:define>
</ui:composition>
and the bean as so:
package net.bounceme.dur.nntp;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.faces.bean.ManagedProperty;
import javax.inject.Named;
import javax.mail.Message;
#Named
#RequestScoped
public class Detail {
private static final Logger logger = Logger.getLogger(Detail.class.getName());
private static final Level level = Level.INFO;
#ManagedProperty(value = "#{param.id}")
private Integer id = 0;
private Message message = null;
private SingletonNNTP nntp = SingletonNNTP.INSTANCE;
public Detail() {
message = nntp.getMessage(id);
}
public int forward() {
logger.log(level, "Detail.forward.." + id);
id = id + 1;
logger.log(level, "..Detail.forward " + id);
return id;
}
public int back() {
logger.log(level, "Detail.back.." + id);
id = id - 1;
logger.log(level, "..Detail.back " + id);
return id;
}
public Message getMessage() {
return message;
}
public String getContent() throws Exception {
return message.getContent().toString();
}
}
This works only with the in JSF 2.3 introduced javax.faces.annotation.ManagedProperty.
#Inject #ManagedProperty("#{param.id}")
private String id;
The now deprecated javax.faces.bean.ManagedProperty annotation works only in JSF #ManagedBean classes. I.e. in instances which are managed by JSF. It does not work in instances which are managed by CDI #Named. Further, you've made another mistake: you're trying to prepare the Message based on the managed property in the constructor. If it were a real #ManagedBean, that would also not have worked. The managed property is not available during construction, simply because it's not possible to call the setter method before the constructor is called. You should have used a #PostConstruct method for this.
If you cannot upgrade to JSF 2.3, you'd need to create a custom CDI annotation. A concrete example is posted in this blog. Here's an extract of relevance:
The custom #HttpParam annotation:
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, FIELD, PARAMETER})
public #interface HttpParam {
#NonBinding
public String value() default "";
}
The annotation value producer:
public class HttpParamProducer {
#Inject
FacesContext facesContext;
#Produces
#HttpParam
String getHttpParameter(InjectionPoint ip) {
String name = ip.getAnnotated().getAnnotation(HttpParam.class).value();
if ("".equals(name)) name = ip.getMember().getName();
return facesContext.getExternalContext()
.getRequestParameterMap()
.get(name);
}
}
An usage example:
#Inject #HttpParam
private String id;
JSF utility library OmniFaces has a #Param for exactly this purpose, with builtin support for JSF conversion and validation.
Alternatively, you can also manually grab the request parameter from the external context in the Detail managed bean. The recommended way to do managed bean initialization is to use a #PostConstruct method, not the constructor, as the constructor could be used for completely different purposes than managed bean creation:
#PostConstruct
public void init() {
String id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
// ...
}
Another way, IMO also more suitable for this particular case, is to use <f:viewParam> which also allows you to convert the ID to Message directly by a custom converter.
<f:metadata>
<f:viewParam name="id" value="#{detail.message}" converter="messageConverter" />
</f:metadata>
with just
#Named
public class Detail {
private Message message;
// Getter+setter
}
and a
#FacesConverter("messageConverter")
public class MessageConverter implements Converter {
// Convert string id to Message object in getAsObject().
// Convert Message object to string id in getAsString().
}
See also
ViewParam vs #ManagedProperty(value = "#{param.id}")
Communication in JSF 2.0 - processing GET request parameters
First, to explain the alien part - Glassfish uses JBoss Weld as its CDI implementation, Oracle does not develop an implementation of its own.
And concerning the meaning of the error message: FacesContext is simply not injectable via #Inject. There is an rather old feature request for that, and I think Seam or Solder provide a producer. But there's no need to integrate either of the libraries just for that. Access faces context like you would in normal managed bean, via FacesContext.getCurrentInstance().
I was asking a complex way of doing a simple thing. In CDI, to pass params around you cannot use #ManagedProperty, as explained above by BalusC. Instead, you just setup your xhtml files as so:
<?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://java.sun.com/jsf/facelets"
template="./template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core">
<ui:define name="top">
<h:form>
<h:commandButton action="#{messages.back()}" value="..back" />
</h:form>
<h:form>
<h:commandButton action="#{messages.forward()}" value="forward.." />
</h:form>
</ui:define>
<ui:define name="content">
<h:dataTable value="#{messages.model}" var="m">
<h:column>
<f:facet name="id">
<h:outputText value="id" />
</f:facet>
<h:outputLink id="hmmm" value="detail.xhtml">
<f:param name="id" value="#{m.getMessageNumber()}" />
<h:outputText value="#{m.getMessageNumber()}" />
</h:outputLink>
</h:column>
<h:column>
<f:facet name="subject">
<h:outputText value="subject" />
</f:facet>
<h:outputText value="#{m.subject}"></h:outputText>
</h:column>
<h:column>
<f:facet name="content">
<h:outputText value="content" />
</f:facet>
<h:outputText value="#{m.sentDate}"></h:outputText>
</h:column>
<h:column>
<f:facet name="date">
<h:outputText value="date" />
</f:facet>
<h:outputLink value="#{messages.getUrl(m)}">#{messages.getUrl(m)}</h:outputLink>
</h:column>
</h:dataTable>
</ui:define>
</ui:composition>
to:
<?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://java.sun.com/jsf/facelets"
template="./template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core">
<ui:define name="top">
<h:form>
<h:outputLink id="back" value="detail.xhtml">
<f:metadata>
<f:viewParam name="id" value="#{detail.id}" />
</f:metadata>
<f:param name="id" value="#{detail.back()}" />
<h:outputText value="back" />
</h:outputLink>
</h:form>
<h:form>
<h:outputLink id="forward" value="detail.xhtml">
<f:metadata>
<f:viewParam name="id" value="#{detail.id}" />
</f:metadata>
<f:param name="id" value="#{detail.forward()}" />
<h:outputText value="forward" />
</h:outputLink>
</h:form>
</ui:define>
<ui:define name="content">
<h:outputText value="#{detail.content}"></h:outputText>
</ui:define>
</ui:composition>
I'm only including this for anyone who comes along, to clarify that, for this simple example, you don't need a Converter, that the default works fine.
The original question is more than a bit mangled, as well. From looking at other questions on this, I think others could benefit from a simple example such as this. So many examples are overly complex, or involve EJB, etc.

Resources