HHH-3515 : EntityNameResolver
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15258 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
86eeb9be34
commit
c3d4758f1e
|
@ -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);
|
||||
}
|
|
@ -39,6 +39,7 @@ import java.util.Iterator;
|
|||
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,8 @@ import org.hibernate.QueryException;
|
|||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.SessionFactoryObserver;
|
||||
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;
|
||||
|
@ -117,6 +120,7 @@ import org.hibernate.type.AssociationType;
|
|||
import org.hibernate.type.Type;
|
||||
import org.hibernate.util.CollectionHelper;
|
||||
import org.hibernate.util.ReflectHelper;
|
||||
import org.hibernate.util.EmptyIterator;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -177,6 +181,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
|||
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 );
|
||||
|
||||
|
@ -325,11 +330,15 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
|||
// 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:
|
||||
|
@ -458,6 +467,41 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ import org.hibernate.Transaction;
|
|||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.UnknownProfileException;
|
||||
import org.hibernate.EntityNameResolver;
|
||||
import org.hibernate.collection.PersistentCollection;
|
||||
import org.hibernate.engine.ActionQueue;
|
||||
import org.hibernate.engine.CollectionEntry;
|
||||
|
@ -127,6 +128,7 @@ import org.hibernate.proxy.LazyInitializer;
|
|||
import org.hibernate.stat.SessionStatistics;
|
||||
import org.hibernate.stat.SessionStatisticsImpl;
|
||||
import org.hibernate.tuple.DynamicMapInstantiator;
|
||||
import org.hibernate.tuple.entity.PojoEntityTuplizer;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.util.ArrayHelper;
|
||||
import org.hibernate.util.CollectionHelper;
|
||||
|
@ -175,6 +177,30 @@ public final class SessionImpl extends AbstractSessionImpl
|
|||
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".
|
||||
*
|
||||
|
@ -1724,23 +1750,7 @@ public final class SessionImpl extends AbstractSessionImpl
|
|||
|
||||
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 {
|
||||
|
|
|
@ -132,7 +132,6 @@ public abstract class AbstractEntityPersister
|
|||
private final boolean isLazyPropertiesCacheable;
|
||||
private final CacheEntryStructure cacheEntryStructure;
|
||||
private final EntityMetamodel entityMetamodel;
|
||||
private final Map entityNameBySubclass = new HashMap();
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private final String[] rootTableKeyColumnNames;
|
||||
|
@ -456,15 +455,6 @@ public abstract class AbstractEntityPersister
|
|||
(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();
|
||||
|
@ -3302,10 +3292,6 @@ public abstract class AbstractEntityPersister
|
|||
return entityMetamodel.getEntityType();
|
||||
}
|
||||
|
||||
private String getSubclassEntityName(Class clazz) {
|
||||
return ( String ) entityNameBySubclass.get( clazz );
|
||||
}
|
||||
|
||||
public boolean isPolymorphic() {
|
||||
return entityMetamodel.isPolymorphic();
|
||||
}
|
||||
|
@ -3694,29 +3680,17 @@ public abstract class AbstractEntityPersister
|
|||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -668,15 +668,35 @@ public interface EntityPersister extends OptimisticCacheSource {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,15 @@ public abstract class EntityModeToTuplizerMapping implements Serializable {
|
|||
tuplizers.put( entityMode, tuplizer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow iteration over all defined {@link Tuplizer Tuplizers}.
|
||||
*
|
||||
* @return Iterator over defined tuplizers
|
||||
*/
|
||||
public Iterator iterateTuplizers() {
|
||||
return tuplizers.values().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a supposed instance of an entity/component, guess its entity mode.
|
||||
*
|
||||
|
|
|
@ -73,13 +73,6 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
|||
private final AbstractComponentType identifierMapperType;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
|
|
@ -35,6 +35,8 @@ import org.hibernate.property.Getter;
|
|||
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 org.slf4j.LoggerFactory;
|
|||
|
||||
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 @@ public class Dom4jEntityTuplizer extends AbstractEntityTuplizer {
|
|||
|
||||
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 @@ public class Dom4jEntityTuplizer extends AbstractEntityTuplizer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 @@ public class Dom4jEntityTuplizer extends AbstractEntityTuplizer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected ProxyFactory buildProxyFactory(PersistentClass mappingInfo, Getter idGetter, Setter idSetter) {
|
||||
HashSet proxyInterfaces = new HashSet();
|
||||
proxyInterfaces.add( HibernateProxy.class );
|
||||
|
@ -132,15 +154,73 @@ public class Dom4jEntityTuplizer extends AbstractEntityTuplizer {
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ import java.util.Map;
|
|||
|
||||
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 class DynamicMapEntityTuplizer extends AbstractEntityTuplizer {
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,21 +122,10 @@ public class EntityMetamodel implements Serializable {
|
|||
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 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
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 class EntityMetamodel implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ public class EntityMetamodel implements Serializable {
|
|||
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) + ')';
|
||||
}
|
||||
|
|
|
@ -28,8 +28,11 @@ import java.io.Serializable;
|
|||
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 @@ import org.hibernate.engine.SessionImplementor;
|
|||
* @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 interface EntityTuplizer extends Tuplizer {
|
|||
*/
|
||||
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 @@ public interface EntityTuplizer extends Tuplizer {
|
|||
* 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);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory;
|
|||
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.cfg.Environment;
|
|||
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 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
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 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
}
|
||||
|
||||
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 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Object[] getPropertyValues(Object entity) throws HibernateException {
|
||||
if ( shouldGetAllProperties( entity ) && optimizer != null && optimizer.getAccessOptimizer() != null ) {
|
||||
return getPropertyValuesWithOptimizer( entity );
|
||||
|
@ -231,6 +245,9 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
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 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean hasUninitializedLazyProperties(Object entity) {
|
||||
if ( getEntityMetamodel().hasLazyProperties() ) {
|
||||
FieldInterceptor callback = FieldInterceptionHelper.extractFieldInterceptor( entity );
|
||||
|
@ -298,8 +342,37 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue