Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is it appropriate to set a request-scoped variable in a JSP?

In my experience, it is rarely/never necessary to set scope="request" on an EL variable.

For example, I have a page that, given an item parameter, constructs a URL specific to that item based on its properties. This page is included in any page that needs to render a link to an item.

(A) With request-scoped variables

itemLink.jsp

<%-- Accepts a parameter named 'item' --%>
<c:set var="urlTemplate" value="${param['item'].urlTemplate}" />
<c:choose>
  <c:when test="${empty urlTemplate}">
    <c:set var="itemUrl" scope="request" value="/missingProductUrl.jsp"/>
  </c:when>
  <c:otherwise>
    <c:url var="itemUrl" scope="request" value="${urlTemplate}">
      <c:param name="id" value="${param['item'].id}"/>
    </c:url>
  </c:otherwise>
</c:choose>

otherPage.jsp

<jsp:include page="itemLink.jsp">
  <jsp:param name="item" value="${currentItem}"/>
</jsp:include>

<%-- 'itemUrl' has request scope --%>
<a href="${itemUrl}">Item Link</a>

(B) Without request-scoped variables

itemLink.jsp

<%-- Accepts a parameter named 'item' --%>
<c:set var="urlTemplate" value="${param['item'].urlTemplate}" />
<c:choose>
  <c:when test="${empty urlTemplate}">
    <c:set var="itemUrl" value="/missingProductUrl.jsp"/>
  </c:when>
  <c:otherwise>
    <c:url var="itemUrl" value="${urlTemplate}">
      <c:param name="id" value="${param['item'].id}"/>
    </c:url>
  </c:otherwise>
</c:choose>

<c:out value="${itemUrl}"/>

otherPage.jsp

<c:set var="itemUrl">
  <jsp:include page="itemLink.jsp">
    <jsp:param name="item" value="${currentItem}"/>
  </jsp:include>
</c:set>

<%-- 'itemUrl' has page scope --%>
<a href="${itemUrl}">Item Link</a>

Is there any reason to use (A) over (B)? My answer is no, with the following justifications:

  • With (A), you need to remember that any other page processed during the same request will see itemUrl, and so you should avoid name collisions. It also makes tracing the source of EL variables more difficult, as there's no way to find where a request-scoped variable is set except to search through all pages that are processed during the same request.

  • With (B), none of this is an issue because variables only ever have page scope.

EDIT:

Perhaps there's a better solution than (B):

(C) Using a static include

itemLink.jspf

<%-- Accepts a parameter named 'item' --%>
<c:set var="urlTemplate" value="${param['item'].urlTemplate}" />
<c:choose>
  <c:when test="${empty urlTemplate}">
    <c:set var="itemUrl" value="/missingProductUrl.jsp"/>
  </c:when>
  <c:otherwise>
    <c:url var="itemUrl" value="${urlTemplate}">
      <c:param name="id" value="${param['item'].id}"/>
    </c:url>
  </c:otherwise>
</c:choose>

otherPage.jsp

<c:set var="item" value="${currentItem}"/>
<%@ include page="itemLink.jsp" %>

<%-- 'itemUrl' has page scope --%>
<a href="${itemUrl}">Item Link</a>

It's still the case that neither alternative, (B) nor (C), requires the use of a request-scoped variable. Is there some reason for using request scope that I've missed?

like image 632
Spencer Small Avatar asked Oct 09 '22 21:10

Spencer Small


1 Answers

This section you presented


<c:set var="itemUrl">
<jsp:include page="itemLink.jsp">
<jsp:param name="item" value="${currentItem}"/>
</jsp:include>
</c:set>

would work only if the itemLink.jsp has only the value for itemUrl and nothing else (No additional html content) But hardly is that a case.

Consider a case where you have a Car object in the request scope in your one.jsp and a link in this page takes you to a two.jsp which needs this same Car object.

Then


<c:set var="myCar" value="${requestScope.car}" scope="request"/> 

would do the job. This would be impossible with method(B).

update: As to why it would not be possible by method(B): In your snippet jsp:include includes the response of the JSP (a text) and then that is set to itemUrl. What if you needed to assign a complex object (non textual, like Car or an ArrayList ) to a request scoped attribute ? A JSP response is typically a html text.

Just putting forward an alternative, why not render this way ?



<%-- Accepts a parameter named 'item' --%>
<c:set var="urlTemplate" value="${param['item'].urlTemplate}" />
<c:choose>
<c:when test="${empty urlTemplate}">
<a href value="/missingProductUrl.jsp"/>
</c:when>
<c:otherwise>
<c:url var="itemUrl" scope="request" value="${urlTemplate}">
<c:param name="id" value="${param['item'].id}"/>
</c:url>
<c:out value="${itemUrl}"/>
</c:otherwise>
</c:choose>



<jsp:include page="itemLink.jsp">
<jsp:param name="item" value="${currentItem}"/>
</jsp:include>

All said, I have hardly had situations where c:set was needed. Normally setting of any scoped attributes is done by the servlet/controller. A JSP would just get a scoped attribute and show it. If JSPs were setting scoped attributes, it would be pretty hard to maintain. And it would be better to limit the using of c:set to only setting page scoped attributes.

like image 93
stratwine Avatar answered Oct 19 '22 10:10

stratwine