2011-07-11

Defining custom EL functions

I've been working on porting my sandbox webapp to Spring WebMVC, and in the process I've been learning more about JSP as well. This work led me to ask a question at StackOverflow, a favorite site of mine for a while for finding solutions to problems, though I've only recently begun participating.
In the question I asked about the best way to sort a single List in different ways in JSP, and I didn't get any answers that I really liked, so I kept looking and found an answer that I was able to use to suit my needs. You can see my solution at StackOverflow, but I'll reproduce it here as well.
The solution is to define an EL function, and any public static method will work.
package org.hierax.ifdl.tags.player;

public final class SortFunction {
    public static List<Player> sortByRank(List<Player> playerList) {
        Collections.sort(playerList, new PlayerSortByRank());
        return playerList;
    }
    
    public static List<Player> sortByAlias(List<Player> playerList) {
        Collections.sort(playerList, new PlayerSortByAlias());
        return playerList;
    }
}
EL functions need to be defined in a taglib TLD using the function element instead of tag. Although my EL function methods used generics, they aren't supported in the function-class or function-signature elements; no problem, just use the plain type.
<?xml version="1.0" encoding="UTF-8" ?>
<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-jsptaglibrary_2_1.xsd"
    version="2.1">
    
    <display-name>Player Functions</display-name>
    <tlib-version>1.0</tlib-version>
    <short-name>player</short-name>
    <uri>org.hierax.ifdl.tags</uri>
    
    <function>
        <name>sortByRank</name>
        <function-class>org.hierax.ifdl.tags.player.SortFunction</function-class>
        <function-signature>java.util.List sortByRank(java.util.List)</function-signature>
    </function>
    
    <function>
        <name>sortByAlias</name>
        <function-class>org.hierax.ifdl.tags.player.SortFunction</function-class>
        <function-signature>java.util.List sortByAlias(java.util.List)</function-signature>
    </function>

</taglib>
Here's how I used the EL function in one of my JSPs.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="p" uri="/WEB-INF/player.tld" %>

<h1>Players</h1>
<p>
    <c:forEach items="${p:sortByAlias(model.players)}" var="player">
        <a href="<c:url value="/player/${player.id}"/>" class="menuItem">${player.alias}</a>
    </c:forEach>
</p>
The point of all this is to avoid using scriptlets (java code surrounded by <% and %>), and there are several good reasons to do so.
  • EL functions can be tested; a scriptlet cannot.
  • EL functions can be re-used by other Java code or in JSPs; scriptlets cannot.
  • EL functions help keep Java code out of what should be your view layer; theoretically this makes it easier to have a non-Java person make changes to your display logic.

2 comments:

  1. hello. I'm trying to implement your code in my spring mvc webapp (with eclipse as IDE).

    I compiled the class as a jar file and added the jar file into my build path.

    When I try adding the taglib "command" in my JSP file, eclipse can't see it. The exact error is "Can not find the tag library descriptor for "/WEB-INF/mytaglib.tld".

    Any ideas? thanks very much

    ReplyDelete
  2. Hi Jayel, I recommend trying the solutions provided to a similar question to yours on StackOverflow.

    ReplyDelete