渲染异常时如何查找JSF组件?

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

环境:JBoss AS 7.2

上的 JSF 2.0、Seam 2.3、RF 4.3 和 PF 5

我在两个 JSF 页面上有一个奇怪的错误。我在渲染阶段遇到 LIE(延迟初始化异常)。

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]

有问题的页面开始了新的对话,上面应该没有任何陈旧的内容。大多数情况下,这些页面工作正常,但偶尔它们会开始抛出此异常,并且会继续抛出该异常,直到您注销并再次登录。

所以我只能假设某些东西正在引用会话范围 bean 中的实体。

但问题是它们在哪里引用,引用了什么?

有没有办法找出哪个组件(ID 或哪个 line/file)导致了异常?否则就是大海捞针。是否可能需要启用某个记录器类别(设置为 DEBUG 或 TRACE)?

我尝试排除页面的较大部分以缩小问题范围,但即使我再次将之前删除的部分重新添加回来,页面也会突然恢复正常。所以一个合适的 Heisenbug ;-(

该错误明确指出在您的 jsf 页面(即 xhtml)中呈现菜单组件期间发生异常。

 at com.sun.faces.renderkit.html_basic.MenuRenderer.isSelected(MenuRenderer.java:724)

已经可以仅基于堆栈跟踪来解释很多内容(如果您无法理解 class 和方法名称,请阅读相关的源代码,如有必要)。

根据堆栈跟踪,它发生在 MenuRenderer 忙于呈现 <option> 元素并通过项目值的 equals() 方法确定是否应设置 selected 预选属性。此渲染器仅由 <h:select(One|Many)(Menu|Listbox)> 组件使用。正是 com.mycompany.entity.Currency 实例代表 <f:selectItems><h:selectMany(Menu|Listbox)> 的单个项目值的组件,例如 value="#{someBean.someEntity.currencies}".

显然,Collection<Currency> 是使用 FetchType.LAZY 而不是 FetchType.EAGER 获取的。因此,Hibernate 需要加载它,但无法加载它,因为在 JSF 渲染响应阶段数据库会话无处可用。它仅在事务感知服务方法(例如 EJB 方法)中可用。换句话说,您的数据预加载逻辑是错误的,应该更改为使用 FetchType.EAGER 而不是在 JSF 可以使用该数据呈现菜单之前获取 Collection<Currency>

另请参阅: