GSON + Hibernate: Identical objects causing "An entity copy was already assigned to a different entity"

gson, hibernate, jpa

Solution

Here is my working solution not using merge:

I use reflection to iterate over the fields at binding time. I check if the field is an entity or a collection of entities and then call a findByID if the id if provided in the json or create a new instance of the entity if not to get an attached entity. After that I copy the field values that exists in the json via reflection into the attached entity. I do it recursively to handle relations between the entities. After that I have a completly merged and attached version of my entity with all that attached and merged subobjects. I can save it without any Problems

Important note:

Andrei I suggested a lot of logical problems that could occur and changing the api to not get the full countries, but just their IDs would be more clearly. I prefer this and will do this in the future. Therefore Andrei I earned the bounty.

Problem

I have the following JSON: ``` { id: 123, subObjects: [ { id: 564, name: "foo", contry: { id: 1, name: "Germany" } }, { id: 777, name: "bar", contry: { id: 1, name: "Germany" } } ] } ``` And deserialize it using Gson. After that I need to merge the JPA Entity: ``` Model model = new Gson().fromJson(json, modelClass); model = entityManager.merge(model) ``` The refresh is cascaded from the model to the subObjects and down to the countries. This causes the Exception "An entity copy was already assigned to a different entity" by Hibernate. It works if I use different countries. It works if I use copy the country instance from one object into the other one so both subObjects references the same instance of that contry. Both countries have identical values in it. Both have the same hashCode, too. The both countries are equal but not == since they are different instances. The tipps listed on this question did not help me. I am using Hibernate 4.1.3 Final and Gson 2.2 ``` java.lang.IllegalStateException: An entity copy was already assigned to a different entity. at org.hibernate.event.internal.EventCache.put(EventCache.java:184) at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:285) 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.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 org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:874) at play.db.jpa.GenericModel.merge(GenericModel.java:234) [...] ``` How can I solve this problem in a generic way I don't need to know the object types and which objects are logically identical?

Original source

Related problems