52

Im new to JSF 2. My question is related to BalusC's answer to this question jsf2 ajax update parts based on request parameters I tried the kickstart code BalusC posted and I encountered an EL parsing error:

 /nameofpage.xhtml @12,64 rendered="#{bean.panels.contains('u1')}"
 Error Parsing: #{bean.panels.contains('u1')}

I guess that this is caused because I'm not running a Servlet 3.0 / EL 2.2 capable container with a /WEB-INF/web.xml declared as per Servlet 3.0 spec. I'm using Tomcat 6.

BalusC suggested in his answer to create a custom EL function. But how do I accomplish this using a custom EL function? Or can this be fixed by just configuring certain parts of my project?

Below is my web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.jsf</url-pattern>
  </servlet-mapping>
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>    
  </context-param>      
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>
Community
  • 1
  • 1
royjavelosa
  • 2,048
  • 6
  • 30
  • 46

1 Answers1

90

First create a final class with a public static method which does exactly the job you want:

package com.example;

import java.util.Collection;

public final class Functions {

    private Functions() {
        // Hide constructor.
    }

    public static boolean contains(Collection<Object> collection, Object item) {
        return collection.contains(item);
    }

}

Then define it as a facelet-taglib in /WEB-INF/functions.taglib.xml:

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    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-facelettaglibrary_2_0.xsd"
    version="2.0">
    <namespace>http://example.com/functions</namespace>

    <function>
        <function-name>contains</function-name>
        <function-class>com.example.Functions</function-class>
        <function-signature>boolean contains(java.util.Collection, java.lang.Object)</function-signature>
    </function>
</facelet-taglib>

Then familarize Facelets with the new taglib in the existing /WEB-INF/web.xml:

<context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/functions.taglib.xml</param-value>
</context-param>

(note: if you already have the javax.faces.FACELETS_LIBRARIES definied, then you can just add the new path semicolon separated)

Then define it in the Facelets XHTML file as new XML namespace:

<html 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:func="http://example.com/functions"
    ...
>

Finally you can use it as intended:

rendered="#{func:contains(bean.panels, 'u1')}"

As a completely different alternative, you can also include JBoss EL in your project. It works on Tomcat 6.0 and you'll be able to invoke non-getter methods in EL. Drop jboss-el.jar file in /WEB-INF/lib and add the following to your web.xml:

<context-param>     
    <param-name>com.sun.faces.expressionFactory</param-name>
    <param-value>org.jboss.el.ExpressionFactoryImpl</param-value>   
</context-param>

Since EL 2.2 there's another approach: create an @ApplicationScoped bean with methods in turn referring to those static functions. See also a.o. Utility methods in application scoped bean.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks for the quick reply BalusC !!! I tried the jobss-el.jar approach. The error is now gone, it displays 3 check boxes u1, u2, u3 but when i choose any of them nothing seems to happen (Chrome,Firefox) I also tested in Internet Exporer and after checking any of the check box it says: Webpage error details Message: 'mojarra' is undefined Line: 9 Char: 1 Code: 0 URI: http://localhost:8080/myproject/ajaxcall.jsf Am I missing anything? Thanks for your patience and thank you in advance BalusC – royjavelosa Aug 16 '11 at 16:33
  • You're welcome. Your new question is actually a different question which needs to be asked by `Ask Question` button on the right top. Your initial question has been answered. Anyway, here's a hint: ``. – BalusC Aug 16 '11 at 16:37
  • Thanks again BalusC the jobss-el.jar approach worked like a charm! I'll ask my new question using the Ask Question. – royjavelosa Aug 16 '11 at 16:55
  • Hi BalusC. Is there a way to add description to the custom EL, so like when we inside Netbean for example, we can Ctrl + space to show to description of the function? – Thang Pham Aug 22 '12 at 18:42
  • 2
    Yes, you can use `` tag for this: `Your description here....`. – BalusC Aug 22 '12 at 19:33
  • @Thank you BalusC. Just one more question. Can we do custom EL with overload methods. I have two overload methods(same method name, different number of parameters), JSF generates error as below: `Function 'util:transform' specifies 2 params, but 1 were declared`. I have them as two separated ``. – Thang Pham Aug 23 '12 at 19:27
  • 1
    @Thang: no, that isn't possible. Each overloaded EL method must have a different EL function name. – BalusC Aug 23 '12 at 19:29
  • Thank you. That is definitely a very bad limitation on JSF/JSP. – Thang Pham Aug 23 '12 at 19:33
  • Hello, can I ask when do you recommend which approach? jBoss or the final class etc, etc, etc.? In what do they differ? – Roger Jan 14 '13 at 19:33
  • @Roger: JBoss EL saves EL functions boilerplate code. Note that whatever JBoss EL does is also supported in EL 2.2. So if you happen to use Servlet 3.0 / EL 2.2 already, then you can just invoke non-getter methods in EL. – BalusC Jan 14 '13 at 20:16
  • Hello BalusC, does this work if we don't use facelets for rendering, and we have jsp:root ? I mean if it also works in #{} not in ${} – Cosmin Cosmin Dec 19 '13 at 10:19
  • @Cosmin: just create a JSP TLD file instead of Facelets taglib XML file. Syntax is very similar. You can find an example of the JSP TLD file at the bottom of our EL wiki page under the section "EL functions": http://stackoverflow.com/tags/el/info – BalusC Dec 19 '13 at 10:49
  • yes but I want to use it in Deffered EL, with #{}, not with ${} :( – Cosmin Cosmin Dec 19 '13 at 10:51