[hibernate-commits] Hibernate SVN: r15259 - in core/branches/Branch_3_3: core/src/main/java/org/hibernate/impl and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Oct 7 11:56:16 EDT 2008


Author: steve.ebersole at jboss.com
Date: 2008-10-07 11:56:16 -0400 (Tue, 07 Oct 2008)
New Revision: 15259

Added:
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/EntityNameResolver.java
   core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/
   core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/Customer.hbm.xml
   core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/ImprovedTuplizerDynamicEntityTest.java
   core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityInstantiator.java
   core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java
Modified:
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/impl/SessionImpl.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/Dom4jEntityTuplizer.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java
Log:
HHH-3515 : EntityNameResolver

Added: core/branches/Branch_3_3/core/src/main/java/org/hibernate/EntityNameResolver.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/EntityNameResolver.java	                        (rev 0)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/EntityNameResolver.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -0,0 +1,42 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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;
+
+/**
+ * Contract for resolving an entity-name from a given entity instance.
+ *
+ * @author Steve Ebersole
+ */
+public interface EntityNameResolver {
+	/**
+	 * Given an entity instance, determine its entity-name.
+	 *
+	 * @param entity The entity instance.
+	 *
+	 * @return The corresponding entity-name, or null if this impl does not know how to perform resolution
+	 *         for the given entity instance.
+	 */
+	public String resolveEntityName(Object entity);
+}

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -39,6 +39,7 @@
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.LinkedHashSet;
 import javax.naming.NamingException;
 import javax.naming.Reference;
 import javax.naming.StringRefAddr;
@@ -58,6 +59,9 @@
 import org.hibernate.SessionFactory;
 import org.hibernate.StatelessSession;
 import org.hibernate.SessionFactoryObserver;
+import org.hibernate.EntityNameResolver;
+import org.hibernate.EntityNameResolver;
+import org.hibernate.tuple.entity.EntityTuplizer;
 import org.hibernate.cache.CacheKey;
 import org.hibernate.cache.CollectionRegion;
 import org.hibernate.cache.EntityRegion;
@@ -113,6 +117,7 @@
 import org.hibernate.type.Type;
 import org.hibernate.util.CollectionHelper;
 import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.EmptyIterator;
 
 
 /**
@@ -172,6 +177,7 @@
 	private final transient EntityNotFoundDelegate entityNotFoundDelegate;
 	private final transient SQLFunctionRegistry sqlFunctionRegistry;
 	private final transient SessionFactoryObserver observer;
+	private final transient HashMap entityNameResolvers = new HashMap();
 
 	private final QueryPlanCache queryPlanCache = new QueryPlanCache( this );
 
@@ -319,11 +325,15 @@
 		// after *all* persisters and named queries are registered
 		Iterator iter = entityPersisters.values().iterator();
 		while ( iter.hasNext() ) {
-			( (EntityPersister) iter.next() ).postInstantiate();
+			final EntityPersister persister = ( ( EntityPersister ) iter.next() );
+			persister.postInstantiate();
+			registerEntityNameResolvers( persister );
+
 		}
 		iter = collectionPersisters.values().iterator();
 		while ( iter.hasNext() ) {
-			( (CollectionPersister) iter.next() ).postInstantiate();
+			final CollectionPersister persister = ( ( CollectionPersister ) iter.next() );
+			persister.postInstantiate();
 		}
 
 		//JNDI + Serialization:
@@ -415,6 +425,41 @@
 		this.observer.sessionFactoryCreated( this );
 	}
 
+	private void registerEntityNameResolvers(EntityPersister persister) {
+		Iterator itr = persister.getEntityMetamodel().getTuplizerMapping().iterateTuplizers();
+		while ( itr.hasNext() ) {
+			final EntityTuplizer tuplizer = ( EntityTuplizer ) itr.next();
+			registerEntityNameResolvers( tuplizer );
+		}
+	}
+
+	private void registerEntityNameResolvers(EntityTuplizer tuplizer) {
+		EntityNameResolver[] resolvers = tuplizer.getEntityNameResolvers();
+		if ( resolvers == null ) {
+			return;
+		}
+
+		for ( int i = 0; i < resolvers.length; i++ ) {
+			registerEntityNameResolver( resolvers[i], tuplizer.getEntityMode() );
+		}
+	}
+
+	public void registerEntityNameResolver(EntityNameResolver resolver, EntityMode entityMode) {
+		LinkedHashSet resolversForMode = ( LinkedHashSet ) entityNameResolvers.get( entityMode );
+		if ( resolversForMode == null ) {
+			resolversForMode = new LinkedHashSet();
+			entityNameResolvers.put( entityMode, resolversForMode );
+		}
+		resolversForMode.add( resolver );
+	}
+
+	public Iterator iterateEntityNameResolvers(EntityMode entityMode) {
+		Set actualEntityNameResolvers = ( Set ) entityNameResolvers.get( entityMode );
+		return actualEntityNameResolvers == null
+				? EmptyIterator.INSTANCE
+				: actualEntityNameResolvers.iterator();
+	}
+
 	public QueryPlanCache getQueryPlanCache() {
 		return queryPlanCache;
 	}

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/impl/SessionImpl.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/impl/SessionImpl.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/impl/SessionImpl.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -66,6 +66,7 @@
 import org.hibernate.Transaction;
 import org.hibernate.TransientObjectException;
 import org.hibernate.UnresolvableObjectException;
+import org.hibernate.EntityNameResolver;
 import org.hibernate.collection.PersistentCollection;
 import org.hibernate.engine.ActionQueue;
 import org.hibernate.engine.CollectionEntry;
@@ -139,7 +140,7 @@
  *
  * @author Gavin King
  */
-public final class SessionImpl extends AbstractSessionImpl 
+public final class SessionImpl extends AbstractSessionImpl
 		implements EventSource, org.hibernate.classic.Session, JDBCContext.Context {
 
 	// todo : need to find a clean way to handle the "event source" role
@@ -175,6 +176,30 @@
 	private transient Session rootSession;
 	private transient Map childSessionsByEntityMode;
 
+	private EntityNameResolver entityNameResolver = new EntityNameResolver() {
+		public String resolveEntityName(Object entity) {
+			String entityName = interceptor.getEntityName( entity );
+			if ( entityName != null ) {
+				return entityName;
+			}
+
+			Iterator itr = factory.iterateEntityNameResolvers( entityMode );
+			while ( itr.hasNext() ) {
+				final EntityNameResolver resolver = ( EntityNameResolver ) itr.next();
+				entityName = resolver.resolveEntityName( entity );
+				if ( entityName != null ) {
+					break;
+				}
+			}
+			if ( entityName != null ) {
+				return entityName;
+			}
+
+			// the old-time stand-by...
+			return entity.getClass().getName();
+		}
+	};
+
 	/**
 	 * Constructor used in building "child sessions".
 	 *
@@ -1789,23 +1814,7 @@
 
 	public String guessEntityName(Object object) throws HibernateException {
 		errorIfClosed();
-		String entity = interceptor.getEntityName( object );
-		if ( entity == null ) {
-			if ( object instanceof Map ) {
-				entity = (String) ( (Map) object ).get( DynamicMapInstantiator.KEY );
-				if ( entity == null ) {
-					throw new HibernateException( "could not determine type of dynamic entity" );
-				}
-			}
-			else if ( object instanceof Element ) {
-				// TODO : really need to keep a map of nodeName -> entityName, but that would mean nodeName being distinct
-				entity = ( (Element) object ).getName();
-			}
-			else {
-				entity = object.getClass().getName();
-			}
-		}
-		return entity;
+		return entityNameResolver.resolveEntityName( object );
 	}
 
 	public void cancelQuery() throws HibernateException {

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -133,7 +133,6 @@
 	private final boolean isLazyPropertiesCacheable;
 	private final CacheEntryStructure cacheEntryStructure;
 	private final EntityMetamodel entityMetamodel;
-	private final Map entityNameBySubclass = new HashMap();
 	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 	private final String[] rootTableKeyColumnNames;
@@ -455,15 +454,6 @@
 				(CacheEntryStructure) new UnstructuredCacheEntry();
 
 		this.entityMetamodel = new EntityMetamodel( persistentClass, factory );
-
-		if ( persistentClass.hasPojoRepresentation() ) {
-			//TODO: this is currently specific to pojos, but need to be available for all entity-modes
-			Iterator iter = persistentClass.getSubclassIterator();
-			while ( iter.hasNext() ) {
-				PersistentClass pc = ( PersistentClass ) iter.next();
-				entityNameBySubclass.put( pc.getMappedClass(), pc.getEntityName() );
-			}
-		}
 		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 		int batch = persistentClass.getBatchSize();
@@ -3254,10 +3244,6 @@
 		return entityMetamodel.getEntityType();
 	}
 
-	private String getSubclassEntityName(Class clazz) {
-		return ( String ) entityNameBySubclass.get( clazz );
-	}
-
 	public boolean isPolymorphic() {
 		return entityMetamodel.isPolymorphic();
 	}
@@ -3646,29 +3632,17 @@
 		getTuplizer( entityMode ).resetIdentifier( entity, currentId, currentVersion );
 	}
 
-	public EntityPersister getSubclassEntityPersister(Object instance, SessionFactoryImplementor factory, EntityMode entityMode) {
+	public EntityPersister getSubclassEntityPersister(
+			Object instance,
+			SessionFactoryImplementor factory,
+			EntityMode entityMode) {
 		if ( !hasSubclasses() ) {
 			return this;
 		}
 		else {
-			// TODO : really need a way to do something like :
-			//      getTuplizer(entityMode).determineConcreteSubclassEntityName(instance)
-			Class clazz = instance.getClass();
-			if ( clazz == getMappedClass( entityMode ) ) {
-				return this;
-			}
-			else {
-				String subclassEntityName = getSubclassEntityName( clazz );
-				if ( subclassEntityName == null ) {
-					throw new HibernateException(
-							"instance not of expected entity type: " + clazz.getName() +
-							" is not a: " + getEntityName()
-						);
-				}
-				else {
-					return factory.getEntityPersister( subclassEntityName );
-				}
-			}
+			final String concreteEntityName = getTuplizer( entityMode )
+					.determineConcreteSubclassEntityName( instance, factory );
+			return factory.getEntityPersister( concreteEntityName );
 		}
 	}
 

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/persister/entity/EntityPersister.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -668,15 +668,35 @@
 	public boolean hasUninitializedLazyProperties(Object object, EntityMode entityMode);
 
 	/**
-	 * Set the identifier and version of the given instance back
-	 * to its "unsaved" value, returning the id
-	 * @param currentId TODO
-	 * @param currentVersion TODO
+	 * Set the identifier and version of the given instance back to its "unsaved" value.
+	 *
+	 * @param entity The entity instance
+	 * @param currentId The currently assigned identifier value.
+	 * @param currentVersion The currently assigned version value.
+	 * @param entityMode The entity mode represented by the entity instance.
 	 */
 	public void resetIdentifier(Object entity, Serializable currentId, Object currentVersion, EntityMode entityMode);
 
 	/**
-	 * Get the persister for an instance of this class or a subclass
+	 * A request has already identified the entity-name of this persister as the mapping for the given instance.
+	 * However, we still need to account for possible subclassing and potentially re-route to the more appropriate
+	 * persister.
+	 * <p/>
+	 * For example, a request names <tt>Animal</tt> as the entity-name which gets resolved to this persister.  But the
+	 * actual instance is really an instance of <tt>Cat</tt> which is a subclass of <tt>Animal</tt>.  So, here the
+	 * <tt>Animal</tt> persister is being asked to return the persister specific to <tt>Cat</tt>.
+	 * <p/>
+	 * It is also possible that the instance is actually an <tt>Animal</tt> instance in the above example in which
+	 * case we would retrn <tt>this</tt> from this method.
+	 *
+	 * @param instance The entity instance
+	 * @param factory Reference to the SessionFactory
+	 * @param entityMode The entity mode represented by the entity instance.
+	 *
+	 * @return The appropriate persister
+	 *
+	 * @throws HibernateException Indicates that instance was deemed to not be a subclass of the entity mapped by
+	 * this persister.
 	 */
 	public EntityPersister getSubclassEntityPersister(Object instance, SessionFactoryImplementor factory, EntityMode entityMode);
 }

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -74,13 +74,6 @@
 
 
 	/**
-	 * Return the entity-mode handled by this tuplizer instance.
-	 *
-	 * @return The entity-mode
-	 */
-	protected abstract EntityMode getEntityMode();
-
-	/**
 	 * Build an appropriate Getter for the given property.
 	 *
 	 * @param mappedProperty The property to be accessed via the built Getter.
@@ -326,7 +319,6 @@
 	 * @return The property value extracted.
 	 */
 	protected Object getComponentValue(ComponentType type, Object component, String propertyPath) {
-		
 		int loc = propertyPath.indexOf('.');
 		String basePropertyName = loc>0 ?
 			propertyPath.substring(0, loc) : propertyPath;

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/Dom4jEntityTuplizer.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/Dom4jEntityTuplizer.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/Dom4jEntityTuplizer.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -35,6 +35,8 @@
 import org.hibernate.property.Setter;
 import org.hibernate.EntityMode;
 import org.hibernate.HibernateException;
+import org.hibernate.EntityNameResolver;
+import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.tuple.Instantiator;
 import org.hibernate.tuple.Dom4jInstantiator;
 import org.hibernate.type.AbstractComponentType;
@@ -44,8 +46,9 @@
 
 import java.io.Serializable;
 import java.util.HashSet;
-import java.util.Set;
 import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
 
 /**
  * An {@link EntityTuplizer} specific to the dom4j entity mode.
@@ -57,17 +60,21 @@
 
 	static final Logger log = LoggerFactory.getLogger( Dom4jEntityTuplizer.class );
 
-	private Set subclassNodeNames = new HashSet();
+	private Map inheritenceNodeNameMap = new HashMap();
 
 	Dom4jEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
-		super(entityMetamodel, mappedEntity);
+		super( entityMetamodel, mappedEntity );
+		inheritenceNodeNameMap.put( mappedEntity.getNodeName(), mappedEntity.getEntityName() );
 		Iterator itr = mappedEntity.getSubclassClosureIterator();
 		while( itr.hasNext() ) {
 			final PersistentClass mapping = ( PersistentClass ) itr.next();
-			subclassNodeNames.add( mapping.getNodeName() );
+			inheritenceNodeNameMap.put( mapping.getNodeName(), mapping.getEntityName() );
 		}
 	}
 	
+	/**
+	 * {@inheritDoc}
+	 */
 	public EntityMode getEntityMode() {
 		return EntityMode.DOM4J;
 	}
@@ -85,18 +92,30 @@
 		}
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	protected Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity) {
 		return buildPropertyAccessor(mappedProperty).getGetter( null, mappedProperty.getName() );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	protected Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity) {
 		return buildPropertyAccessor(mappedProperty).getSetter( null, mappedProperty.getName() );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	protected Instantiator buildInstantiator(PersistentClass persistentClass) {
 		return new Dom4jInstantiator( persistentClass );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public Serializable getIdentifier(Object entityOrId) throws HibernateException {
 		if (entityOrId instanceof Element) {
 			return super.getIdentifier(entityOrId);
@@ -107,6 +126,9 @@
 		}
 	}
 	
+	/**
+	 * {@inheritDoc}
+	 */
 	protected ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idGetter, Setter idSetter) {
 		HashSet proxyInterfaces = new HashSet();
 		proxyInterfaces.add( HibernateProxy.class );
@@ -132,15 +154,73 @@
 		return pf;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public Class getMappedClass() {
 		return Element.class;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public Class getConcreteProxyClass() {
 		return Element.class;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public boolean isInstrumented() {
 		return false;
 	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public EntityNameResolver[] getEntityNameResolvers() {
+		return new EntityNameResolver[] { new BasicEntityNameResolver( getEntityName(), inheritenceNodeNameMap ) };
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory) {
+		return ( String ) inheritenceNodeNameMap.get( extractNodeName( ( Element ) entityInstance ) );
+	}
+
+	public static String extractNodeName(Element element) {
+		return element.getName();
+	}
+
+	public static class BasicEntityNameResolver implements EntityNameResolver {
+		private final String rootEntityName;
+		private final Map nodeNameToEntityNameMap;
+
+		public BasicEntityNameResolver(String rootEntityName, Map nodeNameToEntityNameMap) {
+			this.rootEntityName = rootEntityName;
+			this.nodeNameToEntityNameMap = nodeNameToEntityNameMap;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public String resolveEntityName(Object entity) {
+		return ( String ) nodeNameToEntityNameMap.get( extractNodeName( ( Element ) entity ) );
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public boolean equals(Object obj) {
+			return rootEntityName.equals( ( ( BasicEntityNameResolver ) obj ).rootEntityName );
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		public int hashCode() {
+			return rootEntityName.hashCode();
+		}
+	}
 }

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/DynamicMapEntityTuplizer.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -28,6 +28,8 @@
 
 import org.hibernate.EntityMode;
 import org.hibernate.HibernateException;
+import org.hibernate.EntityNameResolver;
+import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.tuple.Instantiator;
 import org.hibernate.tuple.DynamicMapInstantiator;
 import org.hibernate.mapping.PersistentClass;
@@ -112,4 +114,37 @@
 	public boolean isInstrumented() {
 		return false;
 	}
+
+	public EntityNameResolver[] getEntityNameResolvers() {
+		return new EntityNameResolver[] { BasicEntityNameResolver.INSTANCE };
+	}
+
+	public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory) {
+		// TODO : do we need an explicit isInstance check here, or is that asserted prior to here?
+		return extractEmbeddedEntityName( ( Map ) entityInstance );
+	}
+
+	public static String extractEmbeddedEntityName(Map entity) {
+		return ( String ) entity.get( DynamicMapInstantiator.KEY );
+	}
+
+	public static class BasicEntityNameResolver implements EntityNameResolver {
+		public static final BasicEntityNameResolver INSTANCE = new BasicEntityNameResolver();
+
+		public String resolveEntityName(Object entity) {
+			final String entityName = extractEmbeddedEntityName( ( Map ) entity );
+			if ( entityName == null ) {
+				throw new HibernateException( "Could not determine type of dynamic map entity" );
+			}
+			return entityName;
+		}
+
+		public boolean equals(Object obj) {
+			return getClass().equals( obj.getClass() );
+		}
+
+		public int hashCode() {
+			return getClass().hashCode();
+		}
+	}
 }

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -122,21 +122,10 @@
 	private final boolean inherited;
 	private final boolean hasSubclasses;
 	private final Set subclassEntityNames = new HashSet();
+	private final Map entityNameByInheritenceClassNameMap = new HashMap();
 
 	private final EntityEntityModeToTuplizerMapping tuplizerMapping;
 
-	public EntityTuplizer getTuplizer(EntityMode entityMode) {
-		return (EntityTuplizer) tuplizerMapping.getTuplizer( entityMode );
-	}
-
-	public EntityTuplizer getTuplizerOrNull(EntityMode entityMode) {
-		return ( EntityTuplizer ) tuplizerMapping.getTuplizerOrNull( entityMode );
-	}
-
-	public EntityMode guessEntityMode(Object object) {
-		return tuplizerMapping.guessEntityMode( object );
-	}
-
 	public EntityMetamodel(PersistentClass persistentClass, SessionFactoryImplementor sessionFactory) {
 		this.sessionFactory = sessionFactory;
 
@@ -322,6 +311,15 @@
 		}
 		subclassEntityNames.add( name );
 
+		if ( persistentClass.hasPojoRepresentation() ) {
+			entityNameByInheritenceClassNameMap.put( persistentClass.getMappedClass(), persistentClass.getEntityName() );
+			iter = persistentClass.getSubclassIterator();
+			while ( iter.hasNext() ) {
+				final PersistentClass pc = ( PersistentClass ) iter.next();
+				entityNameByInheritenceClassNameMap.put( pc.getMappedClass(), pc.getEntityName() );
+			}
+		}
+
 		tuplizerMapping = new EntityEntityModeToTuplizerMapping( persistentClass, this );
 	}
 
@@ -395,6 +393,22 @@
 		}
 	}
 
+	public EntityEntityModeToTuplizerMapping getTuplizerMapping() {
+		return tuplizerMapping;
+	}
+
+	public EntityTuplizer getTuplizer(EntityMode entityMode) {
+		return (EntityTuplizer) tuplizerMapping.getTuplizer( entityMode );
+	}
+
+	public EntityTuplizer getTuplizerOrNull(EntityMode entityMode) {
+		return ( EntityTuplizer ) tuplizerMapping.getTuplizerOrNull( entityMode );
+	}
+
+	public EntityMode guessEntityMode(Object object) {
+		return tuplizerMapping.guessEntityMode( object );
+	}
+
 	public int[] getNaturalIdentifierProperties() {
 		return naturalIdPropertyNumbers;
 	}
@@ -555,6 +569,16 @@
 		return isAbstract;
 	}
 
+	/**
+	 * Return the entity-name mapped to the given class within our inheritence hierarchy, if any.
+	 *
+	 * @param inheritenceClass The class for which to resolve the entity-name.
+	 * @return The mapped entity-name, or null if no such mapping was found.
+	 */
+	public String findEntityNameByEntityClass(Class inheritenceClass) {
+		return ( String ) entityNameByInheritenceClassNameMap.get( inheritenceClass.getName() );
+	}
+
 	public String toString() {
 		return "EntityMetamodel(" + name + ':' + ArrayHelper.toString(properties) + ')';
 	}

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -28,8 +28,11 @@
 import java.util.Map;
 
 import org.hibernate.HibernateException;
+import org.hibernate.EntityNameResolver;
+import org.hibernate.EntityMode;
 import org.hibernate.tuple.Tuplizer;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SessionFactoryImplementor;
 
 /**
  * Defines further responsibilities reagarding tuplization based on
@@ -42,6 +45,12 @@
  * @author Steve Ebersole
  */
 public interface EntityTuplizer extends Tuplizer {
+	/**
+	 * Return the entity-mode handled by this tuplizer instance.
+	 *
+	 * @return The entity-mode
+	 */
+	public EntityMode getEntityMode();
 
     /**
      * Create an entity instance initialized with the given identifier.
@@ -176,11 +185,11 @@
 	 */
 	public boolean isValidatableImplementor();
 
-	// TODO: getConcreteProxyClass() is solely used (externally) to perform narrowProxy()
-	// would be great to fully encapsulate that narrowProxy() functionality within the
-	// Tuplizer, itself, with a Tuplizer.narrowProxy(..., PersistentContext) method
 	/**
 	 * Returns the java class to which generated proxies will be typed.
+	 * <p/>
+	 * todo : look at fully encapsulating {@link org.hibernate.engine.PersistenceContext#narrowProxy} here,
+	 * since that is the only external use of this method
 	 *
 	 * @return The java class to which generated proxies will be typed
 	 */
@@ -198,4 +207,35 @@
 	 * Is it an instrumented POJO?
 	 */
 	public boolean isInstrumented();
+
+	/**
+	 * Get any {@link EntityNameResolver EntityNameResolvers} associated with this {@link Tuplizer}.
+	 *
+	 * @return The associated resolvers.  May be null or empty.
+	 */
+	public EntityNameResolver[] getEntityNameResolvers();
+
+	/**
+	 * Given an entity instance, determine the most appropriate (most targeted) entity-name which represents it.
+	 * This is called in situations where we already know an entity name for the given entityInstance; we are being
+	 * asked to determine if there is a more appropriate entity-name to use, specifically within an inheritence
+	 * hierarchy.
+	 * <p/>
+	 * For example, consider a case where a user calls <tt>session.update( "Animal", cat );</tt>.  Here, the
+	 * user has explicitly provided <tt>Animal</tt> as the entity-name.  However, they have passed in an instance
+	 * of <tt>Cat</tt> which is a subclass of <tt>Animal</tt>.  In this case, we would return <tt>Cat</tt> as the
+	 * entity-name.
+	 * <p/>
+	 * <tt>null</tt> may be returned from calls to this method.  The meaining of <tt>null</tt> in that case is assumed
+	 * to be that we should use whatever explicit entity-name the user provided (<tt>Animal</tt> rather than <tt>Cat</tt>
+	 * in the example above).
+	 *
+	 * @param entityInstance The entity instance.
+	 * @param factory Reference to the SessionFactory.
+	 *
+	 * @return The most appropriate entity name to use.
+	 *
+	 * @throws HibernateException If we are unable to determine an entity-name within the inheritence hierarchy.
+	 */
+	public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory);
 }

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java	2008-10-07 15:54:42 UTC (rev 15258)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -36,6 +36,7 @@
 import org.hibernate.EntityMode;
 import org.hibernate.HibernateException;
 import org.hibernate.MappingException;
+import org.hibernate.EntityNameResolver;
 import org.hibernate.tuple.Instantiator;
 import org.hibernate.tuple.PojoInstantiator;
 import org.hibernate.bytecode.ReflectionOptimizer;
@@ -43,6 +44,7 @@
 import org.hibernate.classic.Lifecycle;
 import org.hibernate.classic.Validatable;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.intercept.FieldInterceptor;
 import org.hibernate.intercept.FieldInterceptionHelper;
 import org.hibernate.mapping.PersistentClass;
@@ -70,7 +72,7 @@
 	private final boolean lifecycleImplementor;
 	private final boolean validatableImplementor;
 	private final Set lazyPropertyNames = new HashSet();
-	private ReflectionOptimizer optimizer;
+	private final ReflectionOptimizer optimizer;
 
 	public PojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
 		super( entityMetamodel, mappedEntity );
@@ -109,6 +111,9 @@
 	
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, 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
@@ -199,11 +204,14 @@
 	}
 
 	protected ProxyFactory buildProxyFactoryInternal(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
-		// TODO : YUCK!!!  finx after HHH-1907 is complete
+		// TODO : YUCK!!!  fix after HHH-1907 is complete
 		return Environment.getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory();
 //		return getFactory().getSettings().getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory();
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	protected Instantiator buildInstantiator(PersistentClass persistentClass) {
 		if ( optimizer == null ) {
 			return new PojoInstantiator( persistentClass, null );
@@ -213,6 +221,9 @@
 		}
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public void setPropertyValues(Object entity, Object[] values) throws HibernateException {
 		if ( !getEntityMetamodel().hasLazyProperties() && optimizer != null && optimizer.getAccessOptimizer() != null ) {
 			setPropertyValuesWithOptimizer( entity, values );
@@ -222,6 +233,9 @@
 		}
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public Object[] getPropertyValues(Object entity) throws HibernateException {
 		if ( shouldGetAllProperties( entity ) && optimizer != null && optimizer.getAccessOptimizer() != null ) {
 			return getPropertyValuesWithOptimizer( entity );
@@ -231,6 +245,9 @@
 		}
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session) throws HibernateException {
 		if ( shouldGetAllProperties( entity ) && optimizer != null && optimizer.getAccessOptimizer() != null ) {
 			return getPropertyValuesWithOptimizer( entity );
@@ -248,36 +265,60 @@
 		return optimizer.getAccessOptimizer().getPropertyValues( object );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public EntityMode getEntityMode() {
 		return EntityMode.POJO;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public Class getMappedClass() {
 		return mappedClass;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public boolean isLifecycleImplementor() {
 		return lifecycleImplementor;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public boolean isValidatableImplementor() {
 		return validatableImplementor;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	protected Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity) {
 		return mappedProperty.getGetter( mappedEntity.getMappedClass() );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	protected Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity) {
 		return mappedProperty.getSetter( mappedEntity.getMappedClass() );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public Class getConcreteProxyClass() {
 		return proxyInterface;
 	}
 
     //TODO: need to make the majority of this functionality into a top-level support class for custom impl support
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
 		if ( isInstrumented() ) {
 			Set lazyProps = lazyPropertiesAreUnfetched && getEntityMetamodel().hasLazyProperties() ?
@@ -288,6 +329,9 @@
 		}
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public boolean hasUninitializedLazyProperties(Object entity) {
 		if ( getEntityMetamodel().hasLazyProperties() ) {
 			FieldInterceptor callback = FieldInterceptionHelper.extractFieldInterceptor( entity );
@@ -298,8 +342,37 @@
 		}
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public boolean isInstrumented() {
 		return FieldInterceptionHelper.isInstrumented( getMappedClass() );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
+	public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory) {
+		final Class concreteEntityClass = entityInstance.getClass();
+		if ( concreteEntityClass == getMappedClass() ) {
+			return getEntityName();
+		}
+		else {
+			String entityName = getEntityMetamodel().findEntityNameByEntityClass( concreteEntityClass );
+			if ( entityName == null ) {
+				throw new HibernateException(
+						"Unable to resolve entity name from Class [" + concreteEntityClass.getName() + "]"
+								+ " expected instance/subclass of [" + getEntityName() + "]"
+				);
+			}
+			return entityName;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public EntityNameResolver[] getEntityNameResolvers() {
+		return null;
+	}
 }

Added: core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/Customer.hbm.xml
===================================================================
--- core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/Customer.hbm.xml	                        (rev 0)
+++ core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/Customer.hbm.xml	2008-10-07 15:56:16 UTC (rev 15259)
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<!--
+  ~ Hibernate, Relational Persistence for Idiomatic Java
+  ~
+  ~ Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+  ~
+  ~ 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
+  ~
+  -->
+
+<!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.dynamicentity">
+
+    <class name="Person" table="t_person" discriminator-value="person" abstract="false">
+        <tuplizer class="org.hibernate.test.dynamicentity.tuplizer2.MyEntityTuplizer" entity-mode="pojo"/>
+		<id name="id">
+            <generator class="native"/>
+        </id>
+        <discriminator force="false"/>
+		<property name="name"/>
+
+        <many-to-one name="address" cascade="all" column="addr_id"/>
+
+        <set name="family" lazy="true" cascade="all">
+            <key column="pers_id"/>
+            <one-to-many class="Person"/>
+        </set>
+
+        <subclass name="Customer" discriminator-value="customer" abstract="false">
+            <tuplizer class="org.hibernate.test.dynamicentity.tuplizer2.MyEntityTuplizer" entity-mode="pojo"/>
+            <many-to-one name="company" cascade="none" column="comp_id"/>
+    	</subclass>
+    </class>
+
+	<class name="Company" table="t_company" abstract="false">
+        <tuplizer class="org.hibernate.test.dynamicentity.tuplizer2.MyEntityTuplizer" entity-mode="pojo"/>
+		<id name="id">
+            <generator class="native"/>
+        </id>
+		<property name="name"/>
+	</class>
+
+    <class name="Address" table="t_address" abstract="false">
+        <tuplizer class="org.hibernate.test.dynamicentity.tuplizer2.MyEntityTuplizer" entity-mode="pojo"/>
+        <id name="id">
+            <generator class="native"/>
+        </id>
+        <property name="street"/>
+        <property name="city"/>
+        <property name="postalCode"/>
+    </class>
+
+</hibernate-mapping>

Added: core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/ImprovedTuplizerDynamicEntityTest.java
===================================================================
--- core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/ImprovedTuplizerDynamicEntityTest.java	                        (rev 0)
+++ core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/ImprovedTuplizerDynamicEntityTest.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -0,0 +1,149 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.dynamicentity.tuplizer2;
+
+import org.hibernate.test.dynamicentity.Company;
+import org.hibernate.test.dynamicentity.ProxyHelper;
+import org.hibernate.test.dynamicentity.Customer;
+import org.hibernate.test.dynamicentity.Address;
+import org.hibernate.test.dynamicentity.Person;
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+import junit.framework.TestSuite;
+
+import java.util.HashSet;
+
+/**
+ * Demonstrates use of Tuplizers to allow the use of JDK
+ * {@link java.lang.reflect.Proxy dynamic proxies} as our
+ * domain model.
+ * <p/>
+ * Here we plug a custom Interceptor into the session simply to
+ * allow us to not have to explicitly supply the appropriate entity
+ * name to the Session calls.
+ *
+ * @author Steve Ebersole
+ */
+public class ImprovedTuplizerDynamicEntityTest extends FunctionalTestCase {
+	public ImprovedTuplizerDynamicEntityTest(String x) {
+		super( x );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "dynamicentity/tuplizer2/Customer.hbm.xml" };
+	}
+
+	public void configure(Configuration cfg) {
+		super.configure( cfg );
+	}
+
+	public static TestSuite suite() {
+		return new FunctionalTestClassTestSuite( ImprovedTuplizerDynamicEntityTest.class );
+	}
+
+	public void testIt() {
+		// Test saving these dyna-proxies
+		Session session = openSession();
+		session.beginTransaction();
+		Company company = ProxyHelper.newCompanyProxy();
+		company.setName( "acme" );
+		session.save( company );
+		Customer customer = ProxyHelper.newCustomerProxy();
+		customer.setName( "Steve" );
+		customer.setCompany( company );
+		Address address = ProxyHelper.newAddressProxy();
+		address.setStreet( "somewhere over the rainbow" );
+		address.setCity( "lawerence, kansas" );
+		address.setPostalCode( "toto");
+		customer.setAddress( address );
+		customer.setFamily( new HashSet() );
+		Person son = ProxyHelper.newPersonProxy();
+		son.setName( "son" );
+		customer.getFamily().add( son );
+		Person wife = ProxyHelper.newPersonProxy();
+		wife.setName( "wife" );
+		customer.getFamily().add( wife );
+		session.save( customer );
+		session.getTransaction().commit();
+		session.close();
+
+		assertNotNull( "company id not assigned", company.getId() );
+		assertNotNull( "customer id not assigned", customer.getId() );
+		assertNotNull( "address id not assigned", address.getId() );
+		assertNotNull( "son:Person id not assigned", son.getId() );
+		assertNotNull( "wife:Person id not assigned", wife.getId() );
+
+		// Test loading these dyna-proxies, along with flush processing
+		session = openSession();
+		session.beginTransaction();
+		customer = ( Customer ) session.load( Customer.class, customer.getId() );
+		assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer ) );
+
+		customer.setName( "other" );
+		session.flush();
+		assertFalse( "should-be-proxy was initialized", Hibernate.isInitialized( customer.getCompany() ) );
+
+		session.refresh( customer );
+		assertEquals( "name not updated", "other", customer.getName() );
+		assertEquals( "company association not correct", "acme", customer.getCompany().getName() );
+
+		session.getTransaction().commit();
+		session.close();
+
+		// Test detached entity re-attachment with these dyna-proxies
+		customer.setName( "Steve" );
+		session = openSession();
+		session.beginTransaction();
+		session.update( customer );
+		session.flush();
+		session.refresh( customer );
+		assertEquals( "name not updated", "Steve", customer.getName() );
+		session.getTransaction().commit();
+		session.close();
+
+		// Test querying
+		session = openSession();
+		session.beginTransaction();
+		int count = session.createQuery( "from Customer" ).list().size();
+		assertEquals( "querying dynamic entity", 1, count );
+		session.clear();
+		count = session.createQuery( "from Person" ).list().size();
+		assertEquals( "querying dynamic entity", 3, count );
+		session.getTransaction().commit();
+		session.close();
+
+		// test deleteing
+		session = openSession();
+		session.beginTransaction();
+		session.delete( company );
+		session.delete( customer );
+		session.getTransaction().commit();
+		session.close();
+	}
+}

Added: core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityInstantiator.java
===================================================================
--- core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityInstantiator.java	                        (rev 0)
+++ core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityInstantiator.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -0,0 +1,78 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.dynamicentity.tuplizer2;
+
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.test.dynamicentity.Customer;
+import org.hibernate.test.dynamicentity.ProxyHelper;
+import org.hibernate.test.dynamicentity.Company;
+import org.hibernate.test.dynamicentity.Address;
+import org.hibernate.test.dynamicentity.Person;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.HibernateException;
+
+import java.io.Serializable;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MyEntityInstantiator implements Instantiator {
+	private final String entityName;
+
+	public MyEntityInstantiator(String entityName) {
+		this.entityName = entityName;
+	}
+
+	public Object instantiate(Serializable id) {
+		if ( Person.class.getName().equals( entityName ) ) {
+			return ProxyHelper.newPersonProxy( id );
+		}
+		if ( Customer.class.getName().equals( entityName ) ) {
+			return ProxyHelper.newCustomerProxy( id );
+		}
+		else if ( Company.class.getName().equals( entityName ) ) {
+			return ProxyHelper.newCompanyProxy( id );
+		}
+		else if ( Address.class.getName().equals( entityName ) ) {
+			return ProxyHelper.newAddressProxy( id );
+		}
+		else {
+			throw new IllegalArgumentException( "unknown entity for instantiation [" + entityName + "]" );
+		}
+	}
+
+	public Object instantiate() {
+		return instantiate( null );
+	}
+
+	public boolean isInstance(Object object) {
+		try {
+			return ReflectHelper.classForName( entityName ).isInstance( object );
+		}
+		catch( Throwable t ) {
+			throw new HibernateException( "could not get handle to entity-name as interface : " + t );
+		}
+	}
+}

Added: core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java
===================================================================
--- core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java	                        (rev 0)
+++ core/branches/Branch_3_3/testsuite/src/test/java/org/hibernate/test/dynamicentity/tuplizer2/MyEntityTuplizer.java	2008-10-07 15:56:16 UTC (rev 15259)
@@ -0,0 +1,87 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.dynamicentity.tuplizer2;
+
+import org.hibernate.tuple.entity.PojoEntityTuplizer;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.tuple.Instantiator;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+import org.hibernate.test.dynamicentity.tuplizer.MyEntityInstantiator;
+import org.hibernate.test.dynamicentity.ProxyHelper;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.EntityNameResolver;
+
+/**
+ * @author Steve Ebersole
+ */
+public class MyEntityTuplizer extends PojoEntityTuplizer {
+
+	public MyEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
+		super( entityMetamodel, mappedEntity );
+	}
+
+	public EntityNameResolver[] getEntityNameResolvers() {
+		return new EntityNameResolver[] { MyEntityNameResolver.INSTANCE };
+	}
+
+	protected Instantiator buildInstantiator(PersistentClass persistentClass) {
+		return new MyEntityInstantiator( persistentClass.getEntityName() );
+	}
+
+	public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory) {
+		String entityName = ProxyHelper.extractEntityName( entityInstance );
+		if ( entityName == null ) {
+			entityName = super.determineConcreteSubclassEntityName( entityInstance, factory );
+		}
+		return entityName;
+	}
+
+	protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
+		// allows defining a custom proxy factory, which is responsible for
+		// generating lazy proxies for a given entity.
+		//
+		// Here we simply use the default...
+		return super.buildProxyFactory( persistentClass, idGetter, idSetter );
+	}
+
+	public static class MyEntityNameResolver implements EntityNameResolver {
+		public static final MyEntityNameResolver INSTANCE = new MyEntityNameResolver();
+
+		public String resolveEntityName(Object entity) {
+			return ProxyHelper.extractEntityName( entity );
+		}
+
+		public boolean equals(Object obj) {
+			return getClass().equals( obj.getClass() );
+		}
+
+		public int hashCode() {
+			return getClass().hashCode();
+		}
+	}
+}




More information about the hibernate-commits mailing list