JSF, Composite Component: method call with default attribute value as parameter - jsf-2

I am new to JSF and still learning. I tried searching for a solution to my specific problem described below but I could not find anything. If it because I was searching for the wrong things, please point me in the right direction, but hopefully it is something that hasn't been answered and an answer can benefit everyone.
The following example illustrates the problem I came across. The example is simplified to focus on the problem and to hide the complexities of the actual project in which the problem occurred.
Consider the following pages / classes:
/resources/test/custom.xhtml;
/test/CharsetProvider.java;
/test/CharsetHello.java;
/testWith.xhtml;
/testWithout.xhtml;
/resources/test/custom.xhtml
This is composite component with one attribute with a default value. The component simply takes the attribute value and passes it as an argument to the CDI bean described below in order obtain the model object used for output.
<?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">
<cc:interface>
<cc:attribute name="charset"
default="#{charsetProvider.defaultCharset}"
type="java.nio.charset.Charset" />
</cc:interface>
<cc:implementation>
<h:outputText value="#{charsetProvider.createCharsetHello(cc.attrs.charset).hello}"/>
</cc:implementation>
</html>
test/CharsetProvider.java
This is a CDI bean that simply contains a default value used throughout the application and has a method that creates an object used as the model for a component. The reason I use a CDI bean instead of a backing bean is because in my specific project the default value needs to be injected at runtime, but backing beans are not candidates for injection.
package test;
import java.nio.charset.Charset;
import javax.annotation.PostConstruct;
import javax.faces.bean.SessionScoped;
import javax.inject.Named;
#Named
#SessionScoped
public class CharsetProvider {
private Charset defaultCharset;
#PostConstruct
protected void postConstruct() {
this.defaultCharset = Charset.forName("UTF-8");
}
public Charset getDefaultCharset() {
return defaultCharset;
}
public Charset getCharsetForName(String name) {
return Charset.forName(name);
}
public CharsetHello createCharsetHello(Charset cs) {
return new CharsetHello(cs);
}
}
test/CharsetHello.java
This is the "model" object. It simply converts "Hello world!" to a byte array and back using the given charset.
package test;
import java.nio.charset.Charset;
public class CharsetHello {
private static final String HW = "Hello World!";
private final byte[] data;
private final Charset cs;
public CharsetHello(Charset cs) {
this.cs = cs;
this.data = CharsetHello.HW.getBytes(this.cs);
}
public String getHello() {
return new String(this.data, this.cs);
}
}
testWith.xhtml
This is a test page that uses the composite component defined above by specifying a value for the component's attribute. The page renders properly, i.e. "Hello World!" prints on the screen.
<?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"
xmlns:test="http://java.sun.com/jsf/composite/test">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<test:custom charset="#{charsetProvider.getCharsetForName('UTF-16')}" />
</h:body>
</html>
testWithout.xhtml
This is a test page that does not pass a custom value to the component's attribute, intending to use the default value.
<?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"
xmlns:test="http://java.sun.com/jsf/composite/test">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<test:custom />
</h:body>
</html>
The page above results in a JSF error page with the following message:
/resources/test/custom.xhtml #14,94 value="#{charsetProvider.createCharsetHello(cc.attrs.charset).hello}": Cannot convert UTF-8 of type class java.lang.String to class java.nio.charset.Charset
It seems that in the last case the default value is converted to a java.lang.String before being passed to the method.
First off, is this the expected behaviour and why?
If this is the expected behaviour, can you suggest a different implementation?
Thank you in advance!

This problem has exactly the same ground as this problem: FacesConverter forClass don't work with Composite Componet. The composite attribute value type is in Mojarra incorrectly been evaluated as java.lang.Object instead of the actual model type.
It's been reported as Mojarra issue 2568. It works in MyFaces 2.1.9.

Related

Bean or property class for managed bean cannot be found

I'm trying to make a simple JSF hello world, with JSF 2.0, JBoss AS 7.0
Here's my xhml file :
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Page 1</title>
</h:head>
<body>
<f:view>
<h:outputLabel value="Hello Stock Manager Hello JSF again" />
<br/>
<h:outputLabel value="Tester Bean : #{testerBean.message}" />
</f:view>
</body>
</html>
and here's the managed bean class :
package prv.stockmanager.web.beans;
public class TesterBean {
private String message = "This is a message";
public TesterBean() {
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
And here's the faces-config (which is in the web-inf) :
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
<managed-bean>
<managed-bean-name>testerBean</managed-bean-name>
<managed-bean-class>prv.stockmanager.web.beans.TesterBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property> <property-name>message</property-name>
<property-class>java.lang.String</property-class>
<value/>
</managed-property>
</managed-bean>
</faces-config>
The page works fine without exception if I remove the call to the managed bean. But when I call the managed bean I get this :
Bean or property class prv.stockmanager.web.beans.TesterBean for managed bean testerBean cannot be found.
at com.sun.faces.mgbean.BeanManager.create(BeanManager.java:265) [jsf-impl-2.1.3-b02-jbossorg-2.jar:2.1.3-SNAPSHOT]
at com.sun.faces.el.ManagedBeanELResolver.resolveBean(ManagedBeanELResolver.java:244) [jsf-impl-2.1.3-b02-jbossorg-2.jar:2.1.3-SNAPSHOT]
Is it because JBoss AS 7.0 is using JSF 2.1 jar file or something? Should I use JSF 2.1 then? How to change that?
Problem resolved, I figured out that Eclipse is not generating the class. I disabled the automatic build and it worked fine. There should be a problem with JBoss Studio that I am using.

Creating ICEfaces application example connecting beans and Facelets

I'm new in developing web applications and I installed the ICEfaces plugin. I found this tutorial to learn how to work with it and the first given example dont work in my IDE.
Its about the last part of the tutorial where it shows how to use a dateTimeEntry in a webapp.
So I followed the instructions so that my index.xhtml looks like this:
<?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:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:icecore="http://www.icefaces.org/icefaces/core"
xmlns:ace="http://www.icefaces.org/icefaces/components"
xmlns:ice="http://www.icesoft.com/icefaces/component">
<h:body>
<form>
<ace:dateTimeEntry id="dateTimeEntryId"
value="#{yourBean.selectDateProperty}" timeZone="Canada/Mountain"
pattern="MMM/dd/yyyy" style="width: 729px; " renderAsPopup="true">
</ace:dateTimeEntry><br />
</form>
</h:body>
</html>
And my java bean like this:
package org.icefaces.view;
import java.io.Serializable;
import java.util.Date;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.icefaces.ace.event.DateSelectEvent;
#ManagedBean(name= "yourBean")
#ViewScoped
public class YourBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5058131064162864510L;
private Date selectDateProperty = new Date(System.currentTimeMillis());
public Date getSelectDateProperty() {
return selectDateProperty;
}
public void setSelectDateProperty(Date selectDateProperty) {
this.selectDateProperty = selectDateProperty;
}
public void dateSelectListener(DateSelectEvent event) {
setSelectDateProperty(event.getDate());
}
}
The structure of the project looks like this:
The point is, that in the tutorial there is no location given where to save the java beans. So I thougt it has to saved in the java resources directory, but I'm not sure because the app dont work. I just get a blank screen. The server and the configuration of it is valid I think because I can drop some Img or buttons and see the result in the browser. So I think I did not really understand how the java beans are connected with the xhtml files. I thougt it works with ManagedBean - attribute but I'm not sure about that.
Complete list of sample codes you can find here
http://anonsvn.icesoft.org/repo/icefaces3/trunk/icefaces/samples
Well I found out, that the connection of the javabeans and the variables in the xhtml file has to created in faces-config.xml in this form:
<managed-bean>
<managed-bean-name> [bean-name-of-java-class] </managed-bean-name>
<managed-bean-class> [fullpath-to-java-file] </managed-bean-class>
<managed-bean-scope>[scope]</managed-bean-scope>
</managed-bean>

Obtaining the clientId of the parent of a JSF2 composite component

I've got the following code:
<h:dataTable id="dt" value="#{somelist}" var="entry">
<h:column>
#{entry.title}
</h:column>
<h:column>
<h:commandLink id="lnk">
<mycomp:doSomething id="dummy" />
</h:commandLink>
</h:column>
</h:dataTable>
My composite component (mycomp:doSomething) looks like this:
<?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"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
</composite:interface>
<composite:implementation >
<script type="text/javascript">
// #{component.parent.clientId}
</script>
</composite:implementation>
</html>
I would expect the output (#{component.parent.clientId}) to be something similar to this: dt:0:lnk but instead it returns dt:0:dummy i.e. the client ID of the composite component.
How do I get the ID of the real parent tag?
Use #{cc.parent.clientId} instead. All content inside composite:implementation is inside a UIPanel that is on a facelet inside the composite component base instance, which usually is a NamingContainer.
UPDATE: Checking the code, cc.parent resolves the parent composite component instead of the immediate parent. It seems to be an old implementation detail, but it is not mentioned in the spec. The solution proposed in this answer does not work :(.
See http://lists.jboss.org/pipermail/jsr-314-open-mirror/2010-February/002474.html
You can bypass the resolution of cc.parent, providing a custom component class extending UINamingContainer and adding this:
<composite:interface componentType="my.custom.ComponentBaseClass">
then add a getter like
public UIComponent getImmediateParent()
{
return getParent();
}
and finally use #{cc.immediateParent.clientId}. It should work in this way.

Can't use composite component on same page with a ui:include that relies on ui:params

I have a base page that uses a ui:include to include another page. The ui:include uses a ui:param to pass a parameter to the included page. The param is read in the PostConstruct method of the included page's controller.
This design works fine until I add a composite component to the base page; once added, the included page controller reports that the ui:param's value is null. Once I remove the composite component from the page, the ui:param is able to be read (i.e. is not null) by the included page's controller. Please help!
Files to reproduce the problem:
myPage.xhtml
<html xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:mycomponents="http://java.sun.com/jsf/composite/mycomponents">
<ui:include src="includePage.xhtml">
<ui:param name="myParam" value="myValue"/>
</ui:include>
<p/>
<mycomponents:myComponent/>
</html>
myIncludedPage.xhtml
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets">
The value of the param is: #{includedPageController.myParam}
</ui:composition>
myComponent.xhtml (placed in "resources/mycomponents")
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface/>
<composite:implementation>
I am the composite component
</composite:implementation>
</html>
IncludedPageController.java
#ManagedBean
public class IncludePageController
{
String myParam;
#PostConstruct
private void init()
{
FaceletContext faceletContext = (FaceletContext)FacesContext.getCurrentInstance().
getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
myParam = (String)faceletContext.getAttribute("myParam");
}
public String getMyParam()
{
return myParam;
}
public void setMyParam(String myParam)
{
this.myParam = myParam;
}
}
See: How do I set Managed Bean field to the value of a ui:param?. There is no standard for doing this sort of thing in the JSF API. A composite or custom component should be used rather than an include/param tag combination.

Accessing JSF2 composite component attributes in backing component

I'm developing a JSF2/Primefaces app and I'm having trouble with accessing attributes defined in an interface of a composite component in this component's backing bean.
My component is defined as follows:
<!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"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface componentType="testComponent">
<composite:attribute name="text" required="true" type="java.lang.String" />
</composite:interface>
<composite:implementation>
<h:outputText value="Passed text is: #{cc.attrs.text}" />
</composite:implementation>
</html>
It is stored in a file called text.xhtml located in: application/src/main/webapp/resources/my_component directory.
I use this component on another page (which is a Facelets composition element) like so:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:myc="http://java.sun.com/jsf/composite/my_component"
template="./resources/templates/template.xhtml">
<ui:define name="content">
<h:form id="products">
<myc:test id="test" text="A text" />
</h:form>
</ui:define>
</ui:composition>
The backing component class is defined as follows:
package my.application.component;
import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#FacesComponent ( value="testComponent" )
public class TestComponent extends UINamingContainer {
Logger log = LoggerFactory.getLogger(TestComponent.class);
public TestComponent() {
log.debug("TestComponent constructor");
log.debug("getAttributes().size(): " + getAttributes().size());
}
}
The component itself works as expected. The using page renders Passed text is: A text output.
Also, logger output displays log messages from TestComponent constructor, so it seems that the component xml definition is correctly bound with the TestComponent class.
Now, the problem is that the getAttributes() method invoked in TestComponent constructor always returns a zero-sized map.
If I understand this correctly, I should be able to access the text attribute declared in component's interface using a call:
getAttributes().get("text");
in the TestComponent class, but it always returns null as the attributes map is empty.
I also tried to access the text attribute using a call:
String text = FacesContext.getCurrentInstance().getApplication().
evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{cc.attrs.text}", String.class));
but it also resolves to null.
What am I doing wrong? Any tips will be much appreciated as I have no idea what to try next.
/Tukasz.
My guess is that the constructor is too early to reference those attributes.
JSF will construct an instance of the backing component first, and will then at some point give it a reference to its attributes. In a method that's called later, eg the encode method, you should have access to them.

Resources