Clean up various legacy "read path" contracts

* Type#nullSafeGet
* Type#hydrate
* Type#resolve
* Type#getSemiResolvedType
* Type#semiResolve
* related
This commit is contained in:
Steve Ebersole 2021-09-10 17:35:09 -05:00
parent 3d27f61221
commit cf36d17fac
23 changed files with 110 additions and 1125 deletions

View File

@ -6,40 +6,12 @@
*/ */
package org.hibernate.engine.internal; package org.hibernate.engine.internal;
import org.hibernate.AssertionFailure;
import org.hibernate.CacheMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.entry.CacheEntry;
import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status; import org.hibernate.engine.spi.Status;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener;
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.event.spi.PreLoadEventListener;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.stat.internal.StatsHelper;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.type.EntityType; import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeHelper;
import org.jboss.logging.Logger;
/** /**
* Functionality relating to the Hibernate two-phase loading process, that may be reused by persisters * Functionality relating to the Hibernate two-phase loading process, that may be reused by persisters
@ -48,482 +20,11 @@ import org.jboss.logging.Logger;
* @author Gavin King * @author Gavin King
*/ */
public final class TwoPhaseLoad { public final class TwoPhaseLoad {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
TwoPhaseLoad.class.getName()
);
private TwoPhaseLoad() { private TwoPhaseLoad() {
} }
/** /**
* Register the "hydrated" state of an entity instance, after the first step of 2-phase loading.
*
* Add the "hydrated state" (an array) of an uninitialized entity to the session. We don't try
* to resolve any associations yet, because there might be other entities waiting to be
* read from the JDBC result set we are currently processing
*
* @param persister The persister for the hydrated entity
* @param id The entity identifier
* @param values The entity values
* @param rowId The rowId for the entity
* @param object An optional instance for the entity being loaded
* @param lockMode The lock mode
* @param session The Session
*/
public static void postHydrate(
final EntityPersister persister,
final Object id,
final Object[] values,
final Object rowId,
final Object object,
final LockMode lockMode,
final SharedSessionContractImplementor session) {
final Object version = Versioning.getVersion( values, persister );
session.getPersistenceContextInternal().addEntry(
object,
Status.LOADING,
values,
rowId,
id,
version,
lockMode,
true,
persister,
false
);
if ( version != null && LOG.isTraceEnabled() ) {
final String versionStr = persister.isVersioned()
? persister.getVersionType().toLoggableString( version, session.getFactory() )
: "null";
LOG.tracef( "Version: %s", versionStr );
}
}
/**
* Perform the second step of 2-phase load. Fully initialize the entity
* instance.
* <p/>
* After processing a JDBC result set, we "resolve" all the associations
* between the entities which were instantiated and had their state
* "hydrated" into an array
*
* @param entity The entity being loaded
* @param readOnly Is the entity being loaded as read-only
* @param session The Session
* @param preLoadEvent The (re-used) pre-load event
*/
public static void initializeEntity(
final Object entity,
final boolean readOnly,
final SharedSessionContractImplementor session,
final PreLoadEvent preLoadEvent) {
initializeEntity( entity, readOnly, session, preLoadEvent, EntityResolver.DEFAULT );
}
/**
* Perform the second step of 2-phase load. Fully initialize the entity
* instance.
* <p/>
* After processing a JDBC result set, we "resolve" all the associations
* between the entities which were instantiated and had their state
* "hydrated" into an array
*
* @param entity The entity being loaded
* @param readOnly Is the entity being loaded as read-only
* @param session The Session
* @param preLoadEvent The (re-used) pre-load event
* @param entityResolver the resolver used for to-one entity associations
* (not used when an entity is a bytecode-enhanced lazy entity)
*/
public static void initializeEntity(
final Object entity,
final boolean readOnly,
final SharedSessionContractImplementor session,
final PreLoadEvent preLoadEvent,
final EntityResolver entityResolver) {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
if ( entityEntry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to the session" );
}
initializeEntityEntryLoadedState( entity, entityEntry, session, entityResolver );
initializeEntityFromEntityEntryLoadedState( entity, entityEntry, readOnly, session, preLoadEvent );
}
public static void initializeEntityEntryLoadedState(
final Object entity,
final EntityEntry entityEntry,
final SharedSessionContractImplementor session,
final EntityResolver entityResolver) throws HibernateException {
final EntityPersister persister = entityEntry.getPersister();
final Object id = entityEntry.getId();
final Object[] hydratedState = entityEntry.getLoadedState();
final boolean debugEnabled = LOG.isDebugEnabled();
if ( debugEnabled ) {
LOG.debugf(
"Resolving attributes for %s",
MessageHelper.infoString( persister, id, session.getFactory() )
);
}
String entityName = persister.getEntityName();
String[] propertyNames = persister.getPropertyNames();
final Type[] types = persister.getPropertyTypes();
for ( int i = 0; i < hydratedState.length; i++ ) {
final Object value = hydratedState[i];
if ( debugEnabled ) {
LOG.debugf(
"Processing attribute `%s` : value = %s",
propertyNames[i],
value == LazyPropertyInitializer.UNFETCHED_PROPERTY ? "<un-fetched>" : value == PropertyAccessStrategyBackRefImpl.UNKNOWN ? "<unknown>" : value
);
}
if ( value == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
if ( debugEnabled ) {
LOG.debugf( "Resolving <un-fetched> attribute : `%s`", propertyNames[i] );
}
// IMPLEMENTATION NOTE: This is a lazy property on a bytecode-enhanced entity.
// hydratedState[i] needs to remain LazyPropertyInitializer.UNFETCHED_PROPERTY so that
// setPropertyValues() below (ultimately AbstractEntityTuplizer#setPropertyValues) works properly
// No resolution is necessary, unless the lazy property is a collection.
if ( types[i].isCollectionType() ) {
// IMPLEMENTATION NOTE: this is a lazy collection property on a bytecode-enhanced entity.
// HHH-10989: We need to resolve the collection so that a CollectionReference is added to StatefulPersistentContext.
// As mentioned above, hydratedState[i] needs to remain LazyPropertyInitializer.UNFETCHED_PROPERTY
// so do not assign the resolved, uninitialized PersistentCollection back to hydratedState[i].
Boolean overridingEager = getOverridingEager( session, entityName, propertyNames[i], types[i], debugEnabled );
types[i].resolve( value, session, entity, overridingEager );
}
}
else if ( value != PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
if ( debugEnabled ) {
final boolean isLazyEnhanced = persister.getBytecodeEnhancementMetadata()
.getLazyAttributesMetadata()
.getLazyAttributeNames()
.contains( propertyNames[i] );
LOG.debugf( "Attribute (`%s`) - enhanced for lazy-loading? - %s", propertyNames[i], isLazyEnhanced );
}
// we know value != LazyPropertyInitializer.UNFETCHED_PROPERTY
Boolean overridingEager = getOverridingEager( session, entityName, propertyNames[i], types[i], debugEnabled );
hydratedState[i] = types[i].isEntityType()
? entityResolver.resolve( (EntityType) types[i], value, session, entity, overridingEager )
: types[i].resolve( value, session, entity, overridingEager );
}
else {
if ( debugEnabled ) {
LOG.debugf( "Skipping <unknown> attribute : `%s`", propertyNames[i] );
}
}
}
}
public static void initializeEntityFromEntityEntryLoadedState(
final Object entity,
final EntityEntry entityEntry,
final boolean readOnly,
final SharedSessionContractImplementor session,
final PreLoadEvent preLoadEvent) throws HibernateException {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityPersister persister = entityEntry.getPersister();
final Object id = entityEntry.getId();
final Object[] hydratedState = entityEntry.getLoadedState();
final boolean debugEnabled = LOG.isDebugEnabled();
//Must occur after resolving identifiers!
if ( session.isEventSource() ) {
preLoadEvent.setEntity( entity ).setState( hydratedState ).setId( id ).setPersister( persister );
session.getFactory().getFastSessionServices()
.eventListenerGroup_PRE_LOAD.fireEventOnEachListener( preLoadEvent, PreLoadEventListener::onPreLoad );
}
persister.setPropertyValues( entity, hydratedState );
final SessionFactoryImplementor factory = session.getFactory();
final StatisticsImplementor statistics = factory.getStatistics();
if ( persister.canWriteToCache() && session.getCacheMode().isPutEnabled() ) {
if ( debugEnabled ) {
LOG.debugf(
"Adding entity to second-level cache: %s",
MessageHelper.infoString( persister, id, session.getFactory() )
);
}
final Object version = Versioning.getVersion( hydratedState, persister );
final CacheEntry entry = persister.buildCacheEntry( entity, hydratedState, version, session );
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object cacheKey = cache.generateCacheKey( id, persister, factory, session.getTenantIdentifier() );
// explicit handling of caching for rows just inserted and then somehow forced to be read
// from the database *within the same transaction*. usually this is done by
// 1) Session#refresh, or
// 2) Session#clear + some form of load
//
// we need to be careful not to clobber the lock here in the cache so that it can be rolled back if need be
if ( session.getPersistenceContextInternal().wasInsertedDuringTransaction( persister, id ) ) {
cache.update(
session,
cacheKey,
persister.getCacheEntryStructure().structure( entry ),
version,
version
);
}
else {
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
try {
eventListenerManager.cachePutStart();
final boolean put = cache.putFromLoad(
session,
cacheKey,
persister.getCacheEntryStructure().structure( entry ),
version,
useMinimalPuts( session, entityEntry )
);
if ( put && statistics.isStatisticsEnabled() ) {
statistics.entityCachePut(
StatsHelper.INSTANCE.getRootEntityRole( persister ),
cache.getRegion().getName()
);
}
}
finally {
eventListenerManager.cachePutEnd();
}
}
}
if ( persister.hasNaturalIdentifier() ) {
persistenceContext.getNaturalIdResolutions().cacheResolutionFromLoad(
id,
persister.getNaturalIdMapping().extractNaturalIdFromEntityState( hydratedState, session ),
persister
);
}
boolean isReallyReadOnly = readOnly;
if ( !persister.isMutable() ) {
isReallyReadOnly = true;
}
else {
final Object proxy = persistenceContext.getProxy( entityEntry.getEntityKey() );
if ( proxy != null ) {
// there is already a proxy for this impl
// only set the status to read-only if the proxy is read-only
isReallyReadOnly = ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isReadOnly();
}
}
if ( isReallyReadOnly ) {
//no need to take a snapshot - this is a
//performance optimization, but not really
//important, except for entities with huge
//mutable property values
persistenceContext.setEntryStatus( entityEntry, Status.READ_ONLY );
}
else {
//take a snapshot
TypeHelper.deepCopy(
hydratedState,
persister.getPropertyTypes(),
persister.getPropertyUpdateability(),
//after setting values to object
hydratedState,
session
);
persistenceContext.setEntryStatus( entityEntry, Status.MANAGED );
}
if ( debugEnabled ) {
LOG.debugf(
"Done materializing entity %s",
MessageHelper.infoString( persister, id, session.getFactory() )
);
}
if ( statistics.isStatisticsEnabled() ) {
statistics.loadEntity( persister.getEntityName() );
}
}
/**
* Perform the afterInitialize() step. This needs to be done after the collections have been properly initialized
* thus a separate step.
*
* @param entity The entity being loaded
* @param session The Session
*/
public static void afterInitialize(
final Object entity,
final SharedSessionContractImplementor session) {
final PersistenceContext persistenceContext = session.getPersistenceContext();
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
entityEntry.getPersister().afterInitialize( entity, session );
}
/**
* Check if eager of the association is overridden (i.e. skipping metamodel strategy), including (order sensitive):
* <ol>
* <li>fetch graph</li>
* <li>fetch profile</li>
* </ol>
*
* @param session session
* @param entityName entity name
* @param associationName association name
* @param associationType association type
* @param isDebugEnabled if debug log level enabled
* @return null if there is no overriding, true if it is overridden to eager and false if it is overridden to lazy
*/
private static Boolean getOverridingEager(
final SharedSessionContractImplementor session,
final String entityName,
final String associationName,
final Type associationType,
final boolean isDebugEnabled) {
// Performance: check type.isCollectionType() first, as type.isAssociationType() is megamorphic
if ( associationType.isCollectionType() || associationType.isAssociationType() ) {
// we can return false invariably for if the entity has been covered by entity graph,
// its associated JOIN has been present in the SQL generated and hence it would be loaded anyway
if ( session.isEnforcingFetchGraph() ) {
return false;
}
// check 'fetch profile' next; skip 'metamodel' if 'fetch profile' takes effect
final Boolean overridingEager = isEagerFetchProfile( session, entityName, associationName );
if ( overridingEager != null ) {
//This method is very hot, and private so let's piggy back on the fact that the caller already knows the debugging state.
if ( isDebugEnabled ) {
LOG.debugf(
"Overriding eager fetching using active fetch profile. EntityName: %s, associationName: %s, eager fetching: %s",
entityName,
associationName,
overridingEager
);
}
return overridingEager;
}
}
// let 'metamodel' decide eagerness
return null;
}
private static Boolean isEagerFetchProfile(SharedSessionContractImplementor session, String entityName, String associationName) {
LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
// Performance: avoid concatenating entityName + "." + associationName when there is no need,
// as otherwise this section becomes an hot allocation point.
if ( loadQueryInfluencers.hasEnabledFetchProfiles() ) {
final String role = entityName + '.' + associationName;
final SessionFactoryImplementor factory = session.getFactory();
for ( String fetchProfileName : loadQueryInfluencers.getEnabledFetchProfileNames() ) {
FetchProfile fp = factory.getFetchProfile( fetchProfileName );
Fetch fetch = fp.getFetchByRole( role );
if ( fetch != null && Fetch.Style.JOIN == fetch.getStyle() ) {
return true;
}
}
}
return null;
}
/**
* This method will be removed.
* @deprecated Use {@link #postLoad(Object, SharedSessionContractImplementor, PostLoadEvent)}
* instead.
*/
@Deprecated
public static void postLoad(
final Object entity,
final SharedSessionContractImplementor session,
final PostLoadEvent postLoadEvent,
final Iterable<PostLoadEventListener> postLoadEventListeners) {
postLoad( entity, session, postLoadEvent );
}
/**
* PostLoad cannot occur during initializeEntity, as that call occurs *before*
* the Set collections are added to the persistence context by Loader.
* Without the split, LazyInitializationExceptions can occur in the Entity's
* postLoad if it acts upon the collection.
*
* HHH-6043
*
* @param entity The entity
* @param session The Session
* @param postLoadEvent The (re-used) post-load event
*/
public static void postLoad(
final Object entity,
final SharedSessionContractImplementor session,
final PostLoadEvent postLoadEvent) {
if ( session.isEventSource() ) {
final EntityEntry entityEntry = session.getPersistenceContextInternal().getEntry( entity );
postLoadEvent.setEntity( entity ).setId( entityEntry.getId() ).setPersister( entityEntry.getPersister() );
session.getFactory().getFastSessionServices().firePostLoadEvent( postLoadEvent );
}
}
private static boolean useMinimalPuts(SharedSessionContractImplementor session, EntityEntry entityEntry) {
if ( session.getFactory().getSessionFactoryOptions().isMinimalPutsEnabled() ) {
return session.getCacheMode() != CacheMode.REFRESH;
}
else {
final EntityPersister persister = entityEntry.getPersister();
return persister.hasLazyProperties()
&& persister.isLazyPropertiesCacheable();
}
}
/**
* Add an uninitialized instance of an entity class, as a placeholder to ensure object
* identity. Must be called before <tt>postHydrate()</tt>.
*
* Create a "temporary" entry for a newly instantiated entity. The entity is uninitialized,
* but we need the mapping from id to instance in order to guarantee uniqueness.
*
* @param key The entity key
* @param object The entity instance
* @param persister The entity persister
* @param lockMode The lock mode
* @param session The Session
*/
public static void addUninitializedEntity(
final EntityKey key,
final Object object,
final EntityPersister persister,
final LockMode lockMode,
final SharedSessionContractImplementor session) {
session.getPersistenceContextInternal().addEntity(
object,
Status.LOADING,
null,
key,
null,
lockMode,
true,
persister,
false
);
}
/**
* Same as {@link #addUninitializedEntity}, but here for an entity from the second level cache
* *
* @param key The entity key * @param key The entity key
* @param object The entity instance * @param object The entity instance
@ -551,23 +52,4 @@ public final class TwoPhaseLoad {
false false
); );
} }
/**
* Implementations determine how a to-one associations is resolved.
*
* @see #initializeEntity(Object, boolean, SharedSessionContractImplementor, PreLoadEvent, EntityResolver)
*/
public interface EntityResolver {
Object resolve(
EntityType entityType,
Object value,
SharedSessionContractImplementor session,
Object owner,
Boolean overridingEager
);
EntityResolver DEFAULT = (entityType, value, session, owner, overridingEager) ->
entityType.resolve( value, session, owner, overridingEager );
}
} }

View File

@ -36,14 +36,14 @@ public class EntityUniqueKey implements Serializable {
public EntityUniqueKey( public EntityUniqueKey(
final String entityName, final String entityName,
final String uniqueKeyName, final String uniqueKeyName,
final Object semiResolvedKey, final Object key,
final Type keyType, final Type keyType,
final EntityMode entityMode, final EntityMode entityMode,
final SessionFactoryImplementor factory) { final SessionFactoryImplementor factory) {
this.uniqueKeyName = uniqueKeyName; this.uniqueKeyName = uniqueKeyName;
this.entityName = entityName; this.entityName = entityName;
this.key = semiResolvedKey; this.key = key;
this.keyType = keyType.getSemiResolvedType( factory ); this.keyType = keyType;
this.entityMode = entityMode; this.entityMode = entityMode;
this.hashCode = generateHashCode( factory ); this.hashCode = generateHashCode( factory );
} }

View File

@ -54,7 +54,8 @@ public class EvictVisitor extends AbstractVisitor {
collection = (PersistentCollection) value; collection = (PersistentCollection) value;
} }
else if ( value == LazyPropertyInitializer.UNFETCHED_PROPERTY ) { else if ( value == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
collection = (PersistentCollection) type.resolve( value, session, this.owner ); final Object keyOfOwner = type.getKeyOfOwner( owner, session );
collection = (PersistentCollection) type.getCollection( keyOfOwner, session, owner, Boolean.FALSE );
} }
else { else {
return; //EARLY EXIT! return; //EARLY EXIT!

View File

@ -11,6 +11,7 @@ import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.Collections; import org.hibernate.engine.internal.Collections;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.type.CollectionType; import org.hibernate.type.CollectionType;
/** /**
@ -41,7 +42,8 @@ public class FlushVisitor extends AbstractVisitor {
coll = session.getPersistenceContextInternal().getCollectionHolder(collection); coll = session.getPersistenceContextInternal().getCollectionHolder(collection);
} }
else if ( collection == LazyPropertyInitializer.UNFETCHED_PROPERTY ) { else if ( collection == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
coll = (PersistentCollection) type.resolve( collection, session, owner ); final Object keyOfOwner = type.getKeyOfOwner( owner, session );
coll = (PersistentCollection) type.getCollection( keyOfOwner, session, owner, Boolean.FALSE );
} }
else if ( collection instanceof PersistentCollection ) { else if ( collection instanceof PersistentCollection ) {
coll = (PersistentCollection) collection; coll = (PersistentCollection) collection;

View File

@ -13,6 +13,7 @@ import java.util.Properties;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.insert.AbstractSelectingDelegate; import org.hibernate.id.insert.AbstractSelectingDelegate;
@ -92,13 +93,16 @@ public class SelectGenerator extends AbstractPostInsertGenerator implements Conf
Dialect dialect, Dialect dialect,
String suppliedUniqueKeyPropertyName) { String suppliedUniqueKeyPropertyName) {
super( persister ); super( persister );
this.persister = persister;
this.dialect = dialect;
this.uniqueKeyPropertyName = determineNameOfPropertyToUse( persister, suppliedUniqueKeyPropertyName );
idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyName ); throw new NotYetImplementedFor6Exception( getClass() );
uniqueKeyType = persister.getPropertyType( uniqueKeyPropertyName );
idType = persister.getIdentifierType(); // this.persister = persister;
// this.dialect = dialect;
// this.uniqueKeyPropertyName = determineNameOfPropertyToUse( persister, suppliedUniqueKeyPropertyName );
//
// idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyName );
// uniqueKeyType = persister.getPropertyType( uniqueKeyPropertyName );
// idType = persister.getIdentifierType();
} }
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() { public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() {
@ -130,12 +134,14 @@ public class SelectGenerator extends AbstractPostInsertGenerator implements Conf
uniqueKeyPropertyName uniqueKeyPropertyName
); );
} }
return idType.nullSafeGet(
rs, throw new NotYetImplementedFor6Exception( getClass() );
persister.getRootTableKeyColumnNames(), // return idType.nullSafeGet(
session, // rs,
entity // persister.getRootTableKeyColumnNames(),
); // session,
// entity
// );
} }
} }
} }

View File

@ -986,23 +986,6 @@ public abstract class AbstractCollectionPersister
return elementClass; return elementClass;
} }
@Override
public Object readElement(ResultSet rs, Object owner, String[] aliases, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
return getElementType().nullSafeGet( rs, aliases, session, owner );
}
@Override
public Object readIndex(ResultSet rs, String[] aliases, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
Object index = getIndexType().nullSafeGet( rs, aliases, session, null );
if ( index == null ) {
throw new HibernateException( "null index column for collection: " + navigableRole.getFullPath() );
}
index = decrementIndexByBase( index );
return index;
}
protected Object decrementIndexByBase(Object index) { protected Object decrementIndexByBase(Object index) {
if ( baseIndex != 0 ) { if ( baseIndex != 0 ) {
index = (Integer)index - baseIndex; index = (Integer)index - baseIndex;
@ -1010,31 +993,6 @@ public abstract class AbstractCollectionPersister
return index; return index;
} }
@Override
public Object readIdentifier(ResultSet rs, String alias, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
Object id = getIdentifierType().nullSafeGet( rs, alias, session, null );
if ( id == null ) {
throw new HibernateException( "null identifier column for collection: " + navigableRole.getFullPath() );
}
return id;
}
@Override
public Object readKey(ResultSet rs, String[] aliases, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
// First hydrate the collection key to check if it is null.
// Don't bother resolving the collection key if the hydrated value is null.
// Implementation note: if collection key is a composite value, then resolving a null value will
// result in instantiating an empty composite if AvailableSettings#CREATE_EMPTY_COMPOSITES_ENABLED
// is true. By not resolving a null value for a composite key, we avoid the overhead of instantiating
// an empty composite, checking if it is equivalent to null (it should be), then ultimately throwing
// out the empty value.
final Object hydratedKey = getKeyType().hydrate( rs, aliases, session, null );
return hydratedKey == null ? null : getKeyType().resolve( hydratedKey, session, null );
}
/** /**
* Write the key to a JDBC <tt>PreparedStatement</tt> * Write the key to a JDBC <tt>PreparedStatement</tt>
*/ */

View File

@ -126,31 +126,6 @@ public interface CollectionPersister extends CollectionDefinition {
return null; return null;
} }
/**
* Read the key from a row of the JDBC <tt>ResultSet</tt>
*/
Object readKey(ResultSet rs, String[] keyAliases, SharedSessionContractImplementor session)
throws HibernateException, SQLException;
/**
* Read the element from a row of the JDBC <tt>ResultSet</tt>
*/
Object readElement(
ResultSet rs,
Object owner,
String[] columnAliases,
SharedSessionContractImplementor session) throws SQLException;
/**
* Read the index from a row of the JDBC <tt>ResultSet</tt>
*/
Object readIndex(ResultSet rs, String[] columnAliases, SharedSessionContractImplementor session) throws SQLException;
/**
* Read the identifier from a row of the JDBC <tt>ResultSet</tt>
*/
Object readIdentifier(
ResultSet rs,
String columnAlias,
SharedSessionContractImplementor session) throws SQLException;
/** /**
* Is this an array or primitive values? * Is this an array or primitive values?
*/ */

View File

@ -107,25 +107,6 @@ public class DiscriminatorType<T> extends AbstractType implements BasicType<T>,
return (T) get( discriminatorValue, options.getSession() ); return (T) get( discriminatorValue, options.getSession() );
} }
@Override
public Object nullSafeGet(
ResultSet rs,
String[] names,
SharedSessionContractImplementor session,
Object owner) throws HibernateException, SQLException {
return nullSafeGet( rs, names[0], session, owner );
}
@Override
public Object nullSafeGet(
ResultSet rs,
String name,
SharedSessionContractImplementor session,
Object owner) throws HibernateException, SQLException {
final Object discriminatorValue = underlyingType.nullSafeGet( rs, name, session, owner );
return get( discriminatorValue, session );
}
private Object get(Object discriminatorValue, SharedSessionContractImplementor session) { private Object get(Object discriminatorValue, SharedSessionContractImplementor session) {
final String entityName = persister.getSubclassForDiscriminatorValue( discriminatorValue ); final String entityName = persister.getSubclassForDiscriminatorValue( discriminatorValue );
if ( entityName == null ) { if ( entityName == null ) {

View File

@ -251,8 +251,7 @@ public abstract class AbstractStandardBasicType<T>
return isDirty( oldHydratedState, currentState ); return isDirty( oldHydratedState, currentState );
} }
@Override private final Object nullSafeGet(
public final Object nullSafeGet(
ResultSet rs, ResultSet rs,
String[] names, String[] names,
SharedSessionContractImplementor session, SharedSessionContractImplementor session,
@ -260,8 +259,7 @@ public abstract class AbstractStandardBasicType<T>
return nullSafeGet( rs, names[0], session ); return nullSafeGet( rs, names[0], session );
} }
@Override private final Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner)
public final Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner)
throws SQLException { throws SQLException {
return nullSafeGet( rs, name, session ); return nullSafeGet( rs, name, session );
} }
@ -336,27 +334,6 @@ public abstract class AbstractStandardBasicType<T>
public final void beforeAssemble(Serializable cached, SharedSessionContractImplementor session) { public final void beforeAssemble(Serializable cached, SharedSessionContractImplementor session) {
} }
@Override
public final Object hydrate(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
return nullSafeGet(rs, names, session, owner);
}
@Override
public final Object resolve(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
return value;
}
@Override
public final Object semiResolve(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
return value;
}
@Override
public final Type getSemiResolvedType(SessionFactoryImplementor factory) {
return this;
}
@Override @Override
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
public final Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) { public final Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) {

View File

@ -7,8 +7,6 @@
package org.hibernate.type; package org.hibernate.type;
import java.io.Serializable; import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -79,30 +77,6 @@ public abstract class AbstractType implements Type {
return !isSame( old, current ); return !isSame( old, current );
} }
@Override
public Object hydrate(
ResultSet rs,
String[] names,
SharedSessionContractImplementor session,
Object owner)
throws HibernateException, SQLException {
// TODO: this is very suboptimal for some subclasses (namely components),
// since it does not take advantage of two-phase-load
return nullSafeGet(rs, names, session, owner);
}
@Override
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException {
return value;
}
@Override
public Object semiResolve(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException {
return value;
}
@Override @Override
public boolean isAnyType() { public boolean isAnyType() {
return false; return false;
@ -139,11 +113,6 @@ public abstract class AbstractType implements Type {
return getHashCode(x ); return getHashCode(x );
} }
@Override
public Type getSemiResolvedType(SessionFactoryImplementor factory) {
return this;
}
@Override @Override
public Object replace( public Object replace(
Object original, Object original,

View File

@ -236,37 +236,6 @@ public class AnyType extends AbstractType implements CompositeType, AssociationT
return 2; return 2;
} }
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
return resolveAny(
(String) discriminatorType.nullSafeGet( rs, names[0], session, owner ),
identifierType.nullSafeGet( rs, names[1], session, owner ),
session
);
}
@Override
public Object hydrate(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
final String entityName = (String) discriminatorType.nullSafeGet( rs, names[0], session, owner );
final Object id = identifierType.nullSafeGet( rs, names[1], session, owner );
return new ObjectTypeCacheEntry( entityName, id );
}
@Override
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
final ObjectTypeCacheEntry holder = (ObjectTypeCacheEntry) value;
return resolveAny( holder.entityName, holder.id, session );
}
private Object resolveAny(String entityName, Object id, SharedSessionContractImplementor session)
throws HibernateException {
return entityName==null || id==null
? null
: session.internalLoad( entityName, id, eager, false );
}
@Override @Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException { throws HibernateException, SQLException {
@ -353,16 +322,10 @@ public class AnyType extends AbstractType implements CompositeType, AssociationT
} }
} }
@Override private Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) {
public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) {
throw new UnsupportedOperationException( "object is a multicolumn type" ); throw new UnsupportedOperationException( "object is a multicolumn type" );
} }
@Override
public Object semiResolve(Object value, SharedSessionContractImplementor session, Object owner) {
throw new UnsupportedOperationException( "any mappings may not form part of a property-ref" );
}
// CompositeType implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CompositeType implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override @Override

View File

@ -8,7 +8,6 @@ package org.hibernate.type;
import java.io.Serializable; import java.io.Serializable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -23,6 +22,7 @@ import java.util.TreeMap;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.collection.internal.AbstractPersistentCollection; import org.hibernate.collection.internal.AbstractPersistentCollection;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
@ -140,17 +140,6 @@ public abstract class CollectionType extends AbstractType implements Association
*/ */
public abstract PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key); public abstract PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister, Object key);
@Override
public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) throws SQLException {
return nullSafeGet( rs, new String[] { name }, session, owner );
}
@Override
public Object nullSafeGet(ResultSet rs, String[] name, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
return resolve( null, session, owner );
}
@Override @Override
public final void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, public final void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable,
SharedSessionContractImplementor session) throws HibernateException, SQLException { SharedSessionContractImplementor session) throws HibernateException, SQLException {
@ -431,11 +420,13 @@ public abstract class CollectionType extends AbstractType implements Association
Class returnedClass = keyType.getReturnedClass(); Class returnedClass = keyType.getReturnedClass();
if ( !returnedClass.isInstance( id ) ) { if ( !returnedClass.isInstance( id ) ) {
id = keyType.semiResolve( // todo (6.0) :
entityEntry.getLoadedValue( foreignKeyPropertyName ), throw new NotYetImplementedFor6Exception( "Re-work support for semi-resolve" );
session, // id = keyType.semiResolve(
owner // entityEntry.getLoadedValue( foreignKeyPropertyName ),
); // session,
// owner
// );
} }
return id; return id;
@ -474,22 +465,7 @@ public abstract class CollectionType extends AbstractType implements Association
return ownerId; return ownerId;
} }
@Override private Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) throws HibernateException {
public Object hydrate(ResultSet rs, String[] name, SharedSessionContractImplementor session, Object owner) {
// can't just return null here, since that would
// cause an owning component to become null
return NOT_NULL_COLLECTION;
}
@Override
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException {
return resolve( value, session, owner, null );
}
@Override
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) throws HibernateException {
return resolveKey( getKeyOfOwner( owner, session ), session, owner, overridingEager ); return resolveKey( getKeyOfOwner( owner, session ), session, owner, overridingEager );
} }
@ -500,13 +476,6 @@ public abstract class CollectionType extends AbstractType implements Association
getCollection( key, session, owner, overridingEager ); getCollection( key, session, owner, overridingEager );
} }
@Override
public Object semiResolve(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException {
throw new UnsupportedOperationException(
"collection mappings may not form part of a property-ref" );
}
public boolean isArrayType() { public boolean isArrayType() {
return false; return false;
} }

View File

@ -10,7 +10,6 @@ import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.sql.CallableStatement; import java.sql.CallableStatement;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -323,12 +322,6 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
} }
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
return resolve( hydrate( rs, names, session, owner ), session, owner );
}
@Override @Override
public void nullSafeSet(PreparedStatement st, Object value, int begin, SharedSessionContractImplementor session) public void nullSafeSet(PreparedStatement st, Object value, int begin, SharedSessionContractImplementor session)
throws HibernateException, SQLException { throws HibernateException, SQLException {
@ -384,13 +377,6 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
} }
} }
@Override
public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
return nullSafeGet( rs, new String[] {name}, session, owner );
}
@Override @Override
public Object getPropertyValue(Object component, int i, SharedSessionContractImplementor session) public Object getPropertyValue(Object component, int i, SharedSessionContractImplementor session)
throws HibernateException { throws HibernateException {
@ -652,64 +638,27 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
return joinedFetch[i]; return joinedFetch[i];
} }
@Override private Object resolve(Object value, SharedSessionContractImplementor session, Object owner)
public Object hydrate(
final ResultSet rs,
final String[] names,
final SharedSessionContractImplementor session,
final Object owner)
throws HibernateException, SQLException {
int begin = 0;
boolean notNull = false;
Object[] values = new Object[propertySpan];
for ( int i = 0; i < propertySpan; i++ ) {
int length = propertyTypes[i].getColumnSpan( session.getFactory() );
String[] range = ArrayHelper.slice( names, begin, length ); //cache this
Object val = propertyTypes[i].hydrate( rs, range, session, owner );
if ( val == null ) {
if ( isKey ) {
return null; //different nullability rules for pk/fk
}
}
else {
notNull = true;
}
values[i] = val;
begin += length;
}
return notNull ? values : null;
}
@Override
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException { throws HibernateException {
if ( value != null ) { throw new NotYetImplementedFor6Exception( getClass() );
Object result = instantiate( owner, session );
Object[] values = (Object[]) value;
Object[] resolvedValues = new Object[values.length]; //only really need new array during semi-resolve!
for ( int i = 0; i < values.length; i++ ) {
resolvedValues[i] = propertyTypes[i].resolve( values[i], session, owner );
}
setPropertyValues( result, resolvedValues, entityMode );
return result;
}
else if ( isCreateEmptyCompositesEnabled() ) {
return instantiate( owner, session );
}
else {
return null;
}
}
@Override // if ( value != null ) {
public Object semiResolve(Object value, SharedSessionContractImplementor session, Object owner) // Object result = instantiate( owner, session );
throws HibernateException { // Object[] values = (Object[]) value;
//note that this implementation is kinda broken // Object[] resolvedValues = new Object[values.length]; //only really need new array during semi-resolve!
//for components with many-to-one associations // for ( int i = 0; i < values.length; i++ ) {
return resolve( value, session, owner ); // resolvedValues[i] = propertyTypes[i].resolve( values[i], session, owner );
// }
// setPropertyValues( result, resolvedValues, entityMode );
// return result;
// }
// else if ( isCreateEmptyCompositesEnabled() ) {
// return instantiate( owner, session );
// }
// else {
// return null;
// }
} }
@Override @Override

View File

@ -169,8 +169,7 @@ public class CustomType<J>
return getUserType().hashCode( x); return getUserType().hashCode( x);
} }
@Override private Object nullSafeGet(
public Object nullSafeGet(
ResultSet rs, ResultSet rs,
String[] names, String[] names,
SharedSessionContractImplementor session, SharedSessionContractImplementor session,
@ -178,8 +177,7 @@ public class CustomType<J>
throw new UnsupportedOperationException( "Reading from ResultSet by name is no longer supported" ); throw new UnsupportedOperationException( "Reading from ResultSet by name is no longer supported" );
} }
@Override private Object nullSafeGet(
public Object nullSafeGet(
ResultSet rs, ResultSet rs,
String columnName, String columnName,
SharedSessionContractImplementor session, SharedSessionContractImplementor session,

View File

@ -7,7 +7,6 @@
package org.hibernate.type; package org.hibernate.type;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -223,21 +222,6 @@ public abstract class EntityType extends AbstractType implements AssociationType
} }
} }
@Override
public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
return nullSafeGet( rs, new String[] {name}, session, owner );
}
@Override
public final Object nullSafeGet(
ResultSet rs,
String[] names,
SharedSessionContractImplementor session,
Object owner) throws HibernateException, SQLException {
return resolve( hydrate( rs, names, session, owner ), session, owner );
}
@Override @Override
public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session) public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session)
throws SQLException { throws SQLException {
@ -418,13 +402,11 @@ public abstract class EntityType extends AbstractType implements AssociationType
/** /**
* Resolve an identifier or unique key value * Resolve an identifier or unique key value
*/ */
@Override private Object resolve(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
return resolve(value, session, owner, null); return resolve(value, session, owner, null);
} }
@Override private Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) throws HibernateException {
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) throws HibernateException {
if ( value != null && !isNull( owner, session ) ) { if ( value != null && !isNull( owner, session ) ) {
if ( isReferenceToPrimaryKey() ) { if ( isReferenceToPrimaryKey() ) {
return resolveIdentifier( value, session, overridingEager ); return resolveIdentifier( value, session, overridingEager );
@ -449,11 +431,6 @@ public abstract class EntityType extends AbstractType implements AssociationType
return overridingEager != null ? overridingEager : this.eager; return overridingEager != null ? overridingEager : this.eager;
} }
@Override
public Type getSemiResolvedType(SessionFactoryImplementor factory) {
return getAssociatedEntityPersister( factory ).getIdentifierType();
}
public EntityPersister getAssociatedEntityPersister(final SessionFactoryImplementor factory) { public EntityPersister getAssociatedEntityPersister(final SessionFactoryImplementor factory) {
final EntityPersister persister = associatedEntityPersister; final EntityPersister persister = associatedEntityPersister;
//The following branch implements a simple lazy-initialization, but rather than the canonical //The following branch implements a simple lazy-initialization, but rather than the canonical

View File

@ -7,8 +7,6 @@
package org.hibernate.type; package org.hibernate.type;
import java.io.Serializable; import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
@ -18,7 +16,6 @@ import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.spi.*; import org.hibernate.engine.spi.*;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**
@ -127,38 +124,6 @@ public class ManyToOneType extends EntityType {
return ForeignKeyDirection.FROM_PARENT; return ForeignKeyDirection.FROM_PARENT;
} }
@Override
public Object hydrate(
ResultSet rs,
String[] names,
SharedSessionContractImplementor session,
Object owner) throws HibernateException, SQLException {
// return the (fully resolved) identifier value, but do not resolve
// to the actual referenced entity instance
// NOTE: the owner of the association is not really the owner of the id!
// First hydrate the ID to check if it is null.
// Don't bother resolving the ID if hydratedKeyState[i] is null.
// Implementation note: if id is a composite ID, then resolving a null value will
// result in instantiating an empty composite if AvailableSettings#CREATE_EMPTY_COMPOSITES_ENABLED
// is true. By not resolving a null value for a composite ID, we avoid the overhead of instantiating
// an empty composite, checking if it is equivalent to null (it should be), then ultimately throwing
// out the empty value.
final Object hydratedId = getIdentifierOrUniqueKeyType( session.getFactory() )
.hydrate( rs, names, session, null );
final Object id;
if ( hydratedId != null ) {
id = getIdentifierOrUniqueKeyType( session.getFactory() )
.resolve( hydratedId, session, null );
}
else {
id = null;
}
scheduleBatchLoadIfNeeded( id, session );
return id;
}
/** /**
* Register the entity as batch loadable, if enabled * Register the entity as batch loadable, if enabled
*/ */
@ -203,28 +168,6 @@ public class ManyToOneType extends EntityType {
.isDirty( getIdentifier( old, session ), getIdentifier( current, session ), session ); .isDirty( getIdentifier( old, session ), getIdentifier( current, session ), session );
} }
@Override
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) throws HibernateException {
Object resolvedValue = super.resolve(value, session, owner, overridingEager);
if ( isLogicalOneToOne && value != null && getPropertyName() != null ) {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
EntityEntry entry = persistenceContext.getEntry( owner );
if ( entry != null ) {
final Loadable ownerPersister = (Loadable) session.getFactory().getMetamodel().entityPersister( entry.getEntityName() );
EntityUniqueKey entityKey = new EntityUniqueKey(
ownerPersister.getEntityName(),
getPropertyName(),
value,
this,
ownerPersister.getEntityMode(),
session.getFactory()
);
persistenceContext.addEntity( entityKey, owner );
}
}
return resolvedValue;
}
@Override @Override
public Serializable disassemble( public Serializable disassemble(
Object value, Object value,

View File

@ -75,26 +75,6 @@ public class MetaType extends AbstractType {
return String.class; return String.class;
} }
@Override
public Object nullSafeGet(
ResultSet rs,
String[] names,
SharedSessionContractImplementor session,
Object owner) throws HibernateException, SQLException {
Object key = baseType.nullSafeGet(rs, names, session, owner);
return key==null ? null : discriminatorValuesToEntityNameMap.get(key);
}
@Override
public Object nullSafeGet(
ResultSet rs,
String name,
SharedSessionContractImplementor session,
Object owner) throws HibernateException, SQLException {
Object key = baseType.nullSafeGet(rs, name, session, owner);
return key==null ? null : discriminatorValuesToEntityNameMap.get(key);
}
@Override @Override
public void nullSafeSet( public void nullSafeSet(
PreparedStatement st, PreparedStatement st,

View File

@ -8,8 +8,6 @@ package org.hibernate.type;
import java.io.Serializable; import java.io.Serializable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -21,6 +19,7 @@ import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.UniqueKeyLoadable;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**
@ -140,15 +139,6 @@ public class OneToOneType extends EntityType {
return foreignKeyType; return foreignKeyType;
} }
@Override
public Object hydrate(
ResultSet rs,
String[] names,
SharedSessionContractImplementor session,
Object owner) throws HibernateException, SQLException {
return session.getContextEntityIdentifier(owner);
}
@Override @Override
public boolean isNullable() { public boolean isNullable() {
return !constrained; return !constrained;
@ -182,7 +172,12 @@ public class OneToOneType extends EntityType {
if ( oid == null ) { if ( oid == null ) {
if ( uniqueKeyPropertyName != null ) { if ( uniqueKeyPropertyName != null ) {
return resolve( session.getContextEntityIdentifier( owner ), session, owner ); final EntityPersister associatedEntityPersister = getAssociatedEntityPersister( session.getFactory() );
return ( (UniqueKeyLoadable) associatedEntityPersister ).loadByUniqueKey(
uniqueKeyPropertyName,
session.getContextEntityIdentifier( owner ),
session
);
} }
return null; return null;
} }

View File

@ -7,8 +7,6 @@
package org.hibernate.type; package org.hibernate.type;
import java.io.Serializable; import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -78,13 +76,6 @@ public class SpecialOneToOneType extends OneToOneType {
return false; return false;
} }
@Override
public Object hydrate(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
return super.getIdentifierOrUniqueKeyType( session.getFactory() )
.nullSafeGet(rs, names, session, owner);
}
// TODO: copy/paste from ManyToOneType // TODO: copy/paste from ManyToOneType
@Override @Override
public Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) public Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner)

View File

@ -283,43 +283,6 @@ public interface Type extends Serializable {
SharedSessionContractImplementor session) SharedSessionContractImplementor session)
throws HibernateException; throws HibernateException;
/**
* Extract a value of the {@link #getReturnedClass() mapped class} from the JDBC result set. Implementors
* should handle possibility of null values.
*
* @param rs The result set from which to extract value.
* @param names the column names making up this type value (use to read from result set)
* @param session The originating session
* @param owner the parent entity
*
* @return The extracted value
*
* @throws HibernateException An error from Hibernate
* @throws SQLException An error from the JDBC driver
*
* @see Type#hydrate(ResultSet, String[], SharedSessionContractImplementor, Object) alternative, 2-phase property initialization
*/
Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException;
/**
* Extract a value of the {@link #getReturnedClass() mapped class} from the JDBC result set. Implementors
* should handle possibility of null values. This form might be called if the type is known to be a
* single-column type.
*
* @param rs The result set from which to extract value.
* @param name the column name making up this type value (use to read from result set)
* @param session The originating session
* @param owner the parent entity
*
* @return The extracted value
*
* @throws HibernateException An error from Hibernate
* @throws SQLException An error from the JDBC driver
*/
Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException;
/** /**
* Bind a value represented by an instance of the {@link #getReturnedClass() mapped class} to the JDBC prepared * Bind a value represented by an instance of the {@link #getReturnedClass() mapped class} to the JDBC prepared
* statement, ignoring some columns as dictated by the 'settable' parameter. Implementors should handle the * statement, ignoring some columns as dictated by the 'settable' parameter. Implementors should handle the
@ -437,82 +400,6 @@ public interface Type extends Serializable {
*/ */
void beforeAssemble(Serializable cached, SharedSessionContractImplementor session); void beforeAssemble(Serializable cached, SharedSessionContractImplementor session);
/**
* Extract a value from the JDBC result set. This is useful for 2-phase property initialization - the second
* phase is a call to {@link #resolve}
* This hydrated value will be either:<ul>
* <li>in the case of an entity or collection type, the key</li>
* <li>otherwise, the value itself</li>
* </ul>
*
* @param rs The JDBC result set
* @param names the column names making up this type value (use to read from result set)
* @param session The originating session
* @param owner the parent entity
*
* @return An entity or collection key, or an actual value.
*
* @throws HibernateException An error from Hibernate
* @throws SQLException An error from the JDBC driver
*
* @see #resolve
*/
Object hydrate(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException;
/**
* @see #resolve(Object, SharedSessionContractImplementor, Object, Boolean)
*/
Object resolve(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException;
/**
* The second phase of 2-phase loading. Only really pertinent for entities and collections. Here we resolve the
* identifier to an entity or collection instance
*
* @param value an identifier or value returned by <tt>hydrate()</tt>
* @param owner the parent entity
* @param session the session
* @param overridingEager can override eager from the mapping. For example because of {@link org.hibernate.engine.spi.LoadQueryInfluencers}
* If null, then it does not override. If true or false then it overrides the mapping value.
*
* @return the given value, or the value associated with the identifier
*
* @throws HibernateException An error from Hibernate
*
* @see #hydrate
*/
default Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager)
throws HibernateException {
return resolve(value, session, owner);
}
/**
* Given a hydrated, but unresolved value, return a value that may be used to reconstruct property-ref
* associations.
*
* @param value The unresolved, hydrated value
* @param session THe originating session
* @param owner The value owner
*
* @return The semi-resolved value
*
* @throws HibernateException An error from Hibernate
*/
Object semiResolve(Object value, SharedSessionContractImplementor session, Object owner)
throws HibernateException;
/**
* As part of 2-phase loading, when we perform resolving what is the resolved type for this type? Generally
* speaking the type and its semi-resolved type will be the same. The main deviation from this is in the
* case of an entity where the type would be the entity type and semi-resolved type would be its identifier type
*
* @param factory The session factory
*
* @return The semi-resolved type
*/
Type getSemiResolvedType(SessionFactoryImplementor factory);
/** /**
* During merge, replace the existing (target) value in the entity we are merging to * During merge, replace the existing (target) value in the entity we are merging to
* with a new (original) value from the detached entity we are merging. For immutable * with a new (original) value from the detached entity we are merging. For immutable

View File

@ -66,11 +66,14 @@ public class MergeEnhancedEntityTest extends BaseCoreFunctionalTestCase {
doInHibernate( this::sessionFactory, s -> { doInHibernate( this::sessionFactory, s -> {
Person entity = s.find( Person.class, 1L ); Person entity = s.find( Person.class, 1L );
entity.name = "John"; entity.name = "John";
try {
s.refresh( entity ); s.refresh( entity );
} catch ( RuntimeException e ) {
fail( "Enhanced entity can't be refreshed: " + e.getMessage() ); // try {
} // s.refresh( entity );
// } catch ( RuntimeException e ) {
// fail( "Enhanced entity can't be refreshed: " + e.getMessage() );
// }
} ); } );
} }

View File

@ -7,8 +7,6 @@
package org.hibernate.orm.test.cfg.persister; package org.hibernate.orm.test.cfg.persister;
import java.io.Serializable; import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@ -783,26 +781,6 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
return null; //To change body of implemented methods use File | Settings | File Templates. return null; //To change body of implemented methods use File | Settings | File Templates.
} }
public Object readKey(ResultSet rs, String[] keyAliases, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Object readElement(ResultSet rs, Object owner, String[] columnAliases, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Object readIndex(ResultSet rs, String[] columnAliases, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Object readIdentifier(ResultSet rs, String columnAlias, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public boolean isPrimitiveArray() { public boolean isPrimitiveArray() {
return false; //To change body of implemented methods use File | Settings | File Templates. return false; //To change body of implemented methods use File | Settings | File Templates.
} }

View File

@ -339,41 +339,42 @@ public class CustomPersister implements EntityPersister {
Object id, Object id,
Object optionalObject, Object optionalObject,
LockMode lockMode, LockMode lockMode,
SharedSessionContractImplementor session SharedSessionContractImplementor session) {
) throws HibernateException {
// fails when optional object is supplied throw new UnsupportedOperationException();
//
Custom clone = null; // // fails when optional object is supplied
Custom obj = (Custom) INSTANCES.get(id); //
if (obj!=null) { // Custom clone = null;
clone = (Custom) obj.clone(); // Custom obj = (Custom) INSTANCES.get(id);
TwoPhaseLoad.addUninitializedEntity( // if (obj!=null) {
session.generateEntityKey( id, this ), // clone = (Custom) obj.clone();
clone, // TwoPhaseLoad.addUninitializedEntity(
this, // session.generateEntityKey( id, this ),
LockMode.NONE, // clone,
session // this,
); // LockMode.NONE,
TwoPhaseLoad.postHydrate( // session
this, // );
id, // TwoPhaseLoad.postHydrate(
new String[] { obj.getName() }, // this,
null, // id,
clone, // new String[] { obj.getName() },
LockMode.NONE, // null,
session // clone,
); // LockMode.NONE,
TwoPhaseLoad.initializeEntity( // session
clone, // );
false, // TwoPhaseLoad.initializeEntity(
session, // clone,
new PreLoadEvent( (EventSource) session ) // false,
); // session,
TwoPhaseLoad.afterInitialize( clone, session ); // new PreLoadEvent( (EventSource) session )
TwoPhaseLoad.postLoad( clone, session, new PostLoadEvent( (EventSource) session ) ); // );
} // TwoPhaseLoad.afterInitialize( clone, session );
return clone; // TwoPhaseLoad.postLoad( clone, session, new PostLoadEvent( (EventSource) session ) );
// }
// return clone;
} }
/** /**