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!
Number
,Boolean
andEnum
(as long as you don't useInteger
which would get interpreted asLong
). – BalusC