JSTL time travel resolution

Your variable may be assigned anything at any time if you know the secret to time travel.

Working on a ticket to address a wrong form action url being used for a different page condition, I ran across a curiosity in a jstl tag file.  It seems that the value for <c:url> was not resolving in a cascading manner as had been the intended behavior of the initial author.

The bit of code I was working on handled mapping search form that either used one of two user selectable conditions:

  1. Address/zip entered by user, which would call endpoint /mapping (and separate java controller method getMapping).
  2.  Or browser location (latitude/longitude), should you as a user allow it. This would call endpoint /mapping/location (and java controller method getLocation).

The defect: only /mapping was being used in both cases, so if a lat/long was passed getMapping would break.

The initial tag code looked like this:

<c:url value="/mapping" var="search" />
<form:form action="${mapping}" method="get" id="results" commandName="MapForm">
  <c:if test="${URL eq 'Mapping' }">
    <input type="hidden" value="${q}" name="q" />
    <c:url value="/mapping" var="search" />
  </c:if>
  <c:if test="${URL eq 'Location' }">
    <input type="hidden" value="${latitude}" name="latitude" />
    <input type="hidden" value="${longitude}" name="longitude" />
    <c:url value="/mapping/location" var="search" />
  </c:if>
  <button/>
</form:form>

In the above code the original author had intended the variable search to be assigned a value LATER based on the source of the user’s choice, but the tag never assigns it and the form action is always “/mapping”.  I looked around (rather quickly) for documentation on this and couldn’t find anything other than a few allusions to tag libraries executing in the order they are written.  This makes sense to me, because even in a jsp page compiled to a servlet, if a variable was assigned that’s the value, and if it changes later it’s previous value is not going to change of course in it’s use without time travel.  Now that I think of it, this seems pretty obvious.

My solution was to change the code to this:

<c:url value="/mapping" var="search" />
<c:if test="${URL eq 'Location' }">
    <c:url value="/mapping/location" var="search" />
</c:if>
<form:form action="${mapping}" method="get" id="results" commandName="MapForm">
  <c:if test="${URL eq 'Mapping' }">
    <input type="hidden" value="${q}" name="q" />
  </c:if>
  <c:if test="${URL eq 'Location' }">
    <input type="hidden" value="${latitude}" name="latitude" />
    <input type="hidden" value="${longitude}" name="longitude" />
  </c:if>
  <button/>
</form:form>

You know something?  Now that I look at this I have a feeling this thing wasn’t even tested!  And seriously, who would write:

int i = 4;
int j = i + 2;
i = 17;
print j;

And expect the answer to be 19?

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>