Search code examples
jsfjsf-2lazy-initialization

How to find JSF component when there is an exception during rendering?


Environment: JSF 2.0, Seam 2.3, RF 4.3 and PF 5 on JBoss AS 7.2

I have a strange error on two JSF pages. I get a LIE (Lazy Initialization Exception) during the render phase.

Error Rendering View[/secure/MyPage.xhtml]: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185) [hibernate-core-4.2.0.Final-redhat-1.jar:4.2.0.Final-redhat-1]
    at com.mycompany.entity.Currency_$$_javassist_17.equals(Currency_$$_javassist_17.java) [:]
    at com.sun.faces.renderkit.html_basic.MenuRenderer.isSelected(MenuRenderer.java:724) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.renderkit.html_basic.MenuRenderer.renderOption(MenuRenderer.java:550) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.renderkit.html_basic.MenuRenderer.renderOptions(MenuRenderer.java:791) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.renderkit.html_basic.MenuRenderer.renderSelect(MenuRenderer.java:843) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.renderkit.html_basic.MenuRenderer.encodeEnd(MenuRenderer.java:297) [jsf-impl-2.1.29.jar:2.1.29]
    at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:877) [jsf-api-2.1.29.jar:2.1]
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:312) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:309) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.renderkit.html_basic.GridRenderer.renderRow(GridRenderer.java:185) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.renderkit.html_basic.GridRenderer.encodeChildren(GridRenderer.java:129) [jsf-impl-2.1.29.jar:2.1.29]
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:847) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1819) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.render.Renderer.encodeChildren(Renderer.java:168) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:847) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1819) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1822) [jsf-api-2.1.29.jar:2.1]
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:447) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:125) [jsf-impl-2.1.29.jar:2.1.29]
    at org.jboss.seam.jsf.SeamViewHandler.renderView(SeamViewHandler.java:188) [jboss-seam.jar:2.3.1.Final]
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:286) [jsf-api-2.1.29.jar:2.1]
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120) [jsf-impl-2.1.29.jar:2.1.29]
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.29.jar:2.1.29]

The pages in question start a new conversation and there shouldn't be anything stale on it. Most of the times these pages work fine but occasionally they start throwing this exception and they continue to throw that exception until you log out and in again.

So I can only assume something is referencing an entity in a Session scoped bean.

But the question is where are they referenced and what is referenced?

Is there a way to find out which component (either the ID or which line/file) caused the exception? Otherwise it is the search for the needle in a rather big haystack. Is there maybe a certain logger category that I need to enable (set to DEBUG or TRACE)?

I've tried excluding larger parts of the page to narrow down the problem but then the page suddenly works again even if I add the previously removed part back in again. So a proper Heisenbug ;-(


Solution

  • A lot can already be interpreted based on the stack trace alone (and if necessary reading the associated source code, if you couldn't make sense of class and method names).

    As per the stack trace, it occurred while MenuRenderer was busy rendering a <option> element and determining via equals() method of the item value whether it should set the selected attribtue for preselection. This renderer is only used by a <h:select(One|Many)(Menu|Listbox)> component. It's exactly that component wherein a com.mycompany.entity.Currency instance represents the individual item value of <f:selectItems> or perhaps <h:selectMany(Menu|Listbox)> like so value="#{someBean.someEntity.currencies}".

    Apparently, that Collection<Currency> was being fetched with FetchType.LAZY instead of FetchType.EAGER. Hence, Hibernate needs to load it, but couldn't do it because the DB session is nowhere available during JSF render response phase. It's only available inside a transaction aware service method, such as an EJB method. In other words, your data preloading logic is wrong and should be altered to use FetchType.EAGER instead to obtain the Collection<Currency> before JSF can render the menu with that data.

    See also: