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
This commit is contained in:
parent
e239d5a319
commit
e5f6d52012
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ 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
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<!--
|
||||
Demonstrates a unidirectional map mapping where the map key is a
|
||||
composite. The unidirectional collection forces Hibernate to use
|
||||
a backref. We want to make sure the backref works properly with
|
||||
the component.
|
||||
-->
|
||||
<hibernate-mapping package="org.hibernate.test.collection.backref.map.compkey" default-access="field">
|
||||
|
||||
<class name="Product" table="t_product">
|
||||
<id name="name"/>
|
||||
<map name="parts" table="Parts" cascade="all,delete-orphan" fetch="join">
|
||||
<key column="productName" not-null="true"/>
|
||||
<composite-map-key class="MapKey">
|
||||
<key-property name="role"/>
|
||||
</composite-map-key>
|
||||
<one-to-many class="Part"/>
|
||||
</map>
|
||||
</class>
|
||||
|
||||
<class name="Part" table="t_part">
|
||||
<id name="name"/>
|
||||
<property name="description" not-null="true"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue