The Black Bean Source™
User Guide for EL-Functors 1.0.2

Rationale

The standard JSP2.1 EL includes support for resolving the following:

  1. Java language arrays and java.util.List objects by numeric index
  2. java.util.Map objects by map key
  3. java.util.ResourceBundle objects by property key
  4. Bean Properties by property name (but only if the object is not a Map, List or ResourceBundle)

There is no built-in support for method access. The standard function support in the unified EL is through pluggable FunctionMappers that map expressions like ${prefix:fnName(a,b,c)} to static methods. The actual mapping can occur through a JSP2.1 taglib, or by providing a custom javax.el.FunctionMapper implementation.

Now assume you want to do something fairly simple like obtaining the lower case version of an existing string. You can't just write item.name.toLowerCase() like you would in java code. Instead you have to define a library class with a static method, like:

package mystuff;
public class MyStringUtils
{
	public static String toLowerCase(String value)
	{
		return value.toLowerCase();
	}
}

Then add a reference to this function within a tag lib, like this:

	<function>
		<name>toLowerCase</name>
		<function-class>mystuff.MyStringUtils</function-class>
		<function-signature>
			java.lang.String toLowerCase( java.lang.String )
		</function-signature>
	</function>

Then you can invoke it within a JSP/JSF page like ${f:toLowerCase(item.name)} where f is the prefix you have mapped the tag library to. [Actually, in this particular case the JSTL implementation does provide just such a taglib function -- fn:toLowerCase(), but the argument still applies, since the provided functions are still quite limited.]

A few issues with this approach are:

  1. You have to write a utility function and a tag library entry for every method you need to access (or you could write an invokeZeroParamObjectMethod type function that uses reflection. Invoking it would look like ${f:invokeZeroParamObjectMethod(item.name, toLowerCase)}. You would still need multiple versions for the different number of arguments that are possible).
  2. The syntax is slightly awkward.
  3. More significantly, you can't use it in places like the faces-config.xml managed bean initialization (which is one place that really needs it). You could get around this by defining your own FunctionMapper library that is installed with a ServletContextListener referred to in the web.xml descriptor. However the effort to do all that is almost the same as the effort to create this EL Functors resolver library.

To do the same thing with the EL-Functors library, you need to add the library to your project (as described below), and then use an expression like ${item.name.toLowerCase$}.