简体   繁体   English

合并现有 Hibernate model object 时出现 UnsupportedOperationException?

[英]UnsupportedOperationException when merging an existing Hibernate model object?

After an upgrade from Hibernate 3 to 4, we're working through a few kinks that popped up along the way.从 Hibernate 3 升级到 4 后,我们正在解决沿途出现的一些问题。 One that has us particularly stumped is an UnsupportedOperationException, where an existing object is pulled from the database, tweaked, and merged.一个让我们特别难过的是 UnsupportedOperationException,其中现有的 object 从数据库中提取、调整和合并。

The problem is that Hibernate appears to be adding an object to an AbstractList问题是 Hibernate 似乎将 object 添加到AbstractList

This only seems to happen to one particular object type, when saved in our DAO, but as best as we can tell:当保存在我们的 DAO 中时,这似乎只发生在一种特定的 object 类型上,但据我们所知:

  1. We're not using any sublist() or asList() methods that would cause an immutable instance to be created.我们没有使用任何会导致创建不可变实例的 sublist() 或 asList() 方法。
  2. Examining the object that's being saved (which is enormous and has many children) I don't think that any of its children items are AbstractList types.检查正在保存的 object(它很大并且有很多子项)我认为它的任何子项都不是AbstractList类型。

Here are the code snippets around the stack points:以下是堆栈点周围的代码片段:

HibernateDao.save(): HibernateDao.save():

@Transactional
public void save(T item) {
    try {
        getSessionFactory().getCurrentSession().merge(item);
    } catch (Exception ex) {
        LOGGER.debug("Unable to merge", ex);
        LOGGER.warn("Unable to merge item, saving instead. (Of type " + item.getClass() + ")");
        getSessionFactory().getCurrentSession().saveOrUpdate(item);
    }
}

Our User item, which is being saved, has a number of children items defined like so:我们正在保存的用户项目有许多子项目定义如下:

@OneToMany(cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
private Map<String, Project> associatedProjects = new HashMap<String, Project>();

The Project class has other similarly-annotated children, but everything has CascadeType.ALL , and LazyCollectionOption.FALSE defined. Project class 有其他类似注释的子项,但所有内容都定义了CascadeType.ALLLazyCollectionOption.FALSE

Here is the (quite tall) stack trace:这是(相当高的)堆栈跟踪:

Note that our code begins with com.company.application请注意,我们的代码以com.company.application

06/04 18:15:45 DEBUG [Thread-19258] hibernate.HibernateDao.save- Unable to merge
java.lang.UnsupportedOperationException
        at java.util.AbstractList.add(AbstractList.java:148)
        at java.util.AbstractList.add(AbstractList.java:108)
        at org.hibernate.collection.internal.PersistentBag.add(PersistentBag.java:292)
        at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:496)
        at org.hibernate.type.CollectionType.replace(CollectionType.java:563)
        at org.hibernate.type.AbstractType.replace(AbstractType.java:178)
        at org.hibernate.type.TypeHelper.replaceAssociations(TypeHelper.java:261)
        at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:398)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:221)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:282)
        at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
        at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
        at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896)
        at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288)
        at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
        at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
        at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
        at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
        at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:439)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:308)
        at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
        at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
        at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896)
        at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288)
        at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
        at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
        at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
        at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
        at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:439)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:308)
        at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
        at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
        at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896)
        at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288)
        at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
        at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
        at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
        at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
        at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:439)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:308)
        at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
        at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
        at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:904)
        at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:888)
        at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:892)
        at com.company.hibernate.HibernateDao.save(HibernateDao.java:129)
        at sun.reflect.GeneratedMethodAccessor62.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
        at $Proxy53.save(Unknown Source)
        at com.company.application.UserManager.save(UserManager.java:46)
        at sun.reflect.GeneratedMethodAccessor67.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
        at $Proxy66.save(Unknown Source)
        at com.company.application.UserOperationController.saveUser(UserOperationController.java:533)

We're not sure where the AbstractList is coming from, or how we're responsible.我们不确定 AbstractList 来自哪里,或者我们如何负责。 Are there any potential pitfalls when working with Hibernate 4 (this issue is new since the upgrade) that could result in partially-unmodifiable objects?使用 Hibernate 4(这个问题是升级后的新问题)时是否存在任何可能导致部分不可修改的对象的潜在陷阱? Or that would cause Hibernate to act in a way that results in it attempting to create unmodifiable instances of objects?或者这会导致 Hibernate 的行为方式导致它尝试创建不可修改的对象实例?

In this block of code:在这个代码块中:

@OneToMany(cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
private Map<String, Project> associatedProjects = new HashMap<String, Project>();

how about to add this.怎么加这个。

@OneToMany(cascade = CascadeType.ALL)

*****@JoinColumn(name="")***** 

@LazyCollection(LazyCollectionOption.FALSE)
private Map<String, Project> associatedProjects = new HashMap<String, Project>();

I ran into this same issue (with Sets not Lists ) and it seems like Hibernate's Persistent variant of the collection in question attempts to delegate to an abstract base class that doesn't implement the add method.我遇到了同样的问题(使用Sets而不是Lists ),似乎有问题的集合的 Hibernate 的 Persistent 变体试图委托给一个没有实现add方法的抽象基类。 The solution I found was to set the data member to null, do a merge and then set the data member back to the new list that I wanted it to contain.我找到的解决方案是将数据成员设置为 null,进行merge ,然后将数据成员设置回我希望它包含的新列表。 The rather obvious downside is that I blow away all of the records even if I only want to add or remove one.相当明显的缺点是,即使我只想添加或删除一个记录,我也会吹掉所有记录。 The upside is that it actually works...好处是它确实有效......

I had the same effect for recently - I had used java.util.Arrays#asList in my test case.我最近有同样的效果 - 我在我的测试用例中使用java.util.Arrays#asList

It was easy to miss, as the returned class is named ArrayList , but it was not java.util.ArrayList , but java.util.Arrays.ArrayList很容易错过,因为返回的 class 被命名为ArrayList ,但它不是java.util.ArrayList ,而是java.util.Arrays.ArrayList

使用此交易类型:

@javax.transaction.Transactional(Transactional.TxType.REQUIRES_NEW)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM