Previously on my blog I described a workaround in passing data to JSF bean method. http://community.jboss.org/people/ilya40umov/blog/2010/12/28/my-favourite-workarounds-dummymap-for-jsf-12
It's very useful when you need some simple transformation with data which you are going to display on a page or compare with something using EL.
But now I've already found and tested the best way to do it. This way is a creation of the custom EL function which performs your transformation. This solution is very elegant but it's now new. I found a lot of posts on the Internet dated 2006-... about this topic. But I just want to show you my solution and tell you what didn't work for me.
My environment consists of Jboss 5.1 + Facelets 1.1.15-B1 + JSF 1.2.
I have a tag library based on facelets in my project. It was done accordingly to http://www.ibm.com/developerworks/java/library/j-facelets/.
So at first I want to tell you what didn't work:
- using of function declaration in my taglib.xml like it's shown below didn't get me any results
<facelet-taglib>
<function>
<function-class>com.test.ElFunctions</function-class>
<function-name>isInteger</function-name>
<function-signature>boolean isInteger(java.lang.String)</function-signature>
</function>
</facelet-taglib>
- I had to create a separated library for functions because when I tried to define my custom tags in the same file as library-class it didn't work either.
Now about how it works.
1) Declaring library in web.xml
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/facelets/tags/test.functions.taglib.xml</param-value>
</context-param>
2) I created taglib file (test.functions.taglib.xml):
<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"facelet-taglib_1_0.dtd">
<facelet-taglib>
<library-class>com.test.FnLibrary</library-class>
</facelet-taglib>
3) I created FnLibrary.java
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import com.sun.facelets.tag.AbstractTagLibrary;
public final class FnLibrary extends AbstractTagLibrary {
public final static String NAMESPACE = "http://www.test.com/jsf/functions";
public static final FnLibrary INSTANCE = new FnLibrary();
public FnLibrary() {
super(NAMESPACE);
try {
Method[] methods = FunctionsLibrary.class.getMethods();
for (int i = 0; i < methods.length; i++) {
if (Modifier.isStatic(methods[i].getModifiers())) {
this.addFunction(methods[i].getName(), methods[i]);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
4) And I created FunctionsLibrary.java
public class FunctionsLibrary {
public static boolean isInteger(String value) {
if (value != null) {
try {
Integer.valueOf(value);
return true;
} catch (NumberFormatException e) {
//ignore
}
}
return false;
}
}
For using this library you just need to define prefix in your root element xmlns:tf="http://www.test.com/jsf/functions" and then you can use it in EL expressions.
So #{tf:isInteger('345')} returns true. =)
P.S. I used the following link for my final solution. It's completely based on this source. I'm just wondering why other solutions didn't work.
http://seamframework.org/Documentation/CreatingCustomELFunctions