2012-06-04 9 views
9

Dopo un aggiornamento da Hibernate 3 a 4, stiamo lavorando su alcuni nodi che sono comparsi lungo la strada. Uno che ci ha particolarmente impressionato è un UnsupportedOperationException, in cui un oggetto esistente viene estratto dal database, ottimizzato e unito.UnsupportedOperationException durante l'unione di un oggetto modello Hibernate esistente?

Il problema è che Hibernate sembra essere l'aggiunta di un oggetto in un AbstractList

Questo sembra accadere solo a un particolare tipo di oggetto, quando viene salvato nel nostro DAO, ma come meglio possiamo dire:

  1. Non stiamo usando alcun metodo sublist() o asList() che causerebbe la creazione di un'istanza immutabile.
  2. Esaminando l'oggetto che si sta salvando (che è enorme e ha molti figli) Io non rispondo allo allo che uno dei suoi elementi figli è AbstractList tipi.

Qui ci sono i frammenti di codice intorno ai punti di stack:

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); 
    } 
} 

Il nostro articolo utente, che viene salvato, ha una serie di articoli per bambini definiti in questo modo:

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

T La classe Project ha altri figli con annotazione simile, ma tutto ha CascadeType.ALL e LazyCollectionOption.FALSE definiti.

Ecco la (piuttosto alto) analisi dello stack:

Si noti che il nostro codice inizia con 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) 

Non siamo sicuri di dove l'AbstractList sta venendo, o come noi siamo responsabili. Ci sono potenziali insidie ​​quando si lavora con Hibernate 4 (questo problema è nuovo dopo l'aggiornamento) che potrebbe causare oggetti parzialmente non modificabili? O quello farebbe in modo che Hibernate agisca in modo tale da provocare il tentativo di creare istanze di oggetti non modificabili?

+0

Dal stacktrace, suona come l'unione viene in cascata ad altri oggetti associati con l'utente. Avete delle collezioni mappate come un tipo di Borsa? –

+0

Per me sembra un errore in ibernazione, il che renderebbe brutto aggirare quel problema. Penso che l'unica possibilità di ottenere sia quella di scoprire quale figlio o nipote dell'elemento produce questo errore. Per i test puoi unire manualmente i bambini (e forse i nipotini) di 'item' invece di lasciarlo a cascata. – Johanna

+0

@mattb Sicuramente non abbiamo alcun tipo di Borsa: solo HashMap e ArrayList. Esaminando l'oggetto appena prima che Hibernate lo unisca, sembra che molti dei tipi di ArrayList siano stati in realtà avvolti da Hibernate in PersistentBag. (Ma, sotto le borse c'erano reali implementazioni concrete di ArrayList, quindi non ho visto che questo fosse un problema.) –

risposta

1

@OneToMany (cascade = CascadeType.ALL) @LazyCollection (LazyCollectionOption.FALSE) Mappa associatedProjects private = new HashMap();

come aggiungere questo.

@OneToMany (cascade = CascadeType.ALL)

* @ JoinColumn (name = "") *

@LazyCollection (LazyCollectionOption.FALSE) Mappa privata associataProjects = new HashMap();

0

Mi sono imbattuto in questo stesso problema (con Sets non Lists) e sembra che la variante persistente di Hibernate della collezione in questione tenta di delegare a una classe base astratta che non implementa il metodo add. La soluzione che ho trovato era quella di impostare il membro dati su null, fare un merge e quindi impostare il membro dei dati sul nuovo elenco che volevo che contenesse. Lo svantaggio piuttosto ovvio è che soffio via tutti i record anche se voglio solo aggiungerne uno o rimuoverne uno. Il vantaggio è che funziona davvero ...

0

Utilizzare questo tipo di transazione:

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