JSTL empty operator

A teammate and I were foiled by an interesting JSTL quirk this week. The code looked something like this

<c:if test="${not empty aquarium.fish}">
    <!---- feed the fish or something ---->
</c:if>

THE PROBLEM

The problem was, the fish were being fed whether the aquarium was empty or not.

The code

<c:if test="${!empty aquarium.fish}">

behaved the same, weird way. But we were sure, either way, that our syntax was correct. So that leaves only one question: WTF?

We know that we’re receiving an instance of aquarium from a method call developed by another team. We know that getFish() returns a java.util.Collection. Other than that we don’t care about the implementation, we just want our fish. In theory.

So we dug into the code for the other team’s getFish() method, and found out that our Collection is actually implemented as a HashSet. And JSTL behaves a little weird with respect to the empty operator: it does not work with java.util.Set. Incidentally this isn’t a problem in JSTL 1.1 or 1.2, and unfortunately we’re stuck using JSTL 1.0 for now. So unfortunately this forces us to know how this Collection is implemented in order to know how to handle it.

WHY?

As of JSTL 1.1, “… the Expression Language now belongs to the JSP specification (JSP 2.0).” [from the JSTL 1.1 spec]

Since versions numbers don’t always line up such that it’s clear what is compatible with what, here’s a view of which JSTL versions go with which JSP versions:

JSTL 1.0>JSP 1.3;  JSTL 1.1>JSP 2.0;  JSTL 1.2>JSP 2.1;

Now let’s compare the specs for the empty operator

From the JSTL 1.0 Spec:

To evaluate empty A:

  • If A is null, return true,
  • Otherwise, if A is the empty string, then return true.
  • Otherwise, if A is an empty array, then return true.
  • Otherwise, if A is an empty Map, return true
  • Otherwise, if A is an empty List, return true,
  • Otherwise return false.

From the JSP 2.0 and 2.1 Spec, which are identical in this regard:

To evaluate empty A:

  • If A is null, return true,
  • Otherwise, if A is the empty string, then return true.
  • Otherwise, if A is an empty array, then return true.
  • Otherwise, if A is an empty Map, return true
  • Otherwise, if A is an empty Collection, return true,
  • Otherwise return false.

The difference is the last comparison. The older version uses the List interface, the newer uses Collection interface. List is a sub-interface of Collection, so anything that’s a Collection but not also a List will not work in JSTL 1.0. For example:

  • The “empty” keyword in JSTL will work for things like List, ArrayList, LinkedList, Vector, etc.
  • The “empty” keyword in JSTL will not work for Set, HashSet, TreeSet, etc.

REFACTOR

There’s 2 options around this.

1: upgrade.

2: If that’s not an option, there is another workaround.

The nice thing about “empty” is that it will check for both null and empty lists for you. Our workaround had to be a little more verbose:

<c:if test="${aquarium.fish != null && !aquarium.fish['empty']}">
    <!---- feed the fish or something ---->
</c:if>
About these ads
Posted in code. Tags: . 15 Comments »

15 Responses to “JSTL empty operator”

  1. Dean Says:

    I trust that no actual fish were harmed in the testing of this bug…? :-)

  2. Gayle Says:

    Of course not! :)

  3. Josh Says:

    I just wanted to let you know that I used this post to determine which JSTL version I should use with JSP 2.0. Thanks for posting this!

  4. Gayle Says:

    Hey great! It’s nice to know that it helped someone! :)

  5. marcpeabody Says:

    Wow, that’s freakin’ weird the spec used to specify List instead of Collection. Thanks for that, Gayle.

    By the way, straight dotted notation should have also worked to call isEmpty on Set:

  6. marcpeabody Says:

    <c:if test=”${aquarium.fish != null && !aquarium.fish.empty}”>…

  7. Gayle Says:

    Finally got a chance to try this, and I’m getting an error when I try Marc’s idea (which totally seems like it should work b/c I know HashSet has an isEmpty method). Something I’m missing?

    jsp.error.tlv.invalid.page
    5: tag = ‘if’ / attribute = ‘test’: An error occurred while parsing custom action attribute “test” with value “${aquarium.fish != null && !aquarium.fish.empty}”: Encountered “empty”, expected one of []

  8. Doug Says:

    I ran into the same thing with a TreeSet. ‘empty’ seems to be treated as a keyword when using dotted notation.

    Try this workaround, it worked for me:

  9. Anjali Says:

    That’s a cool solution, thanks for this posting.

  10. Abdel Olakara Says:

    thank Gayle for the post. :)

  11. opi Says:

    did you try to feed the bug to the fish?

  12. salik Says:

    Thank you

  13. Cuco Says:

    I was having the same problem but using JSTL on JEE 5 (no idea which version of JSTL it is, i think it is 1.1).

    As far as i have figured out, JSTL doesnt evaluate any functions on the parameters. It handles them as POJOs (only properties with setters and getters). But i found there is a function library on JSTL. Its very small, but helps to handle this problem, so check out this:
    http://java.sun.com/javaee/5/docs/tutorial/doc/bnalg.html

    Good luck!

  14. John J Says:

    I wish it worked on anything with an isEmpty method. It’s frustrating that you can’t use ${empty thing} or ${thing.empty} on a thing that has an empty method. The first doesn’t work because it does not have the right interface, the second is a syntax error because “empty” is a keyword in jstl.

  15. Neha garg Says:

    I am trying to check whether the Map is null or not using : and it is returning true even when the map is not empty. Tried doing – and it returns true as well. Is there a way to resolve this?


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: