JSP and JSTL Tutorials - Herong's Tutorial Notes
Dr. Herong Yang, Version 3.09, 2006

JSTL - Core Library

Part:   1  2  3  4 

JSP/JSTL Tutorials - Herong's Tutorial Notes © Dr. Herong Yang

Using Cookies

Using JavaBean Classes

HTTP Response Header Lines

Non ASCII Characters

JSTL and Expression Language

File Upload

Execution Context

JSP Elements

JSP Standard Tag Libraries (JSTL)

JSP Custom Tag

... Table of Contents

(Continued from previous part...)

I am not showing you the output here. But it is correct. Trust me. As you can see in the source code, I am not breaking the loop on "j" when "i" has already been approved as a non-prime number, because I don't know how.

One of the emails I received after publishing the above notes suggests me to insert a Java break statement through a scriptlet to break the "forEach" tag. To try this idea, I revised my JSP page to JstlPrimeNumbersRevised.jsp:

<?xml version="1.0"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
   xmlns:c="http://java.sun.com/jstl/core" version="1.2"> 
<!-- JstlPrimeNumbersRevised.jsp - Compilation error
     Copyright (c) 2004 by Dr. Herong Yang
-->
<jsp:directive.page contentType="text/html"/>
<html><body>
<p>Checking prime numbers:</p>
<c:set var="upperLimit" value="${20}"/>
<c:forEach var="i" begin="${3}" end="${upperLimit}">
 <c:set var="isPrime" value="${true}"/>
 <c:forEach var="j" begin="${2}" end="${i-1}">
  <c:if test="${i%j == 0}">
   <c:set var="isPrime" value="${false}"/>
   <jsp:scriptlet>break;</jsp:scriptlet>
  </c:if>
 </c:forEach>
 <c:choose>
  <c:when test="${isPrime}">
   <c:out value="${i} is a prime number."/><br/>
  </c:when>
  <c:otherwise>
   <c:out value="${i} is a not prime number."/><br/>
  </c:otherwise>
 </c:choose>
</c:forEach>
</body></html>
</jsp:root>

If the scriptlet statement can merge with the JSTL tags nicely, the logic will work. However if you view this page, you will get a compilation error saying that there is an unreachable statement. If you open the converted Java class file of the JSP page, JstlPrimeNumbersRevised_jsp.java, you will see:

......
   /* ----  c:forEach ---- */
   org.apache.taglibs.standard.tag.el.core.ForEachTag _jspx_th_c_fo...
   _jspx_th_c_forEach_1.setPageContext(pageContext);
   _jspx_th_c_forEach_1.setParent(_jspx_th_c_forEach_0);
   _jspx_th_c_forEach_1.setVar("j");
   _jspx_th_c_forEach_1.setBegin("${2}");
   _jspx_th_c_forEach_1.setEnd("${i-1}");
   try {
     int _jspx_eval_c_forEach_1 = _jspx_th_c_forEach_1.doStartTag();
     if (_jspx_eval_c_forEach_1 != javax.servlet.jsp.tagext.Tag.SKI...
       do {
         /* ----  c:if ---- */
         org.apache.taglibs.standard.tag.el.core.IfTag _jspx_th_c_i...
         _jspx_th_c_if_0.setPageContext(pageContext);
         _jspx_th_c_if_0.setParent(_jspx_th_c_forEach_1);
         _jspx_th_c_if_0.setTest("${i%j == 0}");
         int _jspx_eval_c_if_0 = _jspx_th_c_if_0.doStartTag();
         if (_jspx_eval_c_if_0 != javax.servlet.jsp.tagext.Tag.SKIP...
           do {
             if (_jspx_meth_c_set_2(_jspx_th_c_if_0, pageContext))
               return;
   break;
             int evalDoAfterBody = _jspx_th_c_if_0.doAfterBody();
             if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTa...
               break;
           } while (true);
         }
         if (_jspx_th_c_if_0.doEndTag() == javax.servlet.jsp.tagext...
           return;
         _jspx_tagPool_c_if_test.reuse(_jspx_th_c_if_0);
         int evalDoAfterBody = _jspx_th_c_forEach_1.doAfterBody();
         if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EV...
           break;
       } while (true);
     }
     if (_jspx_th_c_forEach_1.doEndTag() == javax.servlet.jsp.tagex...
       return;
   } catch (Throwable _jspx_exception) {
     _jspx_th_c_forEach_1.doCatch(_jspx_exception);
   } finally {
     _jspx_th_c_forEach_1.doFinally();
     _jspx_tagPool_c_forEach_var_end_begin.reuse(_jspx_th_c_forEach...
   }
   if (_jspx_meth_c_choose_0(_jspx_th_c_forEach_0, pageContext))
     return;
   int evalDoAfterBody = _jspx_th_c_forEach_0.doAfterBody();
   if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BOD...
     break;
......

The reason for the compilation error is clear. The c:forEach tag has been converted to a Java "while" loop by the JSTL 1.0 tag class - no surprise. However the c:if tag is also converted to a Java "while" loop - big surprise. The break statement provided by the scriptlet is placed in the middle of a while loop without if condition, and it causes the code not reachable compilation error.

So there is still no easy way to break a c:forEach tag.

Can someone confirm that if JSTL 1.1 is still converting c:if into a "while" loop?

Part:   1  2  3  4 

Dr. Herong Yang, updated in 2006
JSP and JSTL Tutorials - Herong's Tutorial Notes - JSTL - Core Library