From e5f6d52012bf09c3cc0811f48a5acbdff442334c Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Tue, 31 Jul 2007 13:39:23 +0000 Subject: [PATCH] HHH-2711 : composite-map-key + unidir map can lead to PropertyAccessException git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@12859 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../component/PojoComponentTuplizer.java | 17 +- .../test/collection/CollectionSuite.java | 2 + .../compkey/BackrefCompositeMapKeyTest.java | 284 ++++++++++++++++++ .../backref/map/compkey/MapKey.java | 59 ++++ .../backref/map/compkey/Mappings.hbm.xml | 45 +++ .../collection/backref/map/compkey/Part.java | 52 ++++ .../backref/map/compkey/Product.java | 49 +++ 7 files changed, 501 insertions(+), 7 deletions(-) create mode 100644 testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/BackrefCompositeMapKeyTest.java create mode 100644 testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/MapKey.java create mode 100644 testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Mappings.hbm.xml create mode 100644 testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Part.java create mode 100644 testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Product.java diff --git a/core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java b/core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java index 3f0ef247ff..22b3925d78 100644 --- a/core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java +++ b/core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java @@ -1,25 +1,25 @@ //$Id: PojoComponentTuplizer.java 9619 2006-03-15 00:12:47Z steve.ebersole@jboss.com $ package org.hibernate.tuple.component; -import java.lang.reflect.Method; import java.io.Serializable; +import java.lang.reflect.Method; -import org.hibernate.HibernateException; import org.hibernate.AssertionFailure; -import org.hibernate.tuple.component.AbstractComponentTuplizer; -import org.hibernate.tuple.Instantiator; -import org.hibernate.tuple.PojoInstantiator; -import org.hibernate.util.ReflectHelper; -import org.hibernate.bytecode.ReflectionOptimizer; +import org.hibernate.HibernateException; import org.hibernate.bytecode.BasicProxyFactory; +import org.hibernate.bytecode.ReflectionOptimizer; import org.hibernate.cfg.Environment; import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.mapping.Component; import org.hibernate.mapping.Property; +import org.hibernate.property.BackrefPropertyAccessor; import org.hibernate.property.Getter; import org.hibernate.property.PropertyAccessor; import org.hibernate.property.PropertyAccessorFactory; import org.hibernate.property.Setter; +import org.hibernate.tuple.Instantiator; +import org.hibernate.tuple.PojoInstantiator; +import org.hibernate.util.ReflectHelper; /** * A {@link ComponentTuplizer} specific to the pojo entity mode. @@ -76,6 +76,9 @@ public class PojoComponentTuplizer extends AbstractComponentTuplizer { } public Object[] getPropertyValues(Object component) throws HibernateException { + if ( component == BackrefPropertyAccessor.UNKNOWN ) { + return new Object[ propertySpan ]; + } if ( optimizer != null && optimizer.getAccessOptimizer() != null ) { return optimizer.getAccessOptimizer().getPropertyValues( component ); } diff --git a/testsuite/src/test/java/org/hibernate/test/collection/CollectionSuite.java b/testsuite/src/test/java/org/hibernate/test/collection/CollectionSuite.java index 8d3a8bea68..880d91550f 100644 --- a/testsuite/src/test/java/org/hibernate/test/collection/CollectionSuite.java +++ b/testsuite/src/test/java/org/hibernate/test/collection/CollectionSuite.java @@ -9,6 +9,7 @@ import org.hibernate.test.collection.list.PersistentListTest; import org.hibernate.test.collection.map.PersistentMapTest; import org.hibernate.test.collection.original.CollectionTest; import org.hibernate.test.collection.set.PersistentSetTest; +import org.hibernate.test.collection.backref.map.compkey.BackrefCompositeMapKeyTest; /** * Suite of collection (i.e. PersistentCollection) related tests @@ -25,6 +26,7 @@ public class CollectionSuite { suite.addTest( PersistentMapTest.suite() ); suite.addTest( CollectionTest.suite() ); suite.addTest( PersistentSetTest.suite() ); + suite.addTest( BackrefCompositeMapKeyTest.suite() ); return suite; } diff --git a/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/BackrefCompositeMapKeyTest.java b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/BackrefCompositeMapKeyTest.java new file mode 100644 index 0000000000..7c76b0800f --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/BackrefCompositeMapKeyTest.java @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved. + * + * 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, v. 2.1. This program is distributed in the + * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this + * distribution; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Red Hat Author(s): Steve Ebersole + */ +package org.hibernate.test.collection.backref.map.compkey; + +import junit.framework.Test; + +import org.hibernate.junit.functional.FunctionalTestCase; +import org.hibernate.junit.functional.FunctionalTestClassTestSuite; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.LockMode; +import org.hibernate.Hibernate; +import org.hibernate.util.SerializationHelper; + +/** + * BackrefCompositeMapKeyTest implementation. Test access to a composite map-key + * backref via a number of different access methods. + * + * @author Steve Ebersole + */ +public class BackrefCompositeMapKeyTest extends FunctionalTestCase { + public BackrefCompositeMapKeyTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "collection/backref/map/compkey/Mappings.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( BackrefCompositeMapKeyTest.class ); + } + + public void testOrphanDeleteOnDelete() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product( "Widget" ); + Part part = new Part( "Widge", "part if a Widget" ); + MapKey mapKey = new MapKey( "Top" ); + prod.getParts().put( mapKey, part ); + Part part2 = new Part( "Get", "another part if a Widget" ); + prod.getParts().put( new MapKey( "Bottom" ), part2 ); + session.persist( prod ); + session.flush(); + + prod.getParts().remove( mapKey ); + + session.delete( prod ); + + t.commit(); + session.close(); + + session = openSession(); + t = session.beginTransaction(); + assertNull( "Orphan 'Widge' was not deleted", session.get(Part.class, "Widge") ); + assertNull( "Orphan 'Get' was not deleted", session.get(Part.class, "Get") ); + assertNull( "Orphan 'Widget' was not deleted", session.get(Product.class, "Widget") ); + t.commit(); + session.close(); + } + + public void testOrphanDeleteAfterPersist() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product( "Widget" ); + Part part = new Part( "Widge", "part if a Widget" ); + MapKey mapKey = new MapKey( "Top" ); + prod.getParts().put( mapKey, part ); + Part part2 = new Part( "Get", "another part if a Widget" ); + prod.getParts().put( new MapKey( "Bottom" ), part2 ); + session.persist( prod ); + + prod.getParts().remove( mapKey ); + + t.commit(); + session.close(); + + session = openSession(); + t = session.beginTransaction(); + session.delete( session.get(Product.class, "Widget") ); + t.commit(); + session.close(); + } + + public void testOrphanDeleteAfterPersistAndFlush() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product( "Widget" ); + Part part = new Part( "Widge", "part if a Widget" ); + MapKey mapKey = new MapKey( "Top" ); + prod.getParts().put( mapKey, part ); + Part part2 = new Part( "Get", "another part if a Widget" ); + prod.getParts().put( new MapKey( "Bottom" ), part2 ); + session.persist( prod ); + session.flush(); + + prod.getParts().remove( mapKey ); + + t.commit(); + session.close(); + + session = openSession(); + t = session.beginTransaction(); + assertNull( session.get(Part.class, "Widge") ); + assertNotNull( session.get(Part.class, "Get") ); + session.delete( session.get(Product.class, "Widget") ); + t.commit(); + session.close(); + } + + public void testOrphanDeleteAfterLock() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product( "Widget" ); + Part part = new Part( "Widge", "part if a Widget" ); + MapKey mapKey = new MapKey( "Top" ); + prod.getParts().put( mapKey, part ); + Part part2 = new Part( "Get", "another part if a Widget" ); + prod.getParts().put( new MapKey( "Bottom" ),part2 ); + session.persist( prod ); + t.commit(); + session.close(); + + + session = openSession(); + t = session.beginTransaction(); + session.lock(prod, LockMode.READ); + prod.getParts().remove(mapKey); + t.commit(); + session.close(); + + session = openSession(); + t = session.beginTransaction(); + assertNull( session.get(Part.class, "Widge") ); + assertNotNull( session.get(Part.class, "Get") ); + session.delete( session.get(Product.class, "Widget") ); + t.commit(); + session.close(); + } + + public void testOrphanDeleteOnSaveOrUpdate() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product( "Widget" ); + Part part = new Part( "Widge", "part if a Widget" ); + MapKey mapKey = new MapKey( "Top" ); + prod.getParts().put( mapKey, part ); + Part part2 = new Part( "Get", "another part if a Widget" ); + prod.getParts().put( new MapKey( "Bottom" ), part2 ); + session.persist( prod ); + t.commit(); + session.close(); + + prod.getParts().remove( mapKey ); + + session = openSession(); + t = session.beginTransaction(); + session.saveOrUpdate(prod); + t.commit(); + session.close(); + + session = openSession(); + t = session.beginTransaction(); + assertNull( session.get(Part.class, "Widge") ); + assertNotNull( session.get(Part.class, "Get") ); + session.delete( session.get(Product.class, "Widget") ); + t.commit(); + session.close(); + } + + public void testOrphanDeleteOnSaveOrUpdateAfterSerialization() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product( "Widget" ); + Part part = new Part( "Widge", "part if a Widget" ); + MapKey mapKey = new MapKey( "Top" ); + prod.getParts().put( mapKey, part ); + Part part2 = new Part( "Get", "another part if a Widget" ); + prod.getParts().put( new MapKey( "Bottom" ), part2 ); + session.persist( prod ); + t.commit(); + session.close(); + + prod.getParts().remove( mapKey ); + + prod = (Product) SerializationHelper.clone( prod ); + + session = openSession(); + t = session.beginTransaction(); + session.saveOrUpdate(prod); + t.commit(); + session.close(); + + session = openSession(); + t = session.beginTransaction(); + assertNull( session.get(Part.class, "Widge") ); + assertNotNull( session.get(Part.class, "Get") ); + session.delete( session.get(Product.class, "Widget") ); + t.commit(); + session.close(); + } + + public void testOrphanDelete() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product( "Widget" ); + Part part = new Part( "Widge", "part if a Widget" ); + MapKey mapKey = new MapKey( "Top" ); + prod.getParts().put( mapKey, part ); + Part part2 = new Part( "Get", "another part if a Widget" ); + prod.getParts().put( new MapKey( "Bottom" ), part2 ); + session.persist( prod ); + t.commit(); + session.close(); + + getSessions().evict(Product.class); + getSessions().evict(Part.class); + + session = openSession(); + t = session.beginTransaction(); + prod = (Product) session.get(Product.class, "Widget"); + assertTrue( Hibernate.isInitialized( prod.getParts() ) ); + part = (Part) session.get(Part.class, "Widge"); + prod.getParts().remove(mapKey); + t.commit(); + session.close(); + + getSessions().evict(Product.class); + getSessions().evict(Part.class); + + session = openSession(); + t = session.beginTransaction(); + prod = (Product) session.get(Product.class, "Widget"); + assertTrue( Hibernate.isInitialized( prod.getParts() ) ); + assertNull( prod.getParts().get(new MapKey("Top"))); + assertNotNull( session.get(Part.class, "Get") ); + session.delete( session.get(Product.class, "Widget") ); + t.commit(); + session.close(); + } + + public void testOrphanDeleteOnMerge() { + Session session = openSession(); + Transaction t = session.beginTransaction(); + Product prod = new Product( "Widget" ); + Part part = new Part( "Widge", "part if a Widget" ); + MapKey mapKey = new MapKey( "Top" ); + prod.getParts().put( mapKey, part ); + Part part2 = new Part( "Get", "another part if a Widget" ); + prod.getParts().put( new MapKey("Bottom"), part2 ); + session.persist( prod ); + t.commit(); + session.close(); + + prod.getParts().remove( mapKey ); + + session = openSession(); + t = session.beginTransaction(); + session.merge(prod); + t.commit(); + session.close(); + + session = openSession(); + t = session.beginTransaction(); + assertNull( session.get(Part.class, "Widge") ); + assertNotNull( session.get(Part.class, "Get") ); + session.delete( session.get(Product.class, "Widget") ); + t.commit(); + session.close(); + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/MapKey.java b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/MapKey.java new file mode 100644 index 0000000000..6830b50224 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/MapKey.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved. + * + * 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, v. 2.1. This program is distributed in the + * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this + * distribution; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Red Hat Author(s): Steve Ebersole + */ +package org.hibernate.test.collection.backref.map.compkey; + +import java.io.Serializable; + +/** + * A composite map key. + * + * @author Steve Ebersole + */ +public class MapKey implements Serializable { + private String role; + + public MapKey() { + } + + public MapKey(String role) { + this.role = role; + } + + public String getRole() { + return role; + } + + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + MapKey mapKey = ( MapKey ) o; + + if ( !role.equals( mapKey.role ) ) { + return false; + } + + return true; + } + + public int hashCode() { + return role.hashCode(); + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Mappings.hbm.xml b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Mappings.hbm.xml new file mode 100644 index 0000000000..af778c6054 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Mappings.hbm.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Part.java b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Part.java new file mode 100644 index 0000000000..79e3e839b5 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Part.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved. + * + * 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, v. 2.1. This program is distributed in the + * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this + * distribution; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Red Hat Author(s): Steve Ebersole + */ +package org.hibernate.test.collection.backref.map.compkey; + +import java.io.Serializable; + +/** + * Part implementation + * + * @author Steve Ebersole + */ +public class Part implements Serializable { + private String name; + private String description; + + public Part() { + } + + public Part(String name) { + this.name = name; + } + + public Part(String name, String description) { + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Product.java b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Product.java new file mode 100644 index 0000000000..a4d9d8060b --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/collection/backref/map/compkey/Product.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved. + * + * 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, v. 2.1. This program is distributed in the + * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this + * distribution; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Red Hat Author(s): Steve Ebersole + */ +package org.hibernate.test.collection.backref.map.compkey; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * Product implementation + * + * @author Steve Ebersole + */ +public class Product implements Serializable { + private String name; + private Map parts = new HashMap(); + + public Product() { + } + + public Product(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Map getParts() { + return parts; + } + + public void setParts(Map parts) { + this.parts = parts; + } +}