Struts 1
  1. Struts 1
  2. STR-1249

[taglib] Problem to include a jsp into an iterate tag

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: Future
    • Fix Version/s: Future
    • Component/s: Tag Libraries
    • Labels:
      None
    • Environment:
      Operating System: All
      Platform: All

      Description

      2 problems have been identified for this type of inclusion :

      Let's start with a sample code :

      Here is a sample main jsp (main.jsp) :
      <%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
      <%@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
      <html:form method="post" action="/submit">
      <html:iterate name="myForm" property="tab" id="tab" indexId ="index"
      scope="request">
      <jsp:include page="/included.jsp" flush="true" />
      </html:iterate>
      </html:form>

      Here is a sample included jsp (included.jsp) :
      <%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
      <%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
      Personne <bean:write name="index"><br>
      Nom <html:text name="tab" property="firstName" indexed="true" /><br>
      Prenom <html:text name="tab" property="lastName" indexed="true" /><br>

      The first problem is that in the included jsp, it is impossible to access to
      the differents properties given by each iteration : The error message
      is "cannot find bean index in any scope"

      One proposed solution is to use <bean:define> into the <logic:iterate> tag and
      to add the index bean and the tab bean in scope session instead of scope page.
      This solution doesn't seams to work : the error message is the same.

      Another solution could be to modify the doStartTag() and doAfterBody() method
      of the o.a.s.taglib.logic.IterateTag class to store the two bean in request
      instead of page context.

      My tested solution is to redefine the <logic:iterate> tag. I have created a
      <perso:iterate> tag with the class PersoIterateTag wich extends IterateTag,
      redefining his doStartTag() and doAfterBody() method :

      public doStartTag() throws JspException {
      int result = super.doStartTag();

      if (result == EVAL_BODY_TAG) {
      Object o = pageContext.getAttribute(id);
      if (o == null)

      { pageContext.getRequest().removeAttribute(id); }

      else

      { pageContext.getRequest().setAttribute(id,o); }
      o = pageContext.getAttribute(indexId);
      if (o != null) { pageContext.getRequest().setAttribute(indexId,o); }
      }

      return result;
      }

      public doAfterBody() throws JspException {
      int result = super.doAfterBody();

      if (result == EVAL_BODY_TAG) {
      Object o = pageContext.getAttribute(id);
      if (o == null) { pageContext.getRequest().removeAttribute(id); } else { pageContext.getRequest().setAttribute(id,o); }

      o = pageContext.getAttribute(indexId);
      if (o != null)

      { pageContext.getRequest().setAttribute(indexId,o); }

      }

      return result;
      }

      Modifying the first jsp (main.jsp) to use this tag, there is no problem for
      finding the bean anymore.

      But, here comes the second problem : the indexed property of tag <html:text>
      provides a way to generate a <html input="text"> type tag with a name property
      like "tab[0].firstName".
      To do this, when the indexed property is true into the <html:text> tag, the
      method prepareIndex() from o.a.s.taglib.html.BaseHanderTag class is called.
      But into this method the first operation consists in calling the
      findAncestorWithClass() method to get the instance of the IterateTag wich
      correspond to the <logic:iterate>.
      In this case the <logic:iterate> tag isn't in the same page than the
      <html:text> tag, and so an error message comes: "indexed="true" is only valid
      within an enclosing iterate tag"
      This problem seems to be a scope problem : the corresponding instance for
      <logic:iterate> is into the page scope, that's why the included jsp cannot
      recover his instance.

      One solution to fixe this problem can be to add two property to the <html:text>
      (and to similar tag) :

      • indexName : The name of the bean containing the current value of the index
        (in this exemple "index")
      • indexScope : The scope where this bean can be found.

      This properties could be added to the o.a.s.taglib.html.BaseHandlerTag class
      with the corresponding getter and setter method.
      On begining of the prepareIndex() method of this class, the following code
      could be added :
      protected void prepareIndex(StringBuffer handlers, String name) throws
      JspException {
      if (indexName != null) {
      Integer index = (Integer)RequestUtils.lookup
      (pageContext,indexName,indexScope);
      if (index == null)

      { JspException e = new JspException(messages.getMessage ("lookup.bean", indexName, indexScope)); RequestUtils.saveException(pageContext, e); throw e; }

      if (name != null)
      handlers.append(name);
      handlers.append("[");
      handlers.append(index);
      handlers.append("]");
      if (name != null)
      handlers.append(".");
      return;
      }
      ...
      }

      On the end of the release() method of this class, the following code could be
      added :
      indexName = null;
      indexScope = null;

      Finally, the struts-html.tld file has to be modified, addding the following
      line to each tag wich can use it :
      <attribute>
      <name>indexName</name>
      <required>false</required>
      <rtexprvalue>true</rtexprvalue>
      </attribute>
      <attribute>
      <name>indexScope</name>
      <required>false</required>
      <rtexprvalue>true</rtexprvalue>
      </attribute>

      With this modification the folowing jsp code will now work :

      Here is the new main jsp (main.jsp) :
      <%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
      <%@taglib uri="/WEB-INF/struts-perso.tld" prefix="logic" %>
      <html:form method="post" action="/submit">
      <logic:iterate name="myForm" property="tab" id="tab" indexId ="index"
      scope="request">
      <jsp:include page="/included.jsp" flush="true" />
      </logic:iterate>
      </html:form>

      Here is the new included jsp (included.jsp) :
      <%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
      <%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
      Personne <bean:write name="index"><br>
      Nom <html:text name="tab" property="firstName" indexName="index"
      indexScope="request" indexed="true" /><br>
      Prenom <html:text name="tab" property="lastName" indexName="index"
      indexScope="request" indexed="true" /><br>

        Activity

        Freddy Lecerf created issue -
        Hide
        David Graham added a comment -

        Current functionality is not broken so this is an enhancement request.

        Show
        David Graham added a comment - Current functionality is not broken so this is an enhancement request.
        Hide
        Ted Husted added a comment -

        Tagging for 1.2 family.

        Show
        Ted Husted added a comment - Tagging for 1.2 family.
        Hide
        Shea Wang Hei added a comment -

        I would like to show a list of jobs and showing who should response to the job.

        So I will create a table like :
        Job Name Respondent
        <The Job Name> <A html <select> </select>

        The Code is like:
        <tr><td> </td><td>name</td><td>description</td><td>required doc</td></tr>

        <nested:iterate id="prdArray" name="prdArray">
        <tr>
        <td></td>
        <td><bean:write name="prdArray" property="name"/></td>
        <td><bean:write name="prdArray" property="desc"/></td>
        <td><bean:write name="prdArray" property="req_doc"/> </td>
        <td>
        <select>
        <nested:iterate id="empArray" name="empArray">
        <option> <bean:write name="empArray" property="staff_name"/>
        <option>
        </nested:iterate>
        </select>
        </td>
        <td>
        </td>
        </tr>
        </nested:iterate>
        </table>

        Error output is:

        type Exception report
        message Internal Server Error
        description The server encountered an internal error (Internal Server Error)
        that prevented it from fulfilling this request.

        exception

        javax.servlet.ServletException: Cannot create iterator for this collection
        at org.apache.jasper.runtime.PageContextImpl.handlePageException
        (PageContextImpl.java:471)
        at org.apache.jsp.NewProd$jsp._jspService(NewProd$jsp.java:275)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:107)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        ..... and so on...

        Show
        Shea Wang Hei added a comment - I would like to show a list of jobs and showing who should response to the job. So I will create a table like : Job Name Respondent <The Job Name> <A html <select> </select> The Code is like: <tr><td> </td><td>name</td><td>description</td><td>required doc</td></tr> <nested:iterate id="prdArray" name="prdArray"> <tr> <td></td> <td><bean:write name="prdArray" property="name"/></td> <td><bean:write name="prdArray" property="desc"/></td> <td><bean:write name="prdArray" property="req_doc"/> </td> <td> <select> <nested:iterate id="empArray" name="empArray"> <option> <bean:write name="empArray" property="staff_name"/> <option> </nested:iterate> </select> </td> <td> </td> </tr> </nested:iterate> </table> Error output is: type Exception report message Internal Server Error description The server encountered an internal error (Internal Server Error) that prevented it from fulfilling this request. exception javax.servlet.ServletException: Cannot create iterator for this collection at org.apache.jasper.runtime.PageContextImpl.handlePageException (PageContextImpl.java:471) at org.apache.jsp.NewProd$jsp._jspService(NewProd$jsp.java:275) at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:107) at javax.servlet.http.HttpServlet.service(HttpServlet.java:853) ..... and so on...
        Don Brown made changes -
        Field Original Value New Value
        issue.field.bugzillaimportkey 17473 26540
        Hide
        Stephan Koops added a comment -

        I've had the problem, that with <jsp:include page="/included.jsp" flush="true" /> nohing of the included jsp was validated (no <bean:write ... />, no <html:text /> and like this).
        I used <%@ include file="/included.jsp" %> and it worked fine

        Show
        Stephan Koops added a comment - I've had the problem, that with <jsp:include page="/included.jsp" flush="true" /> nohing of the included jsp was validated (no <bean:write ... />, no <html:text /> and like this). I used <%@ include file="/included.jsp" %> and it worked fine
        Paul Benedict made changes -
        Assignee Struts Developers [ dev@struts.apache.org ]
        Jeff Turner made changes -
        Project Import Mon Feb 01 01:03:21 UTC 2010 [ 1264986201992 ]
        Mark Thomas made changes -
        Workflow jira [ 12490470 ] Default workflow, editable Closed status [ 12545701 ]
        Mark Thomas made changes -
        Workflow Default workflow, editable Closed status [ 12545701 ] jira [ 12549010 ]
        Mark Thomas made changes -
        Workflow jira [ 12549010 ] Default workflow, editable Closed status [ 12559113 ]
        Mark Thomas made changes -
        Workflow Default workflow, editable Closed status [ 12559113 ] jira [ 12587537 ]

          People

          • Assignee:
            Unassigned
            Reporter:
            Freddy Lecerf
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:

              Development