Link to home
Start Free TrialLog in
Avatar of aturetsky
aturetsky

asked on

using forEach tags with <%=

I have the following code in my jsp:

                  <c:forEach var='doctype' items='${modifyUserFormBean.doctypes}'>
                        <td align="center" valign="middle" class="row_normal">
                        <div><input name="<c:out value='${doctype.doctypeId}' />"
                              type="checkbox" value="checkbox"
                              checked="<%= modifyUserFormBean.getCheckedDoctypes().contains(doctype.getDoctypeId())%>" />
                        <c:out value='${doctype.doctypeName}' /></div>
                        </td>
                  </c:forEach>


In line that says modifyUserFormBean.getCheckedDoctypes().contains(doctype.getDoctypeId())%>"  I get a compilation exception on doctype: doctype cannot be resolved

I've tried different combinations of c: and c_rt: but to no avail.

Please help.
Avatar of bloodredsun
bloodredsun
Flag of Australia image

This is to do with scopes rather than the forEach tag. The scriptlet does not have access to the expression lanaguage variable "doctype"
Does:

               <c:forEach var='doctype' items='${modifyUserFormBean.doctypes}'>
                    <jsp:useBean id="doctype" class="CLASSOFDOCTYPEOBJECT"/>
                    <td align="center" valign="middle" class="row_normal">
                    <div><input name="<c:out value='${doctype.doctypeId}' />"
                         type="checkbox" value="checkbox"
                         checked="<%= modifyUserFormBean.getCheckedDoctypes().contains(doctype.getDoctypeId())%>" />
                    <c:out value='${doctype.doctypeName}' /></div>
                    </td>
               </c:forEach>

help?
(replace CLASSOFDOCTYPEOBJECT with the full classname that the "doctype" obejct represents :-)
Avatar of aturetsky
aturetsky

ASKER

Tim, I am sorry for the delayed response.  I ended up doing it differently before I received your message, so I kept putting off my response until I would get to try out your code.

Here's what i don't understand in your code.  Wouldn't <jsp:useBean id="doctype" class="somepackage.Doctype"/>
result in putting a blank bean of Doctype type into the session.  How, in your code, would it get populated with the contents of ${doctype}?  Would you not need a c:set?
>> How, in your code, would it get populated with the contents of ${doctype}?  Would you not need a c:set?

  <c:forEach var='doctype' items='${modifyUserFormBean.doctypes}'>

defines a doctype object and stores it in the var called "doctype"

  <jsp:useBean id="doctype" class="CLASSOFDOCTYPEOBJECT"/>

gets this object, and defines it so that it can be used in your JSP scriptlet...

As far as I know anyway...  did you try the code?

Tim
Tim,

Well, I tried running it, but it doesn't seem to work for a different reason - the doctype is of class Doctype, which for some reason is not being treated by the jsp compiler as a bean, so I get a "The value for the useBean class attribute com.talisen.workflow.model.Doctype is invalid" error , even though I made sure that the declaration and everything else is correct.  I'll included the code for that class on the very bottom, in case you can tell me offhand why this class is not being treated as a bean.

But in any case here's what I don't understand in your code:

You suggest that the line <jsp:useBean id="doctype" class="CLASSOFDOCTYPEOBJECT"/>  "gets this object."  Well, I didn't think that was true, and that it would instantiate a brand new bean of  that type, but just to be sure I did some research, and I think I am correct here:
According to http://java.sun.com/products/jsp/syntax/1.2/syntaxref1217.html,

"The <jsp:useBean> element locates or instantiates a JavaBeans component. <jsp:useBean> first attempts to locate an instance of the bean. If the bean does not exist, <jsp:useBean> instantiates it from a class or serialized template.

To locate or instantiate the bean, <jsp:useBean> takes the following steps, in this order:

   1. Attempts to locate a bean with the scope and name you specify.
   2. Defines an object reference variable with the name you specify.
   3. If it finds the bean, stores a reference to it in the variable. If you specified type, gives the bean that type.
   4. If it does not find the bean, instantiates it from the class you specify, storing a reference to it in the new variable. If the class name represents a serialized template, the bean is instantiated by java.beans.Beans.instantiate.
   5. If <jsp:useBean> has instantiated (rather than located) the bean, and if it has body tags or elements (between <jsp:useBean> and </jsp:useBean>), executes the body tags"

Now, l'll go through it in order.  Step 1 attempt would result in nothing, because the var doctype in <c:forEach var='doctype' items='${modifyUserFormBean.doctypes}'> is invisible since it only has nested visibility (see bellsouthpwp.net/b/i/billsigg/jstl-quick-reference.pdf).  Therefore, after defining the object reference variable in Step 2, it would not go into Step 3, since such bean does not exist.   Rather, it would go into step 4 and instantiate a new one.  That means the value of the var from the loop will never get into that bean.

Am I wrong?

As promised here' s the code for the Doctype class - and I am increasing the point value.

package com.talisen.workflow.model;

import java.io.Serializable;

public class Doctype implements Serializable, Comparable {

      private Integer doctypeId = null;
      private String doctypeName;
      private String doctypeDesc;
      private String doctypeAbbr;
      private Status status;
    private int hashValue = 0;

    /**
     * @return Returns the doctypeDesc.
     */
    public String getDoctypeDesc()
    {
        return this.doctypeDesc;
    }
    /**
     * @param doctypeDesc The doctypeDesc to set.
     */
    public void setDoctypeDesc(String doctypeDesc)
    {
        this.doctypeDesc = doctypeDesc;
    }
    /**
     * @param doctypeId The doctypeId to set.
     */
    public void setDoctypeId(Integer doctypeId)
    {
        this.doctypeId = doctypeId;
    }
    /**
     * @param doctypeUsers The doctypeUsers to set.
     */

    /**
     * @return Returns the doctypeName.
     */
    public String getDoctypeName()
    {
        return this.doctypeName;
    }

      /**
       * No-arg constructor for JavaBean tools.
       */
      Doctype() {}

      /**
       * Simple constructor.
       */
      public Doctype(String name) {
            this.doctypeName = name;
      }
      public Doctype(Integer doctypeId) {
            this.doctypeId = doctypeId;
      }

      // ********************** Accessor Methods ********************** //

      public Integer getDoctypeId() { return doctypeId; }

      public void setDoctypeName(String name) { this.doctypeName = name; }


      // ********************** Common Methods ********************** //

      public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Doctype)) return false;

            final Doctype doctype = (Doctype) o;

            if (doctypeName != null ? !doctypeName.equals(doctype.doctypeName) : doctype.doctypeName != null) return false;

            return true;
      }

    public int hashCode()
    {
        if (this.hashValue == 0)
        {
            int result = 17;
            int userIdValue = this.getDoctypeId() == null ? 0 : this.getDoctypeId().hashCode();
            result = result * 37 + userIdValue;
            this.hashValue = result;
        }
        return this.hashValue;
    }

      public String toString() {
            return  "Doctype_Id ('" + getDoctypeId() + "'), " +
                        "Doctype_Name: '" + getDoctypeName() + "'";
      }

      public int compareTo(Object o) {
            if (o instanceof Doctype) {
                  return this.getDoctypeName().compareTo( ((Doctype)o).getDoctypeName() );
            }
            return 0;
      }

      // ********************** Business Methods ********************** //

      /**
       * @return Returns the doctypeAbbr.
       */
      public String getDoctypeAbbr() {
            return doctypeAbbr;
      }
      /**
       * @param doctypeAbbr The doctypeAbbr to set.
       */
      public void setDoctypeAbbr(String doctypeAbbr) {
            this.doctypeAbbr = doctypeAbbr;
      }
      /**
       * @return Returns the status.
       */
      public Status getStatus() {
            return status;
      }
      /**
       * @param status The status to set.
       */
      public void setStatus(Status status) {
            this.status = status;
      }
}
Tim, I realize my previous posting might be too long to read, but could you at least please respond to this part of it, so I can go ahead and give you points.
-------------------
But in any case here's what I don't understand in your code:

You suggest that the line <jsp:useBean id="doctype" class="CLASSOFDOCTYPEOBJECT"/>  "gets this object."  Well, I didn't think that was true, and that it would instantiate a brand new bean of  that type, but just to be sure I did some research, and I think I am correct here:
According to http://java.sun.com/products/jsp/syntax/1.2/syntaxref1217.html,

"The <jsp:useBean> element locates or instantiates a JavaBeans component. <jsp:useBean> first attempts to locate an instance of the bean. If the bean does not exist, <jsp:useBean> instantiates it from a class or serialized template.

To locate or instantiate the bean, <jsp:useBean> takes the following steps, in this order:

   1. Attempts to locate a bean with the scope and name you specify.
   2. Defines an object reference variable with the name you specify.
   3. If it finds the bean, stores a reference to it in the variable. If you specified type, gives the bean that type.
   4. If it does not find the bean, instantiates it from the class you specify, storing a reference to it in the new variable. If the class name represents a serialized template, the bean is instantiated by java.beans.Beans.instantiate.
   5. If <jsp:useBean> has instantiated (rather than located) the bean, and if it has body tags or elements (between <jsp:useBean> and </jsp:useBean>), executes the body tags"

Now, l'll go through it in order.  Step 1 attempt would result in nothing, because the var doctype in <c:forEach var='doctype' items='${modifyUserFormBean.doctypes}'> is invisible since it only has nested visibility (see bellsouthpwp.net/b/i/billsigg/jstl-quick-reference.pdf).  Therefore, after defining the object reference variable in Step 2, it would not go into Step 3, since such bean does not exist.   Rather, it would go into step 4 and instantiate a new one.  That means the value of the var from the loop will never get into that bean.

Am I wrong?
>${modifyUserFormBean.doctypes}    
What type of collection is returned ?          rrz
ASKER CERTIFIED SOLUTION
Avatar of rrz
rrz
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
thanks, rrz - well, I mean I ended up doing earlier in a similar way, except I had to put the attribute "doctype" into the request context.

How would your way work, however - that is, how can you, in the following line, expect the doctype to be an attribute in pageContext if you never put it there?

com.talisen.workflow.model.Doctype  currentType  =  
                 (com.talisen.workflow.model.Doctype)pageContext.getAttribute("doctype");
>how can you, in the following line, expect the doctype to be an attribute in pageContext if you never put it there?            
you put it there with  
><c:forEach var='doctype'        
Please try the following page.     rrz  

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
<c:forEach items="1,2,3,4,5,6" var="current">
<%
  String current = (String)pageContext.getAttribute("current");
%>
<%=current%>
</c:forEach>
I guess when it comes down to it having a scriptlet in a JSTL tag is an ugly solution.
Are you using JSP 2.0 ? If so then we can clean it up some.      rrz
My solution is a variation of Tim's solution.
Right  ?  
Cool.  Thanks.  You the man.
Before I reward points, I want to make sure that my problem with Tim's answer was justified.  That is, that using  <jsp:useBean id="doctype" class="CLASSOFDOCTYPEOBJECT"/> would not help since doctype was never instantiated as a bean, only as an attribute of the page context.  Is that accurate?
Also, I just saw your response above.  Yes.  I am using 2.0.   I'd love to know how can we clean it up and not use scriplets.
> I'd love to know how can we clean it up and not use scriplets.  
No, I didn't say that. I meant to say that we could get rid of  the display tags.
><c:out value='${doctype.doctypeName}' /></  
could be just  EL  
${doctype.doctypeName}  

>Is that accurate?  
I don't think so. But let's get Tim's response.    
I would try Tim's idea like below.      rrz    

<jsp:useBean id="doctype" class="com.talisen.workflow.model.Doctype"/>
<c:forEach var='doctype' items='${modifyUserFormBean.doctypes}'>
   <td align="center" valign="middle" class="row_normal">
   type="checkbox" value="checkbox"
   checked="<%= modifyUserFormBean.getCheckedDoctypes().contains(doctype.getDoctypeId())%>" />
   ${doctype.doctypeName}</div>
   </td>
</c:forEach>
No, that won't work ( Tim please help ).
Thanks for all this.  If I don't get the response from Tim today, I'll go ahead and reward the points, since I posted my question to him a while ago.  Speaking of EL ... I am posting a following question, that I am sure you can answer.  The link is below.

1) my development server supports 2.0, so to use EL syntax such as ${doctype.doctypeName} without the c:out, what should the taglib declaration look like, or do I not need a declaration
2) my production server (Sun Web Server 6.1) only supports 1.2, so I am just curious if I can EL-enable it by dropping in a jar or what not, or is that impossible?

The link for the question is https://www.experts-exchange.com/questions/21353601/EL-enablement.html.
1) El is part of JSP 2.0   nothing special is needed.  
2)No  
Wait for Tim's response before taking action here.           rrz    
will do
Hiya!  Sorry, I was at home, asleep ;-)

Whats the problem?  Didn't rrz's solution fix it?
>Whats the problem?  
Just wondering if your use of useBean tag should work.         rrz
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
but even with logic:iterate it would only work for an iteration over a collection of bean objects, correct?  So if my doctype object is, for whatever reason, not classified as a bean (not sure why not in my case, but that's beside the point) it wouldn't work, right?
does it have an empty constructor?

if so, it should work as a bean...  (as long as it has getXXX methods for the parameters you want to read...
Thanks.  Could be my problem is the fact that my empty constructor is not declared as public (as you can see in the code above).  I can't get to changing that code right just now to try it out, but what do you think?
Sounds like it...  Beans need a public constructor with no args...

good luck with it!!

Tim
Thanks, Tim.  I awarded most of the points to rrz since he gave a complete working solution.  However, I do appreciate the time you put in to answer my questions and for sharing your very helpful expertise.
I spent some time trying Tim's idea.  This works  
-------------------------------------------------------------------
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
  ArrayList list = new ArrayList();
  list.add("joe");
  list.add("sue");
%>
<c:set var="list" value="<%=list%>"/>
<c:forEach items="${list}" var="person">
     <jsp:useBean id="person" class="java.lang.String"/>
     <%=person%>
</c:forEach>
-------------------------------------------------------------------
but you never answered my question  
>>${modifyUserFormBean.doctypes}    What type of collection is returned ?
If, you are returning a Map, then the current element is exposed as a java.util.Map.Entry  .  In that case we are "out of luck" because Entry is just an inerface.      
What do you think Tim ?
<%@ page import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
  ArrayList list = new ArrayList();
  list.add("joe");
  list.add("sue");
%>
<c:set var="list" value="<%=list%>"/>
<c:forEach items="${list}" var="person">
     <jsp:useBean id="person" class="java.lang.String"/>
     <%=person%>
</c:forEach>
I have modifyUserFormBean.doctypes as a Set<Doctype>  - I am using Java 1.5 in my development env, so it does typed collections.
So each element should be exposed as a Doctype, which I guess would be a bean once I append "public" modifier to the default constructor - (I didn't get to try that out yet.)

Thanks for all your time, rrz
So let me ask you, then.  If this (your code below) works and bean is anything with a public default constructor, then why would you need <c:set var="list" value="<%=list%>"/>.   If you can access it as an attribute of the pageContext, then why can you not do the same with useBean which would check all contexts for anything that has a public no-arg constructor.  (This is the opposite of what I was asking Tim before - I mean now I would almost think Tim's way should work)

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
<c:forEach items="1,2,3,4,5,6" var="current">
<%
  String current = (String)pageContext.getAttribute("current");
%>
<%=current%>
</c:forEach>
>Tim's way should work)
I think so.    

>why would you need <c:set var="list" value="<%=list%>"/>.      
Please try the following page and ask question aferwards.  
As Tim has pointed out
the useBean tag is the bridge between the two. It creates both.         rrz        


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
  String scriptVar = "scripting variable";
%>
<c:set var="tag" value="set by tag"/>
Scoped variable can be ${tag}.<br/>
Unscoped variable is <%=scriptVar%>.<br/>
?${scriptVar} No, I can't see that.<br/>
<c:set var="scoped" value="<%=scriptVar%>"/>
Now, I can see the scoped ${scoped}.<br/>