From: <hib...@li...> - 2006-03-14 23:47:44
|
Author: ste...@jb... Date: 2006-03-14 18:47:37 -0500 (Tue, 14 Mar 2006) New Revision: 9617 Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/CompositeIdTest.java branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/PropertyRefTest.java branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java Modified: branches/Branch_3_1/Hibernate3/src/org/hibernate/tuple/PojoComponentTuplizer.java Log: HHH-535 : embedded components (<composite-id/> and <properties/>) defined on non-concrete entities Modified: branches/Branch_3_1/Hibernate3/src/org/hibernate/tuple/PojoComponentTuplizer.java =================================================================== --- branches/Branch_3_1/Hibernate3/src/org/hibernate/tuple/PojoComponentTuplizer.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/src/org/hibernate/tuple/PojoComponentTuplizer.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -2,12 +2,22 @@ package org.hibernate.tuple; import java.lang.reflect.Method; +import java.io.Serializable; +import java.util.HashMap; import net.sf.cglib.beans.BulkBean; import net.sf.cglib.reflect.FastClass; +import net.sf.cglib.proxy.Factory; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.CallbackFilter; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.NoOp; +import net.sf.cglib.proxy.MethodProxy; +import net.sf.cglib.proxy.Callback; import org.hibernate.HibernateException; import org.hibernate.PropertyAccessException; +import org.hibernate.AssertionFailure; import org.hibernate.cfg.Environment; import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.mapping.Component; @@ -133,7 +143,12 @@ } protected Instantiator buildInstantiator(Component component) { - return new PojoInstantiator( component, fastClass ); + if ( component.isEmbedded() && ReflectHelper.isAbstractClass( component.getComponentClass() ) ) { + return new ProxiedInstantiator( component ); + } + else { + return new PojoInstantiator( component, fastClass ); + } } protected Getter buildGetter(Component component, Property prop) { @@ -144,4 +159,119 @@ return prop.getSetter( component.getComponentClass() ); } + private static class ProxiedInstantiator implements Instantiator { + private final Class proxiedClass; + private final Class proxyClass; + private final Factory factory; + + public ProxiedInstantiator(Component component) { + proxiedClass = component.getComponentClass(); + proxyClass = buildProxyClass(); + factory = buildFactory(); + } + + public Object instantiate(Serializable id) { + throw new AssertionFailure( "ProxiedInstantiator can only be used to instantiate component" ); + } + + public Object instantiate() { + try { + return factory.newInstance( + new Callback[] { new PassThroughInterceptor( proxyClass.getName() ), NoOp.INSTANCE } + ); + } + catch ( Throwable t ) { + throw new HibernateException( "Unable to instantiate proxy instance" ); + } + } + + public boolean isInstance(Object object) { + return proxiedClass.isInstance( object ); + } + + private Class buildProxyClass() { + Enhancer en = new Enhancer(); + en.setUseCache( false ); + en.setInterceptDuringConstruction( false ); + en.setUseFactory( true ); + en.setCallbackTypes( CALLBACK_TYPES ); + en.setCallbackFilter( FINALIZE_FILTER ); + if ( proxiedClass.isInterface() ) { + en.setInterfaces( new Class[] { proxiedClass } ); + } + else { + en.setSuperclass( proxiedClass ); + } + return en.createClass(); + + } + private Factory buildFactory() { + try { + return ( Factory ) proxyClass.newInstance(); + } + catch ( Throwable t ) { + throw new HibernateException( "Unable to build CGLIB Factory instance" ); + } + } + } + + private static final CallbackFilter FINALIZE_FILTER = new CallbackFilter() { + public int accept(Method method) { + if ( method.getParameterTypes().length == 0 && method.getName().equals("finalize") ){ + return 1; + } + else { + return 0; + } + } + }; + + private static final Class[] CALLBACK_TYPES = new Class[] { MethodInterceptor.class, NoOp.class }; + + private static class PassThroughInterceptor implements MethodInterceptor { + private HashMap data = new HashMap(); + private final String proxiedClassName; + + public PassThroughInterceptor(String proxiedClassName) { + this.proxiedClassName = proxiedClassName; + } + + public Object intercept( + Object obj, + Method method, + Object[] args, + MethodProxy proxy) throws Throwable { + String name = method.getName(); + if ( "toString".equals( name ) ) { + return proxiedClassName + "@" + System.identityHashCode( obj ); + } + else if ( "equals".equals( name ) ) { + return args[0] instanceof Factory && ( ( Factory ) args[0] ).getCallback( 0 ) == this + ? Boolean.TRUE + : Boolean.FALSE; + } + else if ( "hashCode".equals( name ) ) { + return new Integer( System.identityHashCode( obj ) ); + } + boolean hasGetterSignature = method.getParameterTypes().length == 0 && method.getReturnType() != null; + boolean hasSetterSignature = method.getParameterTypes().length == 1 && ( method.getReturnType() == null || method.getReturnType() == void.class ); + if ( name.startsWith( "get" ) && hasGetterSignature ) { + String propName = name.substring( 3 ); + return data.get( propName ); + } + else if ( name.startsWith( "is" ) && hasGetterSignature ) { + String propName = name.substring( 2 ); + return data.get( propName ); + } + else if ( name.startsWith( "set" ) && hasSetterSignature) { + String propName = name.substring( 3 ); + data.put( propName, args[0] ); + return null; + } + else { + // todo : what else to do here? + return null; + } + } + } } Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/CompositeIdTest.java =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/CompositeIdTest.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/CompositeIdTest.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,37 @@ +package org.hibernate.test.abstractembeddedcomponents.cid; + +import org.hibernate.test.TestCase; +import org.hibernate.Session; +import org.hibernate.Transaction; + +/** + * @author Steve Ebersole + */ +public class CompositeIdTest extends TestCase { + public CompositeIdTest(String x) { + super( x ); + } + + protected String[] getMappings() { + return new String[] { "abstractembeddedcomponents/cid/Mappings.hbm.xml" }; + } + + public void testEmbeddedCompositeIdentifierOnAbstractClass() { + MyInterfaceImpl myInterface = new MyInterfaceImpl(); + myInterface.setKey1( "key1" ); + myInterface.setKey2( "key2" ); + myInterface.setName( "test" ); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.save( myInterface ); + s.flush(); + + s.createQuery( "from MyInterface" ).list(); + + s.delete( myInterface ); + t.commit(); + s.close(); + + } +} Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/Mappings.hbm.xml 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD 3.0//EN" + "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> + +<hibernate-mapping package="org.hibernate.test.abstractembeddedcomponents.cid"> + + <class name="MyInterface" table="MY_INTF" proxy="MyInterface"> + <composite-id> + <key-property name="key1" type="string"/> + <key-property name="key2" type="string"/> + </composite-id> + <discriminator column="TYPE" type="string" length="10"/> + <property name="name" type="string"/> + </class> + + <subclass name="MyInterfaceImpl" extends="MyInterface" discriminator-value="1" proxy="MyInterface"> + </subclass> + +</hibernate-mapping> Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterface.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,20 @@ +package org.hibernate.test.abstractembeddedcomponents.cid; + +import java.io.Serializable; + +/** + * @author Steve Ebersole + */ +public interface MyInterface extends Serializable { + String getKey1(); + + void setKey1(String key1); + + String getKey2(); + + void setKey2(String key2); + + String getName(); + + void setName(String name); +} Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/cid/MyInterfaceImpl.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,34 @@ +package org.hibernate.test.abstractembeddedcomponents.cid; + +/** + * @author Steve Ebersole + */ +public class MyInterfaceImpl implements MyInterface { + private String key1; + private String key2; + private String name; + + public String getKey1() { + return key1; + } + + public void setKey1(String key1) { + this.key1 = key1; + } + + public String getKey2() { + return key2; + } + + public void setKey2(String key2) { + this.key2 = key2; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Address.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,13 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +/** + * @author Steve Ebersole + */ +public interface Address { + public Long getId(); + public void setId(Long id); + public String getAddressType(); + public void setAddressType(String addressType); + public Server getServer(); + public void setServer(Server server); +} Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/AddressImpl.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,34 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +/** + * @author Steve Ebersole + */ +public class AddressImpl implements Address { + private Long id; + private String addressType; + private Server server; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAddressType() { + return addressType; + } + + public void setAddressType(String addressType) { + this.addressType = addressType; + } + + public Server getServer() { + return server; + } + + public void setServer(Server server) { + this.server = server; + } +} Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Mappings.hbm.xml 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,43 @@ +<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD 3.0//EN" + "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> + +<hibernate-mapping package="org.hibernate.test.abstractembeddedcomponents.propertyref"> + + <class name="Address" table="ADDRESS" proxy="Address"> + <id name="id" type="long" column="ADDRESS_ID"> + <generator class="native"/> + </id> + <discriminator column="ADDRESS_TYPE" type="string" length="30"/> + <properties name="uniqueAddress"> + <property name="addressType" column="ADDRESS_TYPE" type="string" insert="false" update="false" length="30"/> + <many-to-one name="server" column="SERVER_ID" class="Server" not-null="true"/> + </properties> + </class> + + <subclass name="AddressImpl" extends="Address" discriminator-value="2" proxy="Address"> + </subclass> + + <class name="Server" table="SERVER" proxy="Server"> + <id name="id" type="long" column="SERVER_ID"> + <generator class="native"/> + </id> + <discriminator column="SERVER_TYPE" type="string" length="10"/> + <property name="serverType" type="string" column="SERVER_TYPE" length="10" update="false" insert="false"/> + </class> + + <subclass name="ServerImpl" extends="Server" discriminator-value="1" proxy="Server"> + <many-to-one name="address" + class="AddressImpl" + property-ref="uniqueAddress" + cascade="all" + unique="true" + update="false" + insert="false"> + <column name="ADDRESS_TYPE"/> + <column name="SERVER_ID"/> + </many-to-one> + </subclass> + +</hibernate-mapping> Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/PropertyRefTest.java =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/PropertyRefTest.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/PropertyRefTest.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,47 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +import org.hibernate.test.TestCase; +import org.hibernate.Session; +import org.hibernate.Transaction; + +/** + * Test of property-refs pointing to abstract embedded components; i.e. + * a mapping properties element (which is internally handled as an embedded + * component) defined on an abstract class or interface which is a target of + * a property-ref mapping. + * + * @author Steve Ebersole + */ +public class PropertyRefTest extends TestCase { + public PropertyRefTest(String x) { + super( x ); + } + + protected String[] getMappings() { + return new String[] { "abstractembeddedcomponents/propertyref/Mappings.hbm.xml" }; + } + + public void testPropertiesRefCascades() { + Session session = openSession(); + Transaction trans = session.beginTransaction(); + ServerImpl server = new ServerImpl(); + session.save( server ); + AddressImpl address = new AddressImpl(); + server.setAddress( address ); + address.setServer( server ); + session.flush(); + session.createQuery( "from Server s join fetch s.address" ).list(); + trans.commit(); + session.close(); + + assertNotNull( server.getId() ); + assertNotNull( address.getId() ); + + session = openSession(); + trans = session.beginTransaction(); + session.delete( address ); + session.delete( server ); + trans.commit(); + session.close(); + } +} Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/Server.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,13 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +/** + * @author Steve Ebersole + */ +public interface Server { + public Long getId(); + public void setId(Long id); + public String getServerType(); + public void setServerType(String serverType); + public Address getAddress(); + public void setAddress(Address address); +} Added: branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java =================================================================== --- branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java 2006-03-14 22:10:43 UTC (rev 9616) +++ branches/Branch_3_1/Hibernate3/test/org/hibernate/test/abstractembeddedcomponents/propertyref/ServerImpl.java 2006-03-14 23:47:37 UTC (rev 9617) @@ -0,0 +1,34 @@ +package org.hibernate.test.abstractembeddedcomponents.propertyref; + +/** + * @author Steve Ebersole + */ +public class ServerImpl implements Server { + private Long id; + private String serverType; + private Address address; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getServerType() { + return serverType; + } + + public void setServerType(String serverType) { + this.serverType = serverType; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } +} |