JSTL time travel resolution
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:
- Address/zip entered by user, which would call endpoint /mapping (and separate java controller method getMapping).
- 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?