javax.servlet.ServletException: javax.servlet.jsp.JspTagException: Don't know how to iterate over supplied "items" in <forEach>

57,045

Solution 1

Caused by: javax.servlet.ServletException: javax.servlet.jsp.JspTagException: Don't know how to iterate over supplied "items" in <forEach>

That will happen when the <c:forEach items> does not refer a valid object over which it can iterate. The object should be an Object[] (a plain array), a Collection, Map, Iterator, Enumeration or String (see also source code). Anything else can't be iterated by <c:forEach>. Your DetResults class is not an instance of either of the aforementioned types, so it will fail.

Your DetResults class doesn't look right. It look basically like one God bean with a collection of all properties of multiple individual entities. This is not right. A bean class should represent at most one entity. Rewrite your DetResults class so that you basically end up with with a fullworthy collection of javabeans:

List<DetResult> results = detDAO.fetchDetResults(paramBean);

so that you can access it as follows:

<c:forEach items="${results}" var="result">
    ${result.heading}
    <c:forEach items="${result.data}" var="dataItem">
        ${dataItem}
    </c:forEach>
</c:forEach>

If you really insist to keep your DetResults bean as it is, you could access it as follows:

<c:forEach begin="0" end="${results.columnCount}" varStatus="loop">
    ${results.headings[loop.index]}
    <c:forEach items="${results.data[loop.index]}" var="dataItem">
        ${dataItem}
    </c:forEach>
 </c:forEach>

See also:


Unrelated to the concrete problem, the <c:forEach var> attribute is not right. You should not give it the same name as an existing object in the scope. It would only clash. But that's subject for a new question if you can't interpret the error message.

Solution 2

You should be able to iterate over the headings

<tr>
<c:foreach var="heading" items="${results.headings}">
  <th>${heading}</th>
</c:foreach>
</tr>

And then over the data...

<c:foreach var="row" items="${results.data}">
  <tr>
  <c:foreach var="i" items="${row}">
    <td>${i}</td>
  </c:foreach>
  </tr>
</c:foreach>

Or something along those lines?

Share:
57,045
Doc Holiday
Author by

Doc Holiday

I work as a Java Developer who often has to do SQL development, HQL development, and front-end styling using various JS frameworks.

Updated on December 28, 2020

Comments

  • Doc Holiday
    Doc Holiday over 3 years

    I have a Bean that holds the results. I need to use JSTL to iterate over it and present the results. Here is the bean:

    public class DetResults
    {
        private List<String> headings;
        private List<Class<?>> types;
        private List<Object[]> data;
    
        public DetResults() {}
    
        public List<String> getHeadings() { return this.headings; }
        public String getHeading(int which) { return this.headings.get(which); }
    
        public List<Class<?>> getTypes() { return this.types; }
        public Class<?> getType(int which) { return this.types.get(which); }
    
        public List<Object[]> getData( ) { return this.data; }
        public Object[] getDataAtRow( int row ) { return this.data.get(row); }
    
    
        public void setHeadings( List<String> val ) { this.headings = val; }
        public void setHeadings( String[] val ) { this.headings = Arrays.asList(val); }
        public void addHeading( String val ) 
        { 
            if( this.headings == null ) this.headings = new ArrayList<String>();
            this.headings.add(val); 
        }
    
        public void setTypes( List<Class<?>> val ) { this.types = val; }
        public void setTypes( Class<?> val[] ) { this.types = Arrays.asList(val); }
        public void addType( Class<?> val ) 
        {
            if( this.types == null ) this.types = new ArrayList<Class<?>>();
            this.types.add(val); 
        }
    
    
        public void setData( List<Object[]> val ) { this.data = val; }
    
        // allow NPE to get thrown
        public void setDataAtRow( Object[] val, int row ) { this.data.set(row, val); }
    
        public void appendDataRow( Object[] val ) 
        {
            if( data == null ) data = new ArrayList<Object[]>(); 
            this.data.add(val); 
        }
    
        public int getColumnCount() { return this.headings!=null?this.headings.size():0; }
    
    }
    

    Here is the handler that will set the bean to the JSP:

    DetResults results = detDAO.fetchDetResults(paramBean);
    request.setAttribute("results", results);
    action.setJspURI(".../.jsp");
    

    I tried to display it as follows:

    <c:forEach var="results" items="${results}">
        ${results.heading}
    </c:forEach>
    

    But it threw the following exception:

    Caused by: javax.servlet.ServletException: javax.servlet.jsp.JspTagException: Don't know how to iterate over supplied "items" in <forEach>

    If I log the results on my handler page like this:

    System.out.println( "\n\nthere are " + results.getColumnCount() + " columns in the result set" );
    for( int i=0; i<results.getColumnCount(); i++ )
    {
        System.out.println( results.getHeading(i) + " --> " + results.getType(i) );
    }
    

    The logging seems to show fine on the server.

    • Kevin Bowersox
      Kevin Bowersox about 12 years
      can you post the stack trace?
    • Doc Holiday
      Doc Holiday about 12 years
      yeah give me a minute to run it again
    • BalusC
      BalusC about 12 years
      The problem descriptions "it's blowing up everytime I render the jsp" and "and the page broke :(" are far from helpful in understanding the concrete problem. Do not describe the problem from enduser's perspective, but from developer's perspective.
    • Doc Holiday
      Doc Holiday about 12 years
      Just added error instack trace
    • Dave Newton
      Dave Newton about 12 years
      Bad idea to name the variable the same thing you're iterating over--very confusing. In any case, if it's an instance of DetResults that's in results, of course you can't iterate over it--you'd need to iterate over one of its collections. And if it's using three parallel lists, it's doing it wrong.
  • Doc Holiday
    Doc Holiday about 12 years
    What If I cant rewrite so it's a list?...but use the lists within the bean?
  • BalusC
    BalusC about 12 years
    Then just do so. Your DetResults class is however fishy. I think you should rather rewrite it to a DetResult class which has the properties heading, type, data, etc and then have a List<DetResult>`.
  • Doc Holiday
    Doc Holiday about 12 years
    Nad ...it didnt like that either : javax.servlet.jsp.JspTagException: Don&#039;t know how to iterate over supplied &quot;items&quot; in &lt;forEach&gt; at org.apache.taglibs.standard.tag.common.core.ForEachSupport.t‌​oForEachIterator(For‌​EachSupport.java:255‌​) at org.apache.taglibs.standard.tag.common.core.ForEachSupport.s‌​upportedTypeForEachI‌​terator(ForEachSuppo‌​rt.java:219)
  • BalusC
    BalusC about 12 years
    I updated the answer with some basic examples and useful "See also" links.
  • Doc Holiday
    Doc Holiday about 12 years
    thanx alot...I really would have rather it been in a list but the guy that is building th back end says it has to be this way for now....thanx brother!
  • BalusC
    BalusC about 12 years
    You're welcome. Much luck with this project and team. Sounds like painful.
  • Doc Holiday
    Doc Holiday about 12 years
    Yeah it is painful...they have me doing so many different things...but it's cool...I gues when I become a "Principal" programmer" one day..I will look back on these days and laugh
  • EMS
    EMS about 12 years
    Ah, sorry. I think there probably is a way to get it working with the bean you have, but others are right when they say that redesigning the bean would be better.
  • Pedro Gaspar
    Pedro Gaspar over 5 years
    This doesn't seem to answer the question... There is no such productList in there.