HHH-9106 : Merging multiple representations of the same entity (tests using StrategySelector)

(cherry picked from commit 368cdc1966)
This commit is contained in:
Gail Badner 2014-07-03 11:21:26 -07:00
parent 1472681dc2
commit c7c57fc7ee
11 changed files with 662 additions and 13 deletions

View File

@ -0,0 +1,41 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.ops;
import org.hibernate.cfg.Configuration;
/**
* Tests merging multiple detached representations of the same entity when explicitly allowed and logged.
*
* @author Gail Badner
*/
public class MergeMultipleEntityCopiesAllowedLoggedTest extends MergeMultipleEntityCopiesAllowedTest {
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty(
"hibernate.event.merge.entity_copy_observer",
"log"
);
}
}

View File

@ -36,17 +36,16 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Tests merging multiple detached representations of the same entity
* Tests merging multiple detached representations of the same entity (allowed)
* where some associations include cascade="delete-orphan"
*
* @author Gail Badner
*/
public class MergeMultipleEntityRepresentationsOrphanDeleteTest extends BaseCoreFunctionalTestCase {
public class MergeMultipleEntityCopiesAllowedOrphanDeleteTest extends BaseCoreFunctionalTestCase {
public String[] getMappings() {
return new String[] {

View File

@ -44,11 +44,11 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Tests merging multiple detached representations of the same entity.
* Tests merging multiple detached representations of the same entity when explicitly allowed.
*
* @author Gail Badner
*/
public class MergeMultipleEntityRepresentationsTest extends BaseCoreFunctionalTestCase {
public class MergeMultipleEntityCopiesAllowedTest extends BaseCoreFunctionalTestCase {
public String[] getMappings() {
return new String[] {

View File

@ -0,0 +1,235 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.ops;
import java.util.List;
import org.junit.Test;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.event.spi.EntityCopyObserver;
import org.hibernate.event.spi.EventSource;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* Tests merging multiple detached representations of the same entity using a custom EntityCopyObserver.
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityCopiesCustomTest extends BaseCoreFunctionalTestCase {
public String[] getMappings() {
return new String[] {
"ops/Hoarder.hbm.xml"
};
}
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty(
"hibernate.event.merge.entity_copy_observer",
CustomEntityCopyObserver.class.getName()
);
}
@Test
public void testMergeMultipleEntityCopiesAllowed() {
Item item1 = new Item();
item1.setName( "item1" );
Hoarder hoarder = new Hoarder();
hoarder.setName( "joe" );
Session s = openSession();
s.getTransaction().begin();
s.persist( item1 );
s.persist( hoarder );
s.getTransaction().commit();
s.close();
// Get another representation of the same Item.
s = openSession();
Item item1_1 = (Item) s.get( Item.class, item1.getId() );
s.close();
// item1_1 and item1_2 are unmodified representations of the same persistent entity.
assertFalse( item1 == item1_1 );
assertTrue( item1.equals( item1_1 ) );
// Update hoarder (detached) to references both representations.
hoarder.getItems().add( item1 );
hoarder.setFavoriteItem( item1_1 );
s = openSession();
s.getTransaction().begin();
// the merge should succeed because it does not have Category copies.
// (CustomEntityCopyObserver does not allow Category copies; it does allow Item copies)
hoarder = (Hoarder) s.merge( hoarder );
assertEquals( 1, hoarder.getItems().size() );
assertSame( hoarder.getFavoriteItem(), hoarder.getItems().iterator().next() );
assertEquals( item1.getId(), hoarder.getFavoriteItem().getId() );
assertEquals( item1.getCategory(), hoarder.getFavoriteItem().getCategory() );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
hoarder = (Hoarder) s.get( Hoarder.class, hoarder.getId() );
assertEquals( 1, hoarder.getItems().size() );
assertSame( hoarder.getFavoriteItem(), hoarder.getItems().iterator().next() );
assertEquals( item1.getId(), hoarder.getFavoriteItem().getId() );
assertEquals( item1.getCategory(), hoarder.getFavoriteItem().getCategory() );
s.getTransaction().commit();
s.close();
cleanup();
}
@Test
public void testMergeMultipleEntityCopiesAllowedAndDisallowed() {
Item item1 = new Item();
item1.setName( "item1 name" );
Category category = new Category();
category.setName( "category" );
item1.setCategory( category );
category.setExampleItem( item1 );
Session s = openSession();
s.getTransaction().begin();
s.persist( item1 );
s.getTransaction().commit();
s.close();
// get another representation of item1
s = openSession();
s.getTransaction().begin();
Item item1_1 = (Item) s.get( Item.class, item1.getId() );
// make sure item1_1.category is initialized
Hibernate.initialize( item1_1.getCategory() );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
Item item1Merged = (Item) s.merge( item1 );
item1Merged.setCategory( category );
category.setExampleItem( item1_1 );
// now item1Merged is managed and it has a nested detached item
// and there is multiple managed/detached Category objects
try {
// the following should fail because multiple copies of Category objects is not allowed by
// CustomEntityCopyObserver
s.merge( item1Merged );
fail( "should have failed because CustomEntityCopyObserver does not allow multiple copies of a Category. ");
}
catch (IllegalStateException ex ) {
// expected
}
finally {
s.getTransaction().rollback();
}
s.close();
s = openSession();
s.getTransaction().begin();
item1 = (Item) s.get( Item.class, item1.getId() );
assertEquals( category.getName(), item1.getCategory().getName() );
assertSame( item1, item1.getCategory().getExampleItem() );
s.getTransaction().commit();
s.close();
cleanup();
}
@SuppressWarnings( {"unchecked"})
private void cleanup() {
Session s = openSession();
s.getTransaction().begin();
for ( Hoarder hoarder : (List<Hoarder>) s.createQuery( "from Hoarder" ).list() ) {
hoarder.getItems().clear();
s.delete( hoarder );
}
for ( Category category : (List<Category>) s.createQuery( "from Category" ).list() ) {
if ( category.getExampleItem() != null ) {
category.setExampleItem( null );
s.delete( category );
}
}
for ( Item item : (List<Item>) s.createQuery( "from Item" ).list() ) {
item.setCategory( null );
s.delete( item );
}
s.createQuery( "delete from Item" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
@Override
public Class[] getAnnotatedClasses() {
return new Class[] {
Category.class,
Hoarder.class,
Item.class
};
}
public static class CustomEntityCopyObserver implements EntityCopyObserver {
@Override
public void entityCopyDetected(Object managedEntity, Object mergeEntity1, Object mergeEntity2, EventSource session) {
if ( Category.class.isInstance( managedEntity ) ) {
throw new IllegalStateException(
String.format( "Entity copies of type [%s] not allowed", Category.class.getName() )
);
}
}
@Override
public void topLevelMergeComplete(EventSource session) {
}
@Override
public void clear() {
}
}
}

View File

@ -38,12 +38,12 @@ import static org.junit.Assert.assertTrue;
/**
* Tests merging multiple detached representations of the same entity using
* a the default MergeEventListener (that does not allow this).
* a the default (that does not allow this).
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityRepresentationsNotAllowedTest extends BaseCoreFunctionalTestCase {
public class MergeMultipleEntityCopiesDisallowedByDefaultTest extends BaseCoreFunctionalTestCase {
public String[] getMappings() {
return new String[] {

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.ops;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.TestForIssue;
/**
* Tests merging multiple detached representations of the same entity when explicitly disallowed.
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityCopiesDisallowedTest extends MergeMultipleEntityCopiesDisallowedByDefaultTest {
public void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty(
"hibernate.event.merge.entity_copy_observer",
"disallow"
);
}
}

View File

@ -0,0 +1,46 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.test.emops;
import java.util.Map;
import org.hibernate.testing.TestForIssue;
/**
* Tests merging multiple detached representations of the same entity when it is explicitly allowed and logged.
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityCopiesAllowedLoggedTest extends MergeMultipleEntityCopiesAllowedTest {
@SuppressWarnings( {"unchecked"})
protected void addConfigOptions(Map options) {
super.addConfigOptions( options );
options.put(
"hibernate.event.merge.entity_copy_observer",
"log"
);
}
}

View File

@ -38,15 +38,16 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
/**
* Tests merging multiple detached representations of the same entity.
* Tests merging multiple detached representations of the same entity when it is explicitly allowed.
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityRepresentationsAllowedTest extends BaseEntityManagerFunctionalTestCase {
public class MergeMultipleEntityCopiesAllowedTest extends BaseEntityManagerFunctionalTestCase {
@SuppressWarnings( {"unchecked"})
protected void addConfigOptions(Map options) {
super.addConfigOptions( options );
options.put(
"hibernate.event.merge.entity_copy_observer",
"allow"

View File

@ -0,0 +1,235 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.test.emops;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import org.junit.Test;
import org.hibernate.Hibernate;
import org.hibernate.event.spi.EntityCopyObserver;
import org.hibernate.event.spi.EventSource;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
/**
* Tests merging multiple detached representations of the same entity using a custom EntityCopyObserver.
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityCopiesCustomTest extends BaseEntityManagerFunctionalTestCase {
@SuppressWarnings( {"unchecked"})
protected void addConfigOptions(Map options) {
super.addConfigOptions( options );
options.put(
"hibernate.event.merge.entity_copy_observer",
CustomEntityCopyObserver.class.getName()
);
}
@Test
public void testMergeMultipleEntityCopiesAllowed() {
Item item1 = new Item();
item1.setName( "item1" );
Hoarder hoarder = new Hoarder();
hoarder.setName( "joe" );
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
em.persist( item1 );
em.persist( hoarder );
em.getTransaction().commit();
em.close();
// Get another representation of the same Item from a different EntityManager.
em = getOrCreateEntityManager();
Item item1_1 = em.find( Item.class, item1.getId() );
em.close();
// item1_1 and item1_2 are unmodified representations of the same persistent entity.
assertFalse( item1 == item1_1 );
assertTrue( item1.equals( item1_1 ) );
// Update hoarder (detached) to references both representations.
hoarder.getItems().add( item1 );
hoarder.setFavoriteItem( item1_1 );
em = getOrCreateEntityManager();
em.getTransaction().begin();
// the merge should succeed because it does not have Category copies.
// (CustomEntityCopyObserver does not allow Category copies; it does allow Item copies)
hoarder = em.merge( hoarder );
assertEquals( 1, hoarder.getItems().size() );
assertSame( hoarder.getFavoriteItem(), hoarder.getItems().iterator().next() );
assertEquals( item1.getId(), hoarder.getFavoriteItem().getId() );
assertEquals( item1.getCategory(), hoarder.getFavoriteItem().getCategory() );
em.getTransaction().commit();
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
hoarder = em.find( Hoarder.class, hoarder.getId() );
assertEquals( 1, hoarder.getItems().size() );
assertSame( hoarder.getFavoriteItem(), hoarder.getItems().iterator().next() );
assertEquals( item1.getId(), hoarder.getFavoriteItem().getId() );
assertEquals( item1.getCategory(), hoarder.getFavoriteItem().getCategory() );
em.getTransaction().commit();
em.close();
cleanup();
}
@Test
public void testMergeMultipleEntityCopiesAllowedAndDisallowed() {
Item item1 = new Item();
item1.setName( "item1 name" );
Category category = new Category();
category.setName( "category" );
item1.setCategory( category );
category.setExampleItem( item1 );
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
em.persist( item1 );
em.getTransaction().commit();
em.close();
// get another representation of item1
em = getOrCreateEntityManager();
em.getTransaction().begin();
Item item1_1 = em.find( Item.class, item1.getId() );
// make sure item1_1.category is initialized
Hibernate.initialize( item1_1.getCategory() );
em.getTransaction().commit();
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
Item item1Merged = em.merge( item1 );
// make sure item1Merged.category is also managed
Hibernate.initialize( item1Merged.getCategory() );
item1Merged.setCategory( category );
category.setExampleItem( item1_1 );
// now item1Merged is managed and it has a nested detached item
// and there is multiple managed/detached Category objects
try {
// the following should fail because multiple copies of Category objects is not allowed by
// CustomEntityCopyObserver
em.merge( item1Merged );
fail( "should have failed because CustomEntityCopyObserver does not allow multiple copies of a Category. ");
}
catch (IllegalStateException ex ) {
// expected
}
finally {
em.getTransaction().rollback();
}
em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
item1 = em.find( Item.class, item1.getId() );
assertEquals( category.getName(), item1.getCategory().getName() );
assertSame( item1, item1.getCategory().getExampleItem() );
em.getTransaction().commit();
em.close();
cleanup();
}
@SuppressWarnings( {"unchecked"})
private void cleanup() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
for ( Hoarder hoarder : (List<Hoarder>) em.createQuery( "from Hoarder" ).getResultList() ) {
hoarder.getItems().clear();
em.remove( hoarder );
}
for ( Category category : (List<Category>) em.createQuery( "from Category" ).getResultList() ) {
if ( category.getExampleItem() != null ) {
category.setExampleItem( null );
em.remove( category );
}
}
for ( Item item : (List<Item>) em.createQuery( "from Item" ).getResultList() ) {
item.setCategory( null );
em.remove( item );
}
em.createQuery( "delete from Item" ).executeUpdate();
em.getTransaction().commit();
em.close();
}
@Override
public Class[] getAnnotatedClasses() {
return new Class[] {
Category.class,
Hoarder.class,
Item.class
};
}
public static class CustomEntityCopyObserver implements EntityCopyObserver {
@Override
public void entityCopyDetected(Object managedEntity, Object mergeEntity1, Object mergeEntity2, EventSource session) {
if ( Category.class.isInstance( managedEntity ) ) {
throw new IllegalStateException(
String.format( "Entity copies of type [%s] not allowed", Category.class.getName() )
);
}
}
@Override
public void topLevelMergeComplete(EventSource session) {
}
@Override
public void clear() {
}
}
}

View File

@ -37,13 +37,13 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Tests merging multiple detached representations of the same entity using
* a the default MergeEventListener (that does not allow this).
* Tests merging multiple detached representations of the same entity when
* not allowed by default.
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityRepresentationsNotAllowedTest extends BaseEntityManagerFunctionalTestCase {
public class MergeMultipleEntityCopiesDisallowedByDefaultTest extends BaseEntityManagerFunctionalTestCase {
@Test
public void testCascadeFromDetachedToNonDirtyRepresentations() {

View File

@ -0,0 +1,47 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.test.emops;
import java.util.Map;
import org.hibernate.testing.TestForIssue;
/**
* Tests merging multiple detached representations of the same entity when
* explicitly disallowed.
*
* @author Gail Badner
*/
@TestForIssue( jiraKey = "HHH-9106")
public class MergeMultipleEntityCopiesDisallowedTest extends MergeMultipleEntityCopiesDisallowedByDefaultTest {
@SuppressWarnings( {"unchecked"})
protected void addConfigOptions(Map options) {
super.addConfigOptions( options );
options.put(
"hibernate.event.merge.entity_copy_observer",
"disallow"
);
}
}