diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java b/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java index d3fa342450..a4fa8138e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/SettingsFactory.java @@ -47,6 +47,7 @@ import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.classloading.spi.ClassLoaderService; import org.hibernate.service.jta.platform.spi.JtaPlatform; +import org.hibernate.tuple.entity.EntityTuplizerFactory; /** * Reads configuration properties and builds a {@link Settings} instance. @@ -280,6 +281,9 @@ public class SettingsFactory implements Serializable { LOG.debugf( "multi-tenancy strategy : %s", multiTenancyStrategy ); settings.setMultiTenancyStrategy( multiTenancyStrategy ); + // TODO: Does EntityTuplizerFactory really need to be configurable? revisit for HHH-6383 + settings.setEntityTuplizerFactory( new EntityTuplizerFactory() ); + // String provider = properties.getProperty( Environment.BYTECODE_PROVIDER ); // log.info( "Bytecode provider name : " + provider ); // BytecodeProvider bytecodeProvider = buildBytecodeProvider( provider ); diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java b/hibernate-core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java index e38e37febd..74074e62e3 100755 --- a/hibernate-core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java @@ -30,6 +30,7 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; import org.hibernate.mapping.PersistentClass; +import org.hibernate.metamodel.binding.EntityBinding; public class DynamicMapInstantiator implements Instantiator { @@ -54,6 +55,19 @@ public class DynamicMapInstantiator implements Instantiator { } } + public DynamicMapInstantiator(EntityBinding mappingInfo) { + this.entityName = mappingInfo.getEntity().getName(); + isInstanceEntityNames.add( entityName ); + // TODO: fix this when can get subclass info from EntityBinding (HHH-6337) + //if ( mappingInfo.hasSubclasses() ) { + // Iterator itr = mappingInfo.getSubclassClosureIterator(); + // while ( itr.hasNext() ) { + // final PersistentClass subclassInfo = ( PersistentClass ) itr.next(); + // isInstanceEntityNames.add( subclassInfo.getEntityName() ); + // } + //} + } + public final Object instantiate(Serializable id) { return instantiate(); } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java b/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java index 2e89248b6f..ee23c08945 100755 --- a/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/PojoInstantiator.java @@ -34,6 +34,7 @@ import org.hibernate.bytecode.spi.ReflectionOptimizer; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.mapping.Component; import org.hibernate.mapping.PersistentClass; +import org.hibernate.metamodel.binding.EntityBinding; import org.jboss.logging.Logger; @@ -82,6 +83,21 @@ public class PojoInstantiator implements Instantiator, Serializable { } } + public PojoInstantiator(EntityBinding entityBinding, ReflectionOptimizer.InstantiationOptimizer optimizer) { + this.mappedClass = entityBinding.getEntity().getJavaType().getClassReference(); + this.proxyInterface = entityBinding.getProxyInterfaceType().getClassReference(); + this.embeddedIdentifier = entityBinding.getEntityIdentifier().isEmbedded(); + this.optimizer = optimizer; + + try { + constructor = ReflectHelper.getDefaultConstructor( mappedClass ); + } + catch ( PropertyNotFoundException pnfe ) { + LOG.noDefaultConstructor(mappedClass.getName()); + constructor = null; + } + } + private void readObject(java.io.ObjectInputStream stream) throws ClassNotFoundException, IOException { stream.defaultReadObject(); diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java index e3de7bd95c..d3f5cf690c 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java @@ -47,6 +47,8 @@ import org.hibernate.id.Assigned; import org.hibernate.mapping.Component; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.metamodel.binding.AttributeBinding; +import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.property.Getter; import org.hibernate.property.Setter; import org.hibernate.proxy.HibernateProxy; @@ -129,6 +131,42 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { */ protected abstract ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idGetter, Setter idSetter); + /** + * Build an appropriate Getter for the given property. + * + * + * @param mappedProperty The property to be accessed via the built Getter. + * @return An appropriate Getter instance. + */ + protected abstract Getter buildPropertyGetter(AttributeBinding mappedProperty); + + /** + * Build an appropriate Setter for the given property. + * + * + * @param mappedProperty The property to be accessed via the built Setter. + * @return An appropriate Setter instance. + */ + protected abstract Setter buildPropertySetter(AttributeBinding mappedProperty); + + /** + * Build an appropriate Instantiator for the given mapped entity. + * + * @param mappingInfo The mapping information regarding the mapped entity. + * @return An appropriate Instantiator instance. + */ + protected abstract Instantiator buildInstantiator(EntityBinding mappingInfo); + + /** + * Build an appropriate ProxyFactory for the given mapped entity. + * + * @param mappingInfo The mapping information regarding the mapped entity. + * @param idGetter The constructed Getter relating to the entity's id property. + * @param idSetter The constructed Setter relating to the entity's id property. + * @return An appropriate ProxyFactory instance. + */ + protected abstract ProxyFactory buildProxyFactory(EntityBinding mappingInfo, Getter idGetter, Setter idSetter); + /** * Constructs a new AbstractEntityTuplizer instance. * @@ -193,6 +231,75 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { } } + /** + * Constructs a new AbstractEntityTuplizer instance. + * + * @param entityMetamodel The "interpreted" information relating to the mapped entity. + * @param mappingInfo The parsed "raw" mapping data relating to the given entity. + */ + public AbstractEntityTuplizer(EntityMetamodel entityMetamodel, EntityBinding mappingInfo) { + this.entityMetamodel = entityMetamodel; + + if ( !entityMetamodel.getIdentifierProperty().isVirtual() ) { + idGetter = buildPropertyGetter( mappingInfo.getEntityIdentifier().getValueBinding() ); + idSetter = buildPropertySetter( mappingInfo.getEntityIdentifier().getValueBinding() ); + } + else { + idGetter = null; + idSetter = null; + } + + propertySpan = entityMetamodel.getPropertySpan(); + + getters = new Getter[ propertySpan ]; + setters = new Setter[ propertySpan ]; + + boolean foundCustomAccessor = false; + int i = 0; + for ( AttributeBinding property : mappingInfo.getAttributeBindingClosure() ) { + if ( property == mappingInfo.getEntityIdentifier().getValueBinding() ) { + continue; // ID binding processed above + } + + //TODO: redesign how PropertyAccessors are acquired... + getters[ i ] = buildPropertyGetter( property ); + setters[ i ] = buildPropertySetter( property ); + if ( ! property.isBasicPropertyAccessor() ) { + foundCustomAccessor = true; + } + i++; + } + hasCustomAccessors = foundCustomAccessor; + + instantiator = buildInstantiator( mappingInfo ); + + if ( entityMetamodel.isLazy() ) { + proxyFactory = buildProxyFactory( mappingInfo, idGetter, idSetter ); + if ( proxyFactory == null ) { + entityMetamodel.setLazy( false ); + } + } + else { + proxyFactory = null; + } + + + // TODO: Fix this when components are working (HHH-6173) + //Component mapper = mappingInfo.getEntityIdentifier().getIdentifierMapper(); + Component mapper = null; + if ( mapper == null ) { + identifierMapperType = null; + mappedIdentifierValueMarshaller = null; + } + else { + identifierMapperType = ( CompositeType ) mapper.getType(); + mappedIdentifierValueMarshaller = buildMappedIdentifierValueMarshaller( + ( ComponentType ) entityMetamodel.getIdentifierProperty().getType(), + ( ComponentType ) identifierMapperType + ); + } + } + /** Retreives the defined entity-name for the tuplized entity. * * @return The entity-name. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java index 286149fd8b..9a53bcbe32 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java @@ -30,6 +30,8 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.metamodel.binding.AttributeBinding; +import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.property.Getter; import org.hibernate.property.PropertyAccessor; import org.hibernate.property.PropertyAccessorFactory; @@ -55,6 +57,10 @@ public class DynamicMapEntityTuplizer extends AbstractEntityTuplizer { super(entityMetamodel, mappedEntity); } + DynamicMapEntityTuplizer(EntityMetamodel entityMetamodel, EntityBinding mappedEntity) { + super(entityMetamodel, mappedEntity); + } + /** * {@inheritDoc} */ @@ -120,6 +126,65 @@ public class DynamicMapEntityTuplizer extends AbstractEntityTuplizer { return pf; } + private PropertyAccessor buildPropertyAccessor(AttributeBinding mappedProperty) { + // TODO: fix when backrefs are working in new metamodel + //if ( mappedProperty.isBackRef() ) { + // return mappedProperty.getPropertyAccessor( null ); + //} + //else { + return PropertyAccessorFactory.getDynamicMapPropertyAccessor(); + //} + } + + /** + * {@inheritDoc} + */ + @Override + protected Getter buildPropertyGetter(AttributeBinding mappedProperty) { + return buildPropertyAccessor( mappedProperty ).getGetter( null, mappedProperty.getAttribute().getName() ); + } + + /** + * {@inheritDoc} + */ + @Override + protected Setter buildPropertySetter(AttributeBinding mappedProperty) { + return buildPropertyAccessor( mappedProperty ).getSetter( null, mappedProperty.getAttribute().getName() ); + } + + /** + * {@inheritDoc} + */ + @Override + protected Instantiator buildInstantiator(EntityBinding mappingInfo) { + return new DynamicMapInstantiator( mappingInfo ); + } + + /** + * {@inheritDoc} + */ + @Override + protected ProxyFactory buildProxyFactory(EntityBinding mappingInfo, Getter idGetter, Setter idSetter) { + + ProxyFactory pf = new MapProxyFactory(); + try { + //TODO: design new lifecycle for ProxyFactory + pf.postInstantiate( + getEntityName(), + null, + null, + null, + null, + null + ); + } + catch ( HibernateException he ) { + LOG.unableToCreateProxyFactory(getEntityName(), he); + pf = null; + } + return pf; + } + /** * {@inheritDoc} */ diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 85ae60e4a1..2c2c61615d 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -567,14 +567,12 @@ public class EntityMetamodel implements Serializable { final EntityTuplizerFactory entityTuplizerFactory = sessionFactory.getSettings().getEntityTuplizerFactory(); Class tuplizerClass = entityBinding.getEntityTuplizerClass(); - // TODO: fix this when integrated into tuplizers (HHH-6359) - //if ( tuplizerClass == null ) { - // entityTuplizer = entityTuplizerFactory.constructDefaultTuplizer( entityMode, this, entityBinding ); - //} - //else { - // entityTuplizer = entityTuplizerFactory.constructTuplizer( tuplizerClass, this, entityBinding ); - //} - entityTuplizer = null; + if ( tuplizerClass == null ) { + entityTuplizer = entityTuplizerFactory.constructDefaultTuplizer( entityMode, this, entityBinding ); + } + else { + entityTuplizer = entityTuplizerFactory.constructTuplizer( tuplizerClass, this, entityBinding ); + } } private ValueInclusion determineInsertValueGenerationType(Property mappingProperty, StandardProperty runtimeProperty) { diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java index 373ebfcc8b..d035eb9712 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java @@ -37,8 +37,9 @@ import org.hibernate.tuple.Tuplizer; * Defines further responsibilities reagarding tuplization based on * a mapped entity. *

- * EntityTuplizer implementations should have the following constructor signature: + * EntityTuplizer implementations should have the following constructor signatures: * (org.hibernate.tuple.entity.EntityMetamodel, org.hibernate.mapping.PersistentClass) + * (org.hibernate.tuple.entity.EntityMetamodel, org.hibernate.metamodel.binding.EntityBinding) * * @author Gavin King * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizerFactory.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizerFactory.java index 21e9733ef9..0cf17f85a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizerFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizerFactory.java @@ -32,6 +32,7 @@ import org.hibernate.EntityMode; import org.hibernate.HibernateException; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.mapping.PersistentClass; +import org.hibernate.metamodel.binding.EntityBinding; /** * A registry allowing users to define the default {@link EntityTuplizer} class to use per {@link EntityMode}. @@ -40,6 +41,7 @@ import org.hibernate.mapping.PersistentClass; */ public class EntityTuplizerFactory implements Serializable { public static final Class[] ENTITY_TUP_CTOR_SIG = new Class[] { EntityMetamodel.class, PersistentClass.class }; + public static final Class[] ENTITY_TUP_CTOR_SIG_NEW = new Class[] { EntityMetamodel.class, EntityBinding.class }; private Map> defaultImplClassByMode = buildBaseMapping(); @@ -52,9 +54,11 @@ public class EntityTuplizerFactory implements Serializable { public void registerDefaultTuplizerClass(EntityMode entityMode, Class tuplizerClass) { assert isEntityTuplizerImplementor( tuplizerClass ) : "Specified tuplizer class [" + tuplizerClass.getName() + "] does not implement " + EntityTuplizer.class.getName(); - assert hasProperConstructor( tuplizerClass ) + // TODO: for now we need constructors for both PersistentClass and EntityBinding + assert hasProperConstructor( tuplizerClass, ENTITY_TUP_CTOR_SIG ) + : "Specified tuplizer class [" + tuplizerClass.getName() + "] is not properly instantiatable"; + assert hasProperConstructor( tuplizerClass, ENTITY_TUP_CTOR_SIG_NEW ) : "Specified tuplizer class [" + tuplizerClass.getName() + "] is not properly instantiatable"; - defaultImplClassByMode.put( entityMode, tuplizerClass ); } @@ -84,6 +88,32 @@ public class EntityTuplizerFactory implements Serializable { } } + /** + * Construct an instance of the given tuplizer class. + * + * @param tuplizerClassName The name of the tuplizer class to instantiate + * @param metamodel The metadata for the entity. + * @param entityBinding The mapping info for the entity. + * + * @return The instantiated tuplizer + * + * @throws HibernateException If class name cannot be resolved to a class reference, or if the + * {@link Constructor#newInstance} call fails. + */ + @SuppressWarnings({ "unchecked" }) + public EntityTuplizer constructTuplizer( + String tuplizerClassName, + EntityMetamodel metamodel, + EntityBinding entityBinding) { + try { + Class tuplizerClass = ReflectHelper.classForName( tuplizerClassName ); + return constructTuplizer( tuplizerClass, metamodel, entityBinding ); + } + catch ( ClassNotFoundException e ) { + throw new HibernateException( "Could not locate specified tuplizer class [" + tuplizerClassName + "]" ); + } + } + /** * Construct an instance of the given tuplizer class. * @@ -99,7 +129,7 @@ public class EntityTuplizerFactory implements Serializable { Class tuplizerClass, EntityMetamodel metamodel, PersistentClass persistentClass) { - Constructor constructor = getProperConstructor( tuplizerClass ); + Constructor constructor = getProperConstructor( tuplizerClass, ENTITY_TUP_CTOR_SIG ); assert constructor != null : "Unable to locate proper constructor for tuplizer [" + tuplizerClass.getName() + "]"; try { return constructor.newInstance( metamodel, persistentClass ); @@ -109,6 +139,31 @@ public class EntityTuplizerFactory implements Serializable { } } + /** + * Construct an instance of the given tuplizer class. + * + * @param tuplizerClass The tuplizer class to instantiate + * @param metamodel The metadata for the entity. + * @param entityBinding The mapping info for the entity. + * + * @return The instantiated tuplizer + * + * @throws HibernateException if the {@link Constructor#newInstance} call fails. + */ + public EntityTuplizer constructTuplizer( + Class tuplizerClass, + EntityMetamodel metamodel, + EntityBinding entityBinding) { + Constructor constructor = getProperConstructor( tuplizerClass, ENTITY_TUP_CTOR_SIG_NEW ); + assert constructor != null : "Unable to locate proper constructor for tuplizer [" + tuplizerClass.getName() + "]"; + try { + return constructor.newInstance( metamodel, entityBinding ); + } + catch ( Throwable t ) { + throw new HibernateException( "Unable to instantiate default tuplizer [" + tuplizerClass.getName() + "]", t ); + } + } + /** * Construct am instance of the default tuplizer for the given entity-mode. * @@ -133,19 +188,45 @@ public class EntityTuplizerFactory implements Serializable { return constructTuplizer( tuplizerClass, metamodel, persistentClass ); } + /** + * Construct am instance of the default tuplizer for the given entity-mode. + * + * @param entityMode The entity mode for which to build a default tuplizer. + * @param metamodel The entity metadata. + * @param entityBinding The entity mapping info. + * + * @return The instantiated tuplizer + * + * @throws HibernateException If no default tuplizer found for that entity-mode; may be re-thrown from + * {@link #constructTuplizer} too. + */ + public EntityTuplizer constructDefaultTuplizer( + EntityMode entityMode, + EntityMetamodel metamodel, + EntityBinding entityBinding) { + Class tuplizerClass = defaultImplClassByMode.get( entityMode ); + if ( tuplizerClass == null ) { + throw new HibernateException( "could not determine default tuplizer class to use [" + entityMode + "]" ); + } + + return constructTuplizer( tuplizerClass, metamodel, entityBinding ); + } + private boolean isEntityTuplizerImplementor(Class tuplizerClass) { return ReflectHelper.implementsInterface( tuplizerClass, EntityTuplizer.class ); } - private boolean hasProperConstructor(Class tuplizerClass) { - return getProperConstructor( tuplizerClass ) != null + private boolean hasProperConstructor(Class tuplizerClass, Class[] constructorArgs) { + return getProperConstructor( tuplizerClass, constructorArgs ) != null && ! ReflectHelper.isAbstractClass( tuplizerClass ); } - private Constructor getProperConstructor(Class clazz) { + private Constructor getProperConstructor( + Class clazz, + Class[] constructorArgs) { Constructor constructor = null; try { - constructor = clazz.getDeclaredConstructor( ENTITY_TUP_CTOR_SIG ); + constructor = clazz.getDeclaredConstructor( constructorArgs ); if ( ! ReflectHelper.isPublic( constructor ) ) { try { // found a constructor, but it was not publicly accessible so try to request accessibility diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java index 6244f7213c..626b9ac2ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java @@ -35,6 +35,7 @@ import org.jboss.logging.Logger; import org.hibernate.EntityMode; import org.hibernate.EntityNameResolver; import org.hibernate.HibernateException; +import org.hibernate.PropertyNotFoundException; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.CoreMessageLogger; @@ -48,7 +49,11 @@ import org.hibernate.internal.util.ReflectHelper; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.Subclass; +import org.hibernate.metamodel.binding.AttributeBinding; +import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.property.Getter; +import org.hibernate.property.PropertyAccessor; +import org.hibernate.property.PropertyAccessorFactory; import org.hibernate.property.Setter; import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.ProxyFactory; @@ -108,6 +113,41 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { } + public PojoEntityTuplizer(EntityMetamodel entityMetamodel, EntityBinding mappedEntity) { + super( entityMetamodel, mappedEntity ); + this.mappedClass = mappedEntity.getEntity().getJavaType().getClassReference(); + this.proxyInterface = mappedEntity.getProxyInterfaceType().getClassReference(); + this.lifecycleImplementor = Lifecycle.class.isAssignableFrom( mappedClass ); + + for ( AttributeBinding property : mappedEntity.getAttributeBindingClosure() ) { + if ( property.isLazy() ) { + lazyPropertyNames.add( property.getAttribute().getName() ); + } + } + + String[] getterNames = new String[propertySpan]; + String[] setterNames = new String[propertySpan]; + Class[] propTypes = new Class[propertySpan]; + for ( int i = 0; i < propertySpan; i++ ) { + getterNames[i] = getters[ i ].getMethodName(); + setterNames[i] = setters[ i ].getMethodName(); + propTypes[i] = getters[ i ].getReturnType(); + } + + if ( hasCustomAccessors || ! Environment.useReflectionOptimizer() ) { + optimizer = null; + } + else { + // todo : YUCK!!! + optimizer = Environment.getBytecodeProvider().getReflectionOptimizer( + mappedClass, getterNames, setterNames, propTypes + ); +// optimizer = getFactory().getSettings().getBytecodeProvider().getReflectionOptimizer( +// mappedClass, getterNames, setterNames, propTypes +// ); + } + } + /** * {@inheritDoc} */ @@ -212,6 +252,112 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { } } + /** + * {@inheritDoc} + */ + @Override + protected ProxyFactory buildProxyFactory(EntityBinding entityBinding, Getter idGetter, Setter idSetter) { + // determine the id getter and setter methods from the proxy interface (if any) + // determine all interfaces needed by the resulting proxy + HashSet proxyInterfaces = new HashSet(); + proxyInterfaces.add( HibernateProxy.class ); + + Class mappedClass = entityBinding.getEntity().getJavaType().getClassReference(); + Class proxyInterface = entityBinding.getProxyInterfaceType().getClassReference(); + + if ( proxyInterface!=null && !mappedClass.equals( proxyInterface ) ) { + if ( ! proxyInterface.isInterface() ) { + throw new MappingException( + "proxy must be either an interface, or the class itself: " + getEntityName() + ); + } + proxyInterfaces.add( proxyInterface ); + } + + if ( mappedClass.isInterface() ) { + proxyInterfaces.add( mappedClass ); + } + + // TODO: fix when it's possible to get subclasses from an EntityBinding + //Iterator subclasses = entityBinding.getSubclassIterator(); + //while ( subclasses.hasNext() ) { + // final Subclass subclass = ( Subclass ) subclasses.next(); + // final Class subclassProxy = subclass.getProxyInterface(); + // final Class subclassClass = subclass.getMappedClass(); + // if ( subclassProxy!=null && !subclassClass.equals( subclassProxy ) ) { + // if ( !subclassProxy.isInterface() ) { + // throw new MappingException( + // "proxy must be either an interface, or the class itself: " + subclass.getEntityName() + // ); + // } + // proxyInterfaces.add( subclassProxy ); + // } + //} + + for ( AttributeBinding property : entityBinding.getAttributeBindings() ) { + Method method = getGetter( property ).getMethod(); + if ( method != null && Modifier.isFinal( method.getModifiers() ) ) { + LOG.gettersOfLazyClassesCannotBeFinal(entityBinding.getEntity().getName(), property.getAttribute().getName()); + } + method = getSetter( property ).getMethod(); + if ( method != null && Modifier.isFinal( method.getModifiers() ) ) { + LOG.settersOfLazyClassesCannotBeFinal(entityBinding.getEntity().getName(), property.getAttribute().getName()); + } + } + + Method idGetterMethod = idGetter==null ? null : idGetter.getMethod(); + Method idSetterMethod = idSetter==null ? null : idSetter.getMethod(); + + Method proxyGetIdentifierMethod = idGetterMethod==null || proxyInterface==null ? + null : + ReflectHelper.getMethod(proxyInterface, idGetterMethod); + Method proxySetIdentifierMethod = idSetterMethod==null || proxyInterface==null ? + null : + ReflectHelper.getMethod(proxyInterface, idSetterMethod); + + ProxyFactory pf = buildProxyFactoryInternal( entityBinding, idGetter, idSetter ); + try { + pf.postInstantiate( + getEntityName(), + mappedClass, + proxyInterfaces, + proxyGetIdentifierMethod, + proxySetIdentifierMethod, + entityBinding.getEntityIdentifier().isEmbedded() ? + ( CompositeType ) entityBinding + .getEntityIdentifier() + .getValueBinding() + .getHibernateTypeDescriptor() + .getExplicitType() : + null + ); + } + catch ( HibernateException he ) { + LOG.unableToCreateProxyFactory(getEntityName(), he); + pf = null; + } + return pf; + } + + protected ProxyFactory buildProxyFactoryInternal(EntityBinding entityBinding, Getter idGetter, Setter idSetter) { + // TODO : YUCK!!! fix after HHH-1907 is complete + return Environment.getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory(); +// return getFactory().getSettings().getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory(); + } + + /** + * {@inheritDoc} + */ + @Override + protected Instantiator buildInstantiator(EntityBinding entityBinding) { + if ( optimizer == null ) { + return new PojoInstantiator( entityBinding, null ); + } + else { + return new PojoInstantiator( entityBinding, optimizer.getInstantiationOptimizer() ); + } + } + /** * {@inheritDoc} */ @@ -297,6 +443,44 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { return mappedProperty.getSetter( mappedEntity.getMappedClass() ); } + /** + * {@inheritDoc} + */ + @Override + protected Getter buildPropertyGetter(AttributeBinding mappedProperty) { + return getGetter( mappedProperty ); + } + + /** + * {@inheritDoc} + */ + @Override + protected Setter buildPropertySetter(AttributeBinding mappedProperty) { + return getSetter( mappedProperty ); + } + + private Getter getGetter(AttributeBinding mappedProperty) throws PropertyNotFoundException, MappingException { + return getPropertyAccessor( mappedProperty ).getGetter( + mappedProperty.getEntityBinding().getEntity().getJavaType().getClassReference(), + mappedProperty.getAttribute().getName() + ); + } + + private Setter getSetter(AttributeBinding mappedProperty) throws PropertyNotFoundException, MappingException { + return getPropertyAccessor( mappedProperty ).getSetter( + mappedProperty.getEntityBinding().getEntity().getJavaType().getClassReference(), + mappedProperty.getAttribute().getName() + ); + } + + private PropertyAccessor getPropertyAccessor(AttributeBinding mappedProperty) throws MappingException { + // TODO: Fix this then backrefs are working in new metamodel + return PropertyAccessorFactory.getPropertyAccessor( + mappedProperty.getEntityBinding().getEntity().getJavaType().getClassReference(), + mappedProperty.getPropertyAccessorName() + ); + } + /** * {@inheritDoc} */ diff --git a/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java b/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java index f47d0e33db..433919cfdd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java @@ -26,6 +26,7 @@ package org.hibernate.test.dynamicentity.tuplizer2; import org.hibernate.EntityNameResolver; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.mapping.PersistentClass; +import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.property.Getter; import org.hibernate.property.Setter; import org.hibernate.proxy.ProxyFactory; @@ -44,6 +45,10 @@ public class MyEntityTuplizer extends PojoEntityTuplizer { super( entityMetamodel, mappedEntity ); } + public MyEntityTuplizer(EntityMetamodel entityMetamodel, EntityBinding mappedEntity) { + super( entityMetamodel, mappedEntity ); + } + public EntityNameResolver[] getEntityNameResolvers() { return new EntityNameResolver[] { MyEntityNameResolver.INSTANCE }; }