JSF + Hyperjaxb3 + Hibernate LazyInitializationException 跨请求

发布于 2024-09-24 15:35:14 字数 3587 浏览 1 评论 0原文

我有带有 trinidad 组件的 JSF 应用程序和由 Hyperjaxb3 生成的 JAXB/JPA 实体 bean。在 UI 中,我使用 Trinidad 组合框组件,该组件将 JPA 对象作为值。

该场景是:

  1. 用户在组合框中进行选择
  2. 用户单击向服务器发送请求的控件并返回到同一表单
  3. 表单中的数据已提交,并且组合框中的选择应与用户在步骤 1 中所做的相同。 equals () 方法在组合框项(JPA 对象)上调用,并引发此异常:

org.hibernate.LazyInitializationException:无法延迟初始化角色集合:package.AnObject.items,没有会话或会话已关闭 在 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358) 在 org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)

 at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)

 at org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)

 at org.jvnet.hyperjaxb3.item.AbstractItemList.size(AbstractItemList.java:51)

 at java.util.AbstractList$Itr.hasNext(Unknown Source)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:57)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:29)

 at package.AnObject.equals(AnObject.java:177)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:34)

 at package.ParentObject.equals(ParentObject.java:532)

 at package.ParentObject.equals(ParentObject.java:551)

 at java.util.ArrayList.indexOf(Unknown Source)

 at org.apache.myfaces.trinidad.component.UIXSelectMany._destructiveCompareOutOfOrderLists(UIXSelectMany.java:179)

 at org.apache.myfaces.trinidad.component.UIXSelectMany.compareValues(UIXSelectMany.java:139)

 at org.apache.myfaces.trinidad.component.UIXEditableValue.validate(UIXEditableValue.java:180)

 at org.apache.myfaces.trinidad.component.UIXEditableValue._executeValidate(UIXEditableValue.java:503)

 at org.apache.myfaces.trinidad.component.UIXEditableValue.processValidators(UIXEditableValue.java:270)

 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1058)

 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1058)

我使用 Spring 中的 OpenEntityManagerInViewFilter 来获取延迟加载的对象 - 在一个请求中工作。

在 HyperJAXB 生成的对象级别上,equals() 方法调用 equals(Object object, EqualsBuilder equalsBuilder) 方法,其中 equalsBuilder.append(...) 在该对象的每个属性上调用。当该属性是一个列表时,它由 PersistenBag 代理,这就是我得到 LazyInitializationException 的地方。

equals() 方法 - 由 HyperJaxb 生成:

public boolean equals(Object object) {
    if (!(object instanceof ParentObject)) {
        return false;
    }
    if (this == object) {
        return true;
    }
    final EqualsBuilder equalsBuilder = new JAXBEqualsBuilder();
    equals(object, equalsBuilder);
    return equalsBuilder.isEquals();
}

equals(Object object, EqualsBuilder equalsBuilder) 由 HyperJaxb 生成:

public void equals(Object object, EqualsBuilder equalsBuilder) {
    if (!(object instanceof ParentObject)) {
        equalsBuilder.appendSuper(false);
        return ;
    }
    if (this == object) {
        return ;
    }
    final ParentObjectthat = ((ParentObject) object);
    // PersitentBag, LazyInitializationException is thrown here
    equalsBuilder.append(this.getAnObject(), that.getAnObject());
    equalsBuilder.append(this.get..., that.get...);
    ...
}

你们有什么想法如何解决这个问题吗?

我尝试使用 JSF 转换器并让 SelectItem 具有 String 值(不是对象),但如果我记得正确的 equals() 在 String 转换为我的对象之后被调用。

I have JSF application with trinidad components and JAXB/JPA entity beans generated by Hyperjaxb3. In the UI I use Trinidad combo box component that has JPA object as values.

The scenario is:

  1. User make selection in combo box
  2. User clicks on a control that sends request to the server and is returned to the same form
  3. Data from the form was submitted and selection in combo box should be as user did in the step 1. equals() method is called on combo box items (JPA objects) and this exception is thrown:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: package.AnObject.items, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)

 at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)

 at org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)

 at org.jvnet.hyperjaxb3.item.AbstractItemList.size(AbstractItemList.java:51)

 at java.util.AbstractList$Itr.hasNext(Unknown Source)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:57)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:29)

 at package.AnObject.equals(AnObject.java:177)

 at org.jvnet.jaxb2_commons.lang.builder.JAXBEqualsBuilder.append(JAXBEqualsBuilder.java:34)

 at package.ParentObject.equals(ParentObject.java:532)

 at package.ParentObject.equals(ParentObject.java:551)

 at java.util.ArrayList.indexOf(Unknown Source)

 at org.apache.myfaces.trinidad.component.UIXSelectMany._destructiveCompareOutOfOrderLists(UIXSelectMany.java:179)

 at org.apache.myfaces.trinidad.component.UIXSelectMany.compareValues(UIXSelectMany.java:139)

 at org.apache.myfaces.trinidad.component.UIXEditableValue.validate(UIXEditableValue.java:180)

 at org.apache.myfaces.trinidad.component.UIXEditableValue._executeValidate(UIXEditableValue.java:503)

 at org.apache.myfaces.trinidad.component.UIXEditableValue.processValidators(UIXEditableValue.java:270)

 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1058)

 at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1058)

I use OpenEntityManagerInViewFilter from Spring to get lazy loaded objects - that works in one request.

On the level of HyperJAXB generated object equals() method calls equals(Object object, EqualsBuilder equalsBuilder) method where equalsBuilder.append(...) is called on each attribute of that object. When that attribute is a list it is proxied by PersistenBag and that is the point where I get the LazyInitializationException.

equals() method - generated by HyperJaxb:

public boolean equals(Object object) {
    if (!(object instanceof ParentObject)) {
        return false;
    }
    if (this == object) {
        return true;
    }
    final EqualsBuilder equalsBuilder = new JAXBEqualsBuilder();
    equals(object, equalsBuilder);
    return equalsBuilder.isEquals();
}

equals(Object object, EqualsBuilder equalsBuilder) generated by HyperJaxb:

public void equals(Object object, EqualsBuilder equalsBuilder) {
    if (!(object instanceof ParentObject)) {
        equalsBuilder.appendSuper(false);
        return ;
    }
    if (this == object) {
        return ;
    }
    final ParentObjectthat = ((ParentObject) object);
    // PersitentBag, LazyInitializationException is thrown here
    equalsBuilder.append(this.getAnObject(), that.getAnObject());
    equalsBuilder.append(this.get..., that.get...);
    ...
}

Do you guys have any ideas how fix this problem?

I tried to use JSF converter and have SelectItem with a String value (not object) but if I remember right equals() is called after String is converted to my object.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

揽月 2024-10-01 15:35:14

之所以会出现这种情况,是因为您的对象未分离 (1),并且您在会话 (3) 之外访问数据 (2)。要更正,您应该以任意组合解决 (1-3)。

  1. 分离你的对象。这可能是最简单的,但它不是延迟加载。
  2. 确保会话可用。你说你正在使用 OEMIV 模式 - 为什么调用 equals 方法时会话不存在?我相信这是因为 equals 不是在视图渲染期间调用的,而是在其他一些 JSF 阶段调用的。您可以尝试扩展 OEMIV 模式,使其跨越整个 JSF 生命周期。
  3. 不要访问数据。建议使用 equals(...) 和 hashCode(...) 方法,但不是必需的。您可以在 HJ3 中禁用它们的生成,您可以从 hashCode()/equals(...) 构建中排除某些属性,您可以使用自己的 equals 和 hashCode 策略 - 有很多方法可以实现这一点。

就我个人而言,我会首先检查为什么会话不存在。

You get this because your objects are not detached (1) and you access data (2) outside the session (3). To correct, you should address (1-3) in any combination.

  1. Detach your objects. This is probably the easiest, but it's no lazy loading.
  2. Make sure the session is available. You say you're using OEMIV pattern - how comes that the session isn't there when the equals method is called? I believe it's because equals is called not during the view rendering but in some other JSF phases. You can try to extend the OEMIV pattern to make it span over the whole JSF lifecycle.
  3. Don't access the data. equals(...) and hashCode(...) methods are recommended, but not required. You can disable their generation in HJ3, you can exclude certain properties from hashCode()/equals(...) building, you can use your own equals and hashCode strategies - plenty of ways to achieve this.

Me personally, I'd check first, why is the session not there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文