/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.test.event.collection.detached; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.hibernate.Session; import org.hibernate.event.spi.AbstractCollectionEvent; import org.hibernate.event.spi.PostCollectionRecreateEvent; import org.hibernate.event.spi.PreCollectionRemoveEvent; import org.hibernate.event.spi.PreCollectionUpdateEvent; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; /** * Test HHH-6361: Collection events may contain wrong stored snapshot after * merging a detached entity into the persistencecontext. * * @author Erik-Berndt Scheper */ @TestForIssue( jiraKey = "HHH-6361" ) public class DetachedMultipleCollectionChangeTest extends BaseCoreFunctionalTestCase { @Override public String[] getMappings() { return new String[] { "event/collection/detached/MultipleCollectionBagMapping.hbm.xml" }; } @Override protected void cleanupTest() { Session s = null; s = openSession(); s.beginTransaction(); s.createQuery("delete MultipleCollectionRefEntity1").executeUpdate(); s.createQuery("delete MultipleCollectionRefEntity2").executeUpdate(); s.createQuery("delete MultipleCollectionEntity").executeUpdate(); s.getTransaction().commit(); s.close(); } @Test public void testMergeMultipleCollectionChangeEvents() { MultipleCollectionListeners listeners = new MultipleCollectionListeners( sessionFactory()); listeners.clear(); int eventCount = 0; List<MultipleCollectionRefEntity1> oldRefentities1 = new ArrayList<MultipleCollectionRefEntity1>(); List<MultipleCollectionRefEntity2> oldRefentities2 = new ArrayList<MultipleCollectionRefEntity2>(); Session s = openSession(); s.beginTransaction(); MultipleCollectionEntity mce = new MultipleCollectionEntity(); mce.setText("MultipleCollectionEntity-1"); s.save(mce); s.getTransaction().commit(); checkListener(listeners, listeners.getPreCollectionRecreateListener(), mce, oldRefentities1, eventCount++); checkListener(listeners, listeners.getPostCollectionRecreateListener(), mce, oldRefentities1, eventCount++); checkListener(listeners, listeners.getPreCollectionRecreateListener(), mce, oldRefentities2, eventCount++); checkListener(listeners, listeners.getPostCollectionRecreateListener(), mce, oldRefentities2, eventCount++); checkEventCount(listeners, eventCount); s.close(); Long mceId1 = mce.getId(); assertNotNull(mceId1); // add new entities to both collections MultipleCollectionEntity prevMce = mce.deepCopy(); oldRefentities1 = prevMce.getRefEntities1(); oldRefentities2 = prevMce.getRefEntities2(); listeners.clear(); eventCount = 0; s = openSession(); s.beginTransaction(); MultipleCollectionRefEntity1 re1_1 = new MultipleCollectionRefEntity1(); re1_1.setText("MultipleCollectionRefEntity1-1"); re1_1.setMultipleCollectionEntity(mce); MultipleCollectionRefEntity1 re1_2 = new MultipleCollectionRefEntity1(); re1_2.setText("MultipleCollectionRefEntity1-2"); re1_2.setMultipleCollectionEntity(mce); mce.addRefEntity1(re1_1); mce.addRefEntity1(re1_2); mce = (MultipleCollectionEntity) s.merge(mce); s.getTransaction().commit(); s.close(); checkListener(listeners, listeners.getInitializeCollectionListener(), mce, null, eventCount++); checkListener(listeners, listeners.getPreCollectionUpdateListener(), mce, oldRefentities1, eventCount++); checkListener(listeners, listeners.getPostCollectionUpdateListener(), mce, mce.getRefEntities1(), eventCount++); s = openSession(); s.beginTransaction(); MultipleCollectionRefEntity2 re2_1 = new MultipleCollectionRefEntity2(); re2_1.setText("MultipleCollectionRefEntity2-1"); re2_1.setMultipleCollectionEntity(mce); MultipleCollectionRefEntity2 re2_2 = new MultipleCollectionRefEntity2(); re2_2.setText("MultipleCollectionRefEntity2-2"); re2_2.setMultipleCollectionEntity(mce); mce.addRefEntity2(re2_1); mce.addRefEntity2(re2_2); mce = (MultipleCollectionEntity) s.merge(mce); s.getTransaction().commit(); checkListener(listeners, listeners.getInitializeCollectionListener(), mce, null, eventCount++); checkListener(listeners, listeners.getPreCollectionUpdateListener(), mce, oldRefentities2, eventCount++); checkListener(listeners, listeners.getPostCollectionUpdateListener(), mce, mce.getRefEntities2(), eventCount++); checkEventCount(listeners, eventCount); s.close(); for (MultipleCollectionRefEntity1 refEnt1 : mce.getRefEntities1()) { assertNotNull(refEnt1.getId()); } for (MultipleCollectionRefEntity2 refEnt2 : mce.getRefEntities2()) { assertNotNull(refEnt2.getId()); } // remove and add entities in both collections prevMce = mce.deepCopy(); oldRefentities1 = prevMce.getRefEntities1(); oldRefentities2 = prevMce.getRefEntities2(); listeners.clear(); eventCount = 0; s = openSession(); s.beginTransaction(); assertEquals(2, mce.getRefEntities1().size()); assertEquals(2, mce.getRefEntities2().size()); mce.removeRefEntity1(re1_2); MultipleCollectionRefEntity1 re1_3 = new MultipleCollectionRefEntity1(); re1_3.setText("MultipleCollectionRefEntity1-3"); re1_3.setMultipleCollectionEntity(mce); mce.addRefEntity1(re1_3); mce = (MultipleCollectionEntity) s.merge(mce); s.getTransaction().commit(); s.close(); checkListener(listeners, listeners.getInitializeCollectionListener(), mce, null, eventCount++); checkListener(listeners, listeners.getPreCollectionUpdateListener(), mce, oldRefentities1, eventCount++); checkListener(listeners, listeners.getPostCollectionUpdateListener(), mce, mce.getRefEntities1(), eventCount++); s = openSession(); s.beginTransaction(); mce.removeRefEntity2(re2_2); MultipleCollectionRefEntity2 re2_3 = new MultipleCollectionRefEntity2(); re2_3.setText("MultipleCollectionRefEntity2-3"); re2_3.setMultipleCollectionEntity(mce); mce.addRefEntity2(re2_3); mce = (MultipleCollectionEntity) s.merge(mce); s.getTransaction().commit(); checkListener(listeners, listeners.getInitializeCollectionListener(), mce, null, eventCount++); checkListener(listeners, listeners.getPreCollectionUpdateListener(), mce, oldRefentities2, eventCount++); checkListener(listeners, listeners.getPostCollectionUpdateListener(), mce, mce.getRefEntities2(), eventCount++); checkEventCount(listeners, eventCount); s.close(); } protected void checkListener( MultipleCollectionListeners listeners, MultipleCollectionListeners.Listener listenerExpected, org.hibernate.test.event.collection.Entity ownerExpected, List<? extends org.hibernate.test.event.collection.Entity> expectedCollectionEntrySnapshot, int index) { AbstractCollectionEvent event = listeners .getEvents().get(index); assertSame(listenerExpected, listeners.getListenersCalled().get(index)); assertEquals(ownerExpected, event.getAffectedOwnerOrNull()); assertEquals(ownerExpected.getId(), event.getAffectedOwnerIdOrNull()); assertEquals(ownerExpected.getClass().getName(), event.getAffectedOwnerEntityName()); if (event instanceof PreCollectionUpdateEvent) { Serializable snapshot = listeners.getSnapshots().get(index); assertEquals(expectedCollectionEntrySnapshot, snapshot); } if (event instanceof PreCollectionRemoveEvent) { Serializable snapshot = listeners.getSnapshots().get(index); assertEquals(expectedCollectionEntrySnapshot, snapshot); } if (event instanceof PostCollectionRecreateEvent) { Serializable snapshot = listeners.getSnapshots().get(index); assertEquals(expectedCollectionEntrySnapshot, snapshot); } } private void checkEventCount(MultipleCollectionListeners listeners, int nEventsExpected) { assertEquals(nEventsExpected, listeners.getListenersCalled().size()); assertEquals(nEventsExpected, listeners.getEvents().size()); } }