Here's my FacesComponent class:
#FacesComponent("ExibicaoChecklistComponent")
public class ExibicaoChecklistComponent extends UINamingContainer {
private ListaChecklistWrapper checklist;
private String altura;
public ListaChecklistWrapper getChecklist() {
return checklist;
}
public void setChecklist(ListaChecklistWrapper checklist) {
this.checklist = checklist;
}
public String getAltura() {
return altura;
}
public void setAltura(String altura) {
this.altura = altura;
}
}
and the xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:pretty="http://ocpsoft.com/prettyfaces"
xmlns:ui="http://java.sun.com/jsf/facelets">
<cc:interface componentType="ExibicaoChecklistComponent">
<cc:attribute name="altura" default="300px" type="java.lang.String" />
<cc:attribute name="checklist" required="true" />
</cc:interface>
<cc:implementation>
Altura: #{cc.altura}
Checklist: #{cc.checklist.nome}
</cc:implementation>
and finally the usage:
<checando:exibicaoChecklist altura="200px" checklist="#{CheckBean.checklists[0]}" />
The setAltura method is called with the 200px value, but the setChecklist(ListaChecklistWrapper checklist) is not called and the checklist attribute is always null inside the component.
If I do #{CheckBean.checklists[0].nome} outside the <checando:exibi... tag it works. So, the object is not null... it's only a missing call to the set method.
Is there anything I'm missing?
Mojarra 2.1.13 (20120907-1514) and java version "1.7.0_25".
Thanks.
I guess, giving the nome directly as a parameter into the component does work again? (Something like setChecklistNome(String nome).
If so, there might be a challenge with giving direct parameters different from java.lang.String. Have you tried to give the parameters as cc.attrs.checklist instead from writing it directly into the UINamingContainer?
Related
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:
I'm trying to learn the use of #Produces methods in CDI. I have made really simple web-app to test it out. What I'm trying to do is basically is upon submission of the form pass the value of one bean (Controller) to the other (Cont).
The problem is though that the str value never gets "injected". Obviously there are other ways to do this (inject the entire controller) but I'm trying to learn this specific way.
.xhtml
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
<h:form>
<h:outputText value="Input: " />
<h:inputText value="#{str}" />
<br />
<br />
<h:outputText value="#{cont.str}" />
<br />
<br />
<h:commandButton value="Submit">
</h:commandButton>
</h:form>
</h:body>
Controller.java
#Named
#SessionScoped
public class Controller implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Produces
#Named("str")
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
Cont.java
#Named
#SessionScoped
public class Cont implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Inject
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
Change your h:inputText to use #{cont.str}
The use of a producer here is awkward. #Named is always evaluated, it's best to use a wrapper object to handle it.
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 am solving how to pass values from one page to another without making use of session scope managed bean. For most managed beans I would like to have only Request scope.
I created a very, very simple calculator example which passes Result object resulting from actions on request bean (CalculatorRequestBean) from 5th phase as initializing value for new instance of request bean initialized in next phase lifecycle.
In fact - in production environment we need to pass much more complicated data object which is not as primitive as Result defined below.
What is your opinion on this solution which considers both possibilities - we stay on the same view or we navigate to the new one. But in both cases I can get to previous value stored passed using view scoped managed bean.
Calculator 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">
<h:head>
<title>Calculator</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Value to use:"/>
<h:inputText value="#{calculatorBeanRequest.valueToAdd}"/>
<h:outputText value="Navigate to new view:"/>
<h:selectBooleanCheckbox value="#{calculatorBeanRequest.navigateToNewView}"/>
<h:commandButton value="Add" action="#{calculatorBeanRequest.add}"/>
<h:commandButton value="Subtract" action="#{calculatorBeanRequest.subtract}"/>
<h:outputText value="Result:"/>
<h:outputText value="#{calculatorBeanRequest.result.value}"/>
<h:commandButton value="Calculator2" action="calculator2"/>
<h:outputText value="DUMMY" rendered="#{resultBeanView.dummy}"/>
</h:panelGrid>
</h:form>
</h:body>
Calculator2 page with operations multiply and divide:
<?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">
<h:head>
<title>Calculator 2</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Value to use:"/>
<h:inputText value="#{calculatorBeanRequest2.valueToAdd}"/>
<h:outputText value="Navigate to new view:"/>
<h:selectBooleanCheckbox value="#{calculatorBeanRequest2.navigateToNewView}"/>
<h:commandButton value="Multiply" action="#{calculatorBeanRequest2.multiply}"/>
<h:commandButton value="Divide" action="#{calculatorBeanRequest2.divide}"/>
<h:outputText value="Result:"/>
<h:outputText value="#{calculatorBeanRequest2.result.value}"/>
<h:commandButton value="Calculator" action="calculator"/>
<h:outputText value="DUMMY" rendered="#{resultBeanView.dummy}"/>
</h:panelGrid>
</h:form>
</h:body>
</html>
Object to be passed through lifecycle:
package cz.test.calculator;
import java.io.Serializable;
/**
* Data object passed among pages.
* Lets imagine it holds something much more complicated than primitive int
*/
public class Result implements Serializable {
private int value;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
Request scoped managed bean used on view "calculator.xhtml" with actions add and subtract
package cz.test.calculator;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class CalculatorBeanRequest {
#ManagedProperty(value="#{resultBeanView}")
ResultBeanView resultBeanView;
private Result result;
private int valueToAdd;
/**
* Should perform navigation to
*/
private boolean navigateToNewView;
/** Creates a new instance of CalculatorBeanRequest */
public CalculatorBeanRequest() {
}
#PostConstruct
public void init() {
// Remember already saved result from view scoped bean
result = resultBeanView.getResult();
}
// Dependency injections
public void setResultBeanView(ResultBeanView resultBeanView) {
this.resultBeanView = resultBeanView;
}
public ResultBeanView getResultBeanView() {
return resultBeanView;
}
// Getters, setter
public void setValueToAdd(int valueToAdd) {
this.valueToAdd = valueToAdd;
}
public int getValueToAdd() {
return valueToAdd;
}
public boolean isNavigateToNewView() {
return navigateToNewView;
}
public void setNavigateToNewView(boolean navigateToNewView) {
this.navigateToNewView = navigateToNewView;
}
public Result getResult() {
return result;
}
// Actions
public String add() {
result.setValue(result.getValue() + valueToAdd);
return isNavigateToNewView() ? "calculator" : null;
}
public String subtract() {
result.setValue(result.getValue() - valueToAdd);
return isNavigateToNewView() ? "calculator" : null;
}
}
Request scoped managed bean used on view "calculator2.xhtml" with actions divide and multiply:
package cz.test.calculator;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class CalculatorBeanRequest2 {
#ManagedProperty(value="#{resultBeanView}")
ResultBeanView resultBeanView;
private Result result;
private int valueToUse;
/**
* Should perform navigation to
*/
private boolean navigateToNewView;
/** Creates a new instance of CalculatorBeanRequest2 */
public CalculatorBeanRequest2() {
}
#PostConstruct
public void init() {
result = resultBeanView.getResult();
}
// Dependency injections
public void setResultBeanView(ResultBeanView resultBeanView) {
this.resultBeanView = resultBeanView;
}
public ResultBeanView getResultBeanView() {
return resultBeanView;
}
// Getters, setter
public void setValueToAdd(int valueToAdd) {
this.valueToUse = valueToAdd;
}
public int getValueToAdd() {
return valueToUse;
}
public boolean isNavigateToNewView() {
return navigateToNewView;
}
public void setNavigateToNewView(boolean navigateToNewView) {
this.navigateToNewView = navigateToNewView;
}
public Result getResult() {
return result;
}
// Actions
public String multiply() {
result.setValue(result.getValue() * valueToUse);
return isNavigateToNewView() ? "calculator2" : null;
}
public String divide() {
result.setValue(result.getValue() / valueToUse);
return isNavigateToNewView() ? "calculator2" : null;
}
}
and finally view scoped managed bean to pass Result variable to new page:
package cz.test.calculator;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
#ManagedBean
#ViewScoped
public class ResultBeanView implements Serializable {
private Result result = new Result();
/** Creates a new instance of ResultBeanView */
public ResultBeanView() {
}
#PostConstruct
public void init() {
// Try to find request bean ManagedBeanRequest and reset result value
CalculatorBeanRequest calculatorBeanRequest = (CalculatorBeanRequest)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("calculatorBeanRequest");
if(calculatorBeanRequest != null) {
setResult(calculatorBeanRequest.getResult());
}
CalculatorBeanRequest2 calculatorBeanRequest2 = (CalculatorBeanRequest2)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("calculatorBeanRequest2");
if(calculatorBeanRequest2 != null) {
setResult(calculatorBeanRequest2.getResult());
}
}
/** No need to have public modifier as not used on view
* but only in managed bean within the same package
*/
void setResult(Result result) {
this.result = result;
}
/** No need to have public modifier as not used on view
* but only in managed bean within the same package
*/
Result getResult() {
return result;
}
/**
* To be called on page to instantiate ResultBeanView in Render view phase
*/
public boolean isDummy() {
return false;
}
}
Your question asks about how to pass values from one page to another without making use of session scope managed bean, but in your example I don't actually see different pages.
You stay on the same page (view) all the time. JSF components automatically retain their values in the so-called view state, so there is no need for you to pass anything along manually here.
If you really wanted to pass information between completely different pages (e.g. from a calculator.xthml to a result_overview.xhtml) then one possible solution would be using the conversation scope from Java EE 6. If you are only using the JSF 2.0 libs on e.g. Tomcat, you can't use this scope, but if you added a CDI implementation or deployed to a full Java EE AS like Glassfish V3 or Jboss AS 6 then you could use this.
The conversation scope really works between pages, but there is a small catch in that you have to change your managed beans from #ManagedBean to #Named and have to realize you would be using CDI beans and not JSF managed beans. They mostly interoperate, but there are a number of caveats.
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.