ForEachHandler OutOfMemoryError

From Foochal

Jump to: navigation, search


Stacktrace

I was trying to use a <c:forEach> loop in a facelet .xhtml file. I got this stacktrace.

Caused by: java.lang.OutOfMemoryError: Java heap space
	at com.sun.facelets.tag.jstl.core.ForEachHandler.apply(ForEachHandler.java:123)
	at com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:47)
	at com.sun.facelets.tag.jstl.core.ChooseWhenHandler.apply(ChooseWhenHandler.java:45)
	at com.sun.facelets.tag.jstl.core.ChooseHandler.apply(ChooseHandler.java:68)
	at com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:47)
	at com.sun.facelets.tag.ui.DefineHandler.applyDefinition(DefineHandler.java:64)
	at com.sun.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:131)
	at com.sun.facelets.impl.DefaultFaceletContext$TemplateManager.apply(DefaultFaceletContext.java:310)
	at com.sun.facelets.impl.DefaultFaceletContext.includeDefinition(DefaultFaceletContext.java:280)
	at com.sun.facelets.tag.ui.InsertHandler.apply(InsertHandler.java:68)
	at com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:47)
	at com.sun.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:49)
	at com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:47)
	at com.sun.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:25)
	at com.sun.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:248)
	at com.sun.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:294)
	at com.sun.facelets.impl.DefaultFacelet.include(DefaultFacelet.java:273)
	at com.sun.facelets.impl.DefaultFaceletContext.includeFacelet(DefaultFaceletContext.java:144)
	at com.sun.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:113)
	at com.sun.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:49)
	at com.sun.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:25)
	at com.sun.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:95)
	at com.sun.facelets.FaceletViewHandler.buildView(FaceletViewHandler.java:524)
	at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:567)
	at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
	at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:189)
	at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:106)
	at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
	at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:245)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

Solution

This error occurs when there is no "items" specified in the <c:forEach> tag

Analysis

I set a breakpoint on the in ForEachHandler.java file, where the error occurred and found that the code was trying to instantiate a very large array.

int s = this.getBegin(ctx); 
int e = this.getEnd(ctx);
int m = this.getStep(ctx);
byte[] b = new byte[e + 1];

Here s=0, e=2147483646 and m=1. This explains the OutOfMemoryError. The question now arises: why is e such a large number.

I stepped into the getEnd() code:

   private final int getEnd(FaceletContext ctx) {
       if (this.end != null) {
           return this.end.getInt(ctx);
       }
       return Integer.MAX_VALUE - 1; //hotspot bug in the JVM
   }

It turns out that: this.end = null, this.begin = null, this.items = null. So basically, the forEach loop handler is unable to read the list and sets a default very high loop count. The next question is why is 'items' null?

I looked at my xhtml and discovered that accidentally when I changed the code from <ui:repeat> to <c:forEach> I forgot to change the loop contruct from "value" to "items"

<c:forEach value="#{myBean.books}">

It should be:

<c:forEach items="#{myBean.books}">

Personal tools