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>

15 thoughts on “JSTL empty operator

  1. 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!

  2. 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:

  3. 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 []

  4. 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:

  5. 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!

  6. 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.

  7. 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 to Dean Cancel reply