clean up CollectionType
This commit is contained in:
parent
8f85e6ca47
commit
2c08833c6d
|
@ -10,8 +10,6 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -34,13 +32,11 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.MarkerObject;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.proxy.LazyInitializer;
|
||||
import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry;
|
||||
|
||||
|
@ -49,6 +45,10 @@ import org.jboss.logging.Logger;
|
|||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import static org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.UNFETCHED_PROPERTY;
|
||||
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_BOOLEAN_ARRAY;
|
||||
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_INT_ARRAY;
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.mapOfSize;
|
||||
import static org.hibernate.pretty.MessageHelper.collectionInfoString;
|
||||
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
|
||||
|
||||
/**
|
||||
|
@ -90,14 +90,13 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
// collections, since they can only occur for inverse collections!
|
||||
final Iterator<?> elems = getElementsIterator( collection );
|
||||
while ( elems.hasNext() ) {
|
||||
Object element = elems.next();
|
||||
final Object maybeProxy = elems.next();
|
||||
// worrying about proxies is perhaps a little bit of overkill here...
|
||||
final LazyInitializer li = extractLazyInitializer( element );
|
||||
if ( li != null ) {
|
||||
if ( !li.isUninitialized() ) {
|
||||
element = li.getImplementation();
|
||||
}
|
||||
}
|
||||
final LazyInitializer initializer = extractLazyInitializer( maybeProxy );
|
||||
final Object element =
|
||||
initializer != null && !initializer.isUninitialized()
|
||||
? initializer.getImplementation()
|
||||
: maybeProxy;
|
||||
if ( element == childObject ) {
|
||||
return true;
|
||||
}
|
||||
|
@ -113,13 +112,13 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
@Override
|
||||
public final boolean isEqual(Object x, Object y) {
|
||||
return x == y
|
||||
|| x instanceof PersistentCollection && isEqual( (PersistentCollection<?>) x, y )
|
||||
|| y instanceof PersistentCollection && isEqual( (PersistentCollection<?>) y, x );
|
||||
|| x instanceof PersistentCollection<?> xc && isEqual( xc, y )
|
||||
|| y instanceof PersistentCollection<?> yc && isEqual( yc, x );
|
||||
}
|
||||
|
||||
private boolean isEqual(PersistentCollection<?> x, Object y) {
|
||||
return x.wasInitialized()
|
||||
&& ( x.isWrapper( y ) || x.isDirectlyProvidedCollection( y ) );
|
||||
private boolean isEqual(PersistentCollection<?> collection, Object other) {
|
||||
return collection.wasInitialized()
|
||||
&& ( collection.isWrapper( other ) || collection.isDirectlyProvidedCollection( other ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -161,7 +160,7 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
|
||||
@Override
|
||||
public int[] getSqlTypeCodes(MappingContext mappingContext) throws MappingException {
|
||||
return ArrayHelper.EMPTY_INT_ARRAY;
|
||||
return EMPTY_INT_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -174,43 +173,43 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
if ( value == null ) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if ( !getReturnedClass().isInstance( value ) && !(value instanceof PersistentCollection) ) {
|
||||
// its most likely the collection-key
|
||||
final CollectionPersister persister = getPersister( factory );
|
||||
final Type keyType = persister.getKeyType();
|
||||
if ( keyType.getReturnedClass().isInstance( value ) ) {
|
||||
return getRole() + "#" + keyType.toLoggableString( value, factory );
|
||||
}
|
||||
else {
|
||||
// although it could also be the collection-id
|
||||
else {
|
||||
if ( !getReturnedClass().isInstance( value )
|
||||
&& !(value instanceof PersistentCollection) ) {
|
||||
final CollectionPersister persister = getPersister( factory );
|
||||
final Type keyType = persister.getKeyType();
|
||||
final Type identifierType = persister.getIdentifierType();
|
||||
if ( identifierType != null
|
||||
// its most likely the collection-key
|
||||
if ( keyType.getReturnedClass().isInstance( value ) ) {
|
||||
return getRole() + "#" + keyType.toLoggableString( value, factory );
|
||||
}
|
||||
// although it could also be the collection-id
|
||||
else if ( identifierType != null
|
||||
&& identifierType.getReturnedClass().isInstance( value ) ) {
|
||||
return getRole() + "#" + identifierType.toLoggableString( value, factory );
|
||||
}
|
||||
}
|
||||
return renderLoggableString( value, factory );
|
||||
}
|
||||
return renderLoggableString( value, factory );
|
||||
}
|
||||
|
||||
protected String renderLoggableString(Object value, SessionFactoryImplementor factory) {
|
||||
if ( !Hibernate.isInitialized( value ) ) {
|
||||
return "<uninitialized>";
|
||||
}
|
||||
|
||||
final List<String> list = new ArrayList<>();
|
||||
final Type elemType = getElementType( factory );
|
||||
final Iterator<?> itr = getElementsIterator( value );
|
||||
while ( itr.hasNext() ) {
|
||||
final Object element = itr.next();
|
||||
final String string =
|
||||
element == UNFETCHED_PROPERTY || !Hibernate.isInitialized(element)
|
||||
? "<uninitialized>"
|
||||
: elemType.toLoggableString( element, factory );
|
||||
list.add( string );
|
||||
else {
|
||||
final List<String> list = new ArrayList<>();
|
||||
final Type elemType = getElementType( factory );
|
||||
getElementsIterator( value )
|
||||
.forEachRemaining( element -> list.add( elementString( factory, element, elemType ) ) );
|
||||
return list.toString();
|
||||
}
|
||||
return list.toString();
|
||||
}
|
||||
|
||||
private static String elementString(SessionFactoryImplementor factory, Object element, Type elemType) {
|
||||
return element == UNFETCHED_PROPERTY || !Hibernate.isInitialized( element )
|
||||
? "<uninitialized>"
|
||||
: elemType.toLoggableString( element, factory );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -303,25 +302,24 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
* @return The underlying collection persister
|
||||
*/
|
||||
private CollectionPersister getPersister(SharedSessionContractImplementor session) {
|
||||
CollectionPersister p = this.persister;
|
||||
return p != null ? p : getPersister( session.getFactory() );
|
||||
return getPersister( session.getFactory() );
|
||||
}
|
||||
|
||||
private CollectionPersister getPersister(SessionFactoryImplementor factory) {
|
||||
CollectionPersister p = this.persister;
|
||||
if ( p != null ) {
|
||||
return p;
|
||||
CollectionPersister persister = this.persister;
|
||||
if ( persister != null ) {
|
||||
return persister;
|
||||
}
|
||||
else {
|
||||
synchronized ( this ) {
|
||||
p = this.persister;
|
||||
if ( p != null ) {
|
||||
return p;
|
||||
persister = this.persister;
|
||||
if ( persister != null ) {
|
||||
return persister;
|
||||
}
|
||||
else {
|
||||
p = factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( role );
|
||||
this.persister = p;
|
||||
return p;
|
||||
persister = factory.getMappingMetamodel().getCollectionDescriptor( role );
|
||||
this.persister = persister;
|
||||
return persister;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -408,8 +406,7 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
return key;
|
||||
}
|
||||
else {
|
||||
final CollectionPersister persister = getPersister( session );
|
||||
final EntityPersister ownerPersister = persister.getOwnerEntityPersister();
|
||||
final EntityPersister ownerPersister = getPersister( session ).getOwnerEntityPersister();
|
||||
// TODO: Fix this so it will work for non-POJO entity mode
|
||||
final Class<?> keyClass = keyClass( session );
|
||||
if ( ownerPersister.getMappedClass().isAssignableFrom( keyClass )
|
||||
|
@ -452,7 +449,7 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
@Override
|
||||
public Joinable getAssociatedJoinable(SessionFactoryImplementor factory)
|
||||
throws MappingException {
|
||||
return (Joinable) factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( role );
|
||||
return (Joinable) factory.getMappingMetamodel().getCollectionDescriptor( role );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -463,22 +460,12 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
@Override
|
||||
public String getAssociatedEntityName(SessionFactoryImplementor factory)
|
||||
throws MappingException {
|
||||
try {
|
||||
|
||||
CollectionPersister collectionPersister = factory.getRuntimeMetamodels().getMappingMetamodel().getCollectionDescriptor( role );
|
||||
|
||||
if ( !( collectionPersister.getElementType() instanceof EntityType ) ) {
|
||||
throw new MappingException(
|
||||
"collection was not an association: " +
|
||||
collectionPersister.getRole()
|
||||
);
|
||||
}
|
||||
|
||||
return collectionPersister.getElementPersister().getEntityName();
|
||||
|
||||
final CollectionPersister persister = factory.getMappingMetamodel().getCollectionDescriptor( role );
|
||||
if ( persister.getElementType().isEntityType() ) {
|
||||
return persister.getElementPersister().getEntityName();
|
||||
}
|
||||
catch (ClassCastException cce) {
|
||||
throw new MappingException( "collection role is not queryable " + role );
|
||||
else {
|
||||
throw new MappingException( "Collection is not an association: " + persister.getRole() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -499,13 +486,13 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
Object owner,
|
||||
Map<Object, Object> copyCache,
|
||||
SharedSessionContractImplementor session) {
|
||||
Collection result = (Collection) target;
|
||||
final Collection result = (Collection) target;
|
||||
result.clear();
|
||||
|
||||
// copy elements into newly empty target collection
|
||||
Type elemType = getElementType( session.getFactory() );
|
||||
for ( Object o : (Collection<?>) original ) {
|
||||
result.add( elemType.replace(o, null, session, owner, copyCache) );
|
||||
final Type elemType = getElementType( session.getFactory() );
|
||||
for ( Object o : (Collection) original ) {
|
||||
result.add( elemType.replace( o, null, session, owner, copyCache ) );
|
||||
}
|
||||
|
||||
// if the original is a PersistentCollection, and that original
|
||||
|
@ -517,7 +504,8 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
// on the target because we simply do not know...
|
||||
if ( original instanceof PersistentCollection<?> originalPersistentCollection
|
||||
&& result instanceof PersistentCollection<?> resultPersistentCollection) {
|
||||
preserveSnapshot( originalPersistentCollection, resultPersistentCollection, elemType, owner, copyCache, session );
|
||||
preserveSnapshot( originalPersistentCollection, resultPersistentCollection,
|
||||
elemType, owner, copyCache, session );
|
||||
if ( !originalPersistentCollection.isDirty() ) {
|
||||
resultPersistentCollection.clearDirty();
|
||||
}
|
||||
|
@ -533,71 +521,85 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
Object owner,
|
||||
Map<Object, Object> copyCache,
|
||||
SharedSessionContractImplementor session) {
|
||||
Serializable originalSnapshot = original.getStoredSnapshot();
|
||||
Serializable resultSnapshot = result.getStoredSnapshot();
|
||||
Serializable targetSnapshot;
|
||||
|
||||
if ( originalSnapshot instanceof List ) {
|
||||
ArrayList<Object> targetList = new ArrayList<>( ( (List<?>) originalSnapshot ).size() );
|
||||
targetSnapshot = targetList;
|
||||
for ( Object obj : (List<?>) originalSnapshot ) {
|
||||
targetList.add( elemType.replace( obj, null, session, owner, copyCache ) );
|
||||
}
|
||||
|
||||
final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( result );
|
||||
if ( ce != null ) {
|
||||
ce.resetStoredSnapshot( result,
|
||||
createSnapshot( original, result, elemType, owner, copyCache, session ) );
|
||||
}
|
||||
else if ( originalSnapshot instanceof Map ) {
|
||||
Map<Object,Object> targetMap;
|
||||
if ( originalSnapshot instanceof SortedMap ) {
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
Comparator<Object> comparator = ((SortedMap) originalSnapshot).comparator();
|
||||
targetMap = new TreeMap<>( comparator );
|
||||
}
|
||||
else {
|
||||
targetMap = new HashMap<>(
|
||||
CollectionHelper.determineProperSizing( ( (Map<?,?>) originalSnapshot ).size() ),
|
||||
CollectionHelper.LOAD_FACTOR
|
||||
);
|
||||
}
|
||||
targetSnapshot = (Serializable) targetMap;
|
||||
|
||||
for ( Map.Entry<?,?> entry : ( (Map<?, ?>) originalSnapshot ).entrySet() ) {
|
||||
Object key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
Object resultSnapshotValue = ( resultSnapshot == null )
|
||||
? null
|
||||
: ( (Map<?,?>) resultSnapshot ).get( key );
|
||||
|
||||
Object newValue = elemType.replace( value, resultSnapshotValue, session, owner, copyCache );
|
||||
|
||||
if ( key == value ) {
|
||||
targetMap.put( newValue, newValue );
|
||||
|
||||
}
|
||||
else {
|
||||
targetMap.put( key, newValue );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static Serializable createSnapshot(
|
||||
PersistentCollection<?> original,
|
||||
PersistentCollection<?> result,
|
||||
Type elemType,
|
||||
Object owner,
|
||||
Map<Object, Object> copyCache,
|
||||
SharedSessionContractImplementor session) {
|
||||
final Serializable originalSnapshot = original.getStoredSnapshot();
|
||||
if ( originalSnapshot instanceof List<?> list ) {
|
||||
return createListSnapshot( list, elemType, owner, copyCache, session );
|
||||
}
|
||||
else if ( originalSnapshot instanceof Map<?,?> map ) {
|
||||
return createMapSnapshot( map, result, elemType, owner, copyCache, session );
|
||||
}
|
||||
else if ( originalSnapshot instanceof Object[] array ) {
|
||||
for ( int i = 0; i < array.length; i++ ) {
|
||||
array[i] = elemType.replace( array[i], null, session, owner, copyCache );
|
||||
}
|
||||
targetSnapshot = originalSnapshot;
|
||||
|
||||
return createArraySnapshot( array, elemType, owner, copyCache, session );
|
||||
}
|
||||
else {
|
||||
// retain the same snapshot
|
||||
targetSnapshot = resultSnapshot;
|
||||
|
||||
return result.getStoredSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( result );
|
||||
if ( ce != null ) {
|
||||
ce.resetStoredSnapshot( result, targetSnapshot );
|
||||
private static Serializable createArraySnapshot(
|
||||
Object[] array,
|
||||
Type elemType,
|
||||
Object owner,
|
||||
Map<Object, Object> copyCache,
|
||||
SharedSessionContractImplementor session) {
|
||||
for ( int i = 0; i < array.length; i++ ) {
|
||||
array[i] = elemType.replace( array[i], null, session, owner, copyCache );
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private static Serializable createMapSnapshot(
|
||||
Map<?, ?> map,
|
||||
PersistentCollection<?> result,
|
||||
Type elemType,
|
||||
Object owner,
|
||||
Map<Object, Object> copyCache,
|
||||
SharedSessionContractImplementor session) {
|
||||
final Map<?,?> resultSnapshot = (Map<?,?>) result.getStoredSnapshot();
|
||||
final Map<Object, Object> targetMap;
|
||||
if ( map instanceof SortedMap<?,?> sortedMap ) {
|
||||
//noinspection unchecked, rawtypes
|
||||
targetMap = new TreeMap( sortedMap.comparator() );
|
||||
}
|
||||
else {
|
||||
targetMap = mapOfSize( map.size() );
|
||||
}
|
||||
for ( Map.Entry<?,?> entry : map.entrySet() ) {
|
||||
final Object key = entry.getKey();
|
||||
final Object value = entry.getValue();
|
||||
final Object resultSnapshotValue = resultSnapshot == null ? null : resultSnapshot.get( key );
|
||||
final Object newValue = elemType.replace( value, resultSnapshotValue, session, owner, copyCache );
|
||||
targetMap.put( key == value ? newValue : key, newValue );
|
||||
}
|
||||
return (Serializable) targetMap;
|
||||
}
|
||||
|
||||
private static ArrayList<Object> createListSnapshot(
|
||||
List<?> list,
|
||||
Type elemType,
|
||||
Object owner,
|
||||
Map<Object, Object> copyCache,
|
||||
SharedSessionContractImplementor session) {
|
||||
final ArrayList<Object> targetList = new ArrayList<>( list.size() );
|
||||
for ( Object obj : list ) {
|
||||
targetList.add( elemType.replace( obj, null, session, owner, copyCache ) );
|
||||
}
|
||||
return targetList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -632,86 +634,112 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
final Object owner,
|
||||
final Map<Object, Object> copyCache) throws HibernateException {
|
||||
if ( original == null ) {
|
||||
if ( target == null ) {
|
||||
return null;
|
||||
}
|
||||
if ( target instanceof Collection<?> collection ) {
|
||||
collection.clear();
|
||||
return collection;
|
||||
}
|
||||
else if ( target instanceof Map<?,?> map ) {
|
||||
map.clear();
|
||||
return map;
|
||||
}
|
||||
else {
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
final PersistentCollection<?> collectionHolder = persistenceContext
|
||||
.getCollectionHolder( target );
|
||||
if ( collectionHolder != null ) {
|
||||
if ( collectionHolder instanceof PersistentArrayHolder<?> persistentArrayHolder ) {
|
||||
persistenceContext.removeCollectionHolder( target );
|
||||
persistentArrayHolder.beginRead();
|
||||
persistentArrayHolder.injectLoadedState( persistenceContext.getCollectionEntry( collectionHolder ).getLoadedPersister().getAttributeMapping(), null );
|
||||
persistentArrayHolder.endRead();
|
||||
persistentArrayHolder.dirty();
|
||||
persistenceContext.addCollectionHolder( collectionHolder );
|
||||
return persistentArrayHolder.getArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return replaceNullOriginal( target, session );
|
||||
}
|
||||
if ( !Hibernate.isInitialized( original ) ) {
|
||||
if ( ( (PersistentCollection<?>) original ).hasQueuedOperations() ) {
|
||||
if ( original == target ) {
|
||||
// A managed entity with an uninitialized collection is being merged,
|
||||
// We need to replace any detached entities in the queued operations
|
||||
// with managed copies.
|
||||
final AbstractPersistentCollection<?> pc = (AbstractPersistentCollection<?>) original;
|
||||
pc.replaceQueuedOperationValues( getPersister( session ), copyCache );
|
||||
}
|
||||
else {
|
||||
// original is a detached copy of the collection;
|
||||
// it contains queued operations, which will be ignored
|
||||
LOG.ignoreQueuedOperationsOnMerge(
|
||||
MessageHelper.collectionInfoString(
|
||||
getRole(),
|
||||
( (PersistentCollection<?>) original ).getKey()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
else if ( !Hibernate.isInitialized( original ) ) {
|
||||
return replaceUninitializedOriginal( original, target, session, copyCache );
|
||||
}
|
||||
else {
|
||||
return replaceOriginal( original, target, session, owner, copyCache );
|
||||
}
|
||||
}
|
||||
|
||||
// for a null target, or a target which is the same as the original, we
|
||||
// need to put the merged elements in a new collection
|
||||
Object result = ( target == null ||
|
||||
target == original ||
|
||||
target == UNFETCHED_PROPERTY ||
|
||||
target instanceof PersistentCollection
|
||||
&& ( (PersistentCollection<?>) target ).isWrapper( original ) )
|
||||
? instantiateResult( original ) : target;
|
||||
private Object replaceOriginal(
|
||||
Object original, Object target,
|
||||
SharedSessionContractImplementor session,
|
||||
Object owner,
|
||||
Map<Object, Object> copyCache) {
|
||||
|
||||
//for arrays, replaceElements() may return a different reference, since
|
||||
//the array length might not match
|
||||
result = replaceElements( original, result, owner, copyCache, session );
|
||||
|
||||
final Object result =
|
||||
replaceElements( original,
|
||||
instantiateResultIfNecessary( original, target ),
|
||||
owner, copyCache, session );
|
||||
if ( original == target ) {
|
||||
// get the elements back into the target making sure to handle dirty flag
|
||||
boolean wasClean = target instanceof PersistentCollection
|
||||
&& !( (PersistentCollection<?>) target ).isDirty();
|
||||
final boolean wasClean =
|
||||
target instanceof PersistentCollection<?> collection
|
||||
&& !collection.isDirty();
|
||||
//TODO: this is a little inefficient, don't need to do a whole
|
||||
// deep replaceElements() call
|
||||
replaceElements( result, target, owner, copyCache, session );
|
||||
if ( wasClean ) {
|
||||
( (PersistentCollection<?>) target ).clearDirty();
|
||||
((PersistentCollection<?>) target).clearDirty();
|
||||
}
|
||||
result = target;
|
||||
return target;
|
||||
}
|
||||
else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
private Object instantiateResultIfNecessary(Object original, Object target) {
|
||||
// for a null target, or a target which is the same as the original,
|
||||
// we need to put the merged elements in a new collection
|
||||
return target == null
|
||||
|| target == original
|
||||
|| target == UNFETCHED_PROPERTY
|
||||
|| target instanceof PersistentCollection<?> collection && collection.isWrapper( original )
|
||||
? instantiateResult( original )
|
||||
: target;
|
||||
}
|
||||
|
||||
private Object replaceUninitializedOriginal(
|
||||
Object original,
|
||||
Object target,
|
||||
SharedSessionContractImplementor session,
|
||||
Map<Object, Object> copyCache) {
|
||||
final PersistentCollection<?> persistentCollection = (PersistentCollection<?>) original;
|
||||
if ( persistentCollection.hasQueuedOperations() ) {
|
||||
if ( original == target ) {
|
||||
// A managed entity with an uninitialized collection is being merged,
|
||||
// We need to replace any detached entities in the queued operations
|
||||
// with managed copies.
|
||||
final AbstractPersistentCollection<?> pc = (AbstractPersistentCollection<?>) original;
|
||||
pc.replaceQueuedOperationValues( getPersister( session ), copyCache );
|
||||
}
|
||||
else {
|
||||
// original is a detached copy of the collection;
|
||||
// it contains queued operations, which will be ignored
|
||||
LOG.ignoreQueuedOperationsOnMerge(
|
||||
collectionInfoString( getRole(), persistentCollection.getKey() ) );
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private static Object replaceNullOriginal(Object target, SharedSessionContractImplementor session) {
|
||||
if ( target == null ) {
|
||||
return null;
|
||||
}
|
||||
else if ( target instanceof Collection<?> collection ) {
|
||||
collection.clear();
|
||||
return collection;
|
||||
}
|
||||
else if ( target instanceof Map<?,?> map ) {
|
||||
map.clear();
|
||||
return map;
|
||||
}
|
||||
else {
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
final PersistentCollection<?> collectionHolder = persistenceContext.getCollectionHolder( target );
|
||||
if ( collectionHolder != null ) {
|
||||
if ( collectionHolder instanceof PersistentArrayHolder<?> arrayHolder ) {
|
||||
persistenceContext.removeCollectionHolder( target );
|
||||
arrayHolder.beginRead();
|
||||
final PluralAttributeMapping attributeMapping =
|
||||
persistenceContext.getCollectionEntry( collectionHolder )
|
||||
.getLoadedPersister().getAttributeMapping();
|
||||
arrayHolder.injectLoadedState( attributeMapping, null );
|
||||
arrayHolder.endRead();
|
||||
arrayHolder.dirty();
|
||||
persistenceContext.addCollectionHolder( collectionHolder );
|
||||
return arrayHolder.getArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -739,65 +767,58 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
* @return The collection
|
||||
*/
|
||||
public Object getCollection(Object key, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) {
|
||||
|
||||
final CollectionPersister persister = getPersister( session );
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
|
||||
final CollectionKey collectionKey = new CollectionKey( persister, key );
|
||||
PersistentCollection<?> collection = null;
|
||||
|
||||
// check if collection is currently being loaded
|
||||
final LoadingCollectionEntry loadingCollectionEntry = persistenceContext.getLoadContexts().findLoadingCollectionEntry( collectionKey );
|
||||
if ( loadingCollectionEntry != null ) {
|
||||
collection = loadingCollectionEntry.getCollectionInstance();
|
||||
}
|
||||
|
||||
final LoadingCollectionEntry loadingCollectionEntry =
|
||||
persistenceContext.getLoadContexts().findLoadingCollectionEntry( collectionKey );
|
||||
PersistentCollection<?> collection =
|
||||
loadingCollectionEntry == null ? null
|
||||
: loadingCollectionEntry.getCollectionInstance();
|
||||
if ( collection == null ) {
|
||||
|
||||
// check if it is already completely loaded, but unowned
|
||||
collection = persistenceContext.useUnownedCollection( collectionKey );
|
||||
|
||||
if ( collection == null ) {
|
||||
|
||||
collection = persistenceContext.getCollection( collectionKey );
|
||||
|
||||
if ( collection == null ) {
|
||||
// create a new collection wrapper, to be initialized later
|
||||
collection = instantiate( session, persister, key );
|
||||
|
||||
collection.setOwner( owner );
|
||||
|
||||
persistenceContext.addUninitializedCollection( persister, collection, key );
|
||||
|
||||
// some collections are not lazy:
|
||||
boolean eager = overridingEager != null ? overridingEager : !persister.isLazy();
|
||||
if ( initializeImmediately() ) {
|
||||
session.initializeCollection( collection, false );
|
||||
}
|
||||
else if ( eager ) {
|
||||
persistenceContext.addNonLazyCollection( collection );
|
||||
}
|
||||
|
||||
if ( hasHolder() ) {
|
||||
persistenceContext.addCollectionHolder( collection );
|
||||
}
|
||||
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracef( "Created collection wrapper: %s",
|
||||
MessageHelper.collectionInfoString( persister, collection,
|
||||
key, session ) );
|
||||
}
|
||||
// we have already set the owner so we can just return the value
|
||||
return collection.getValue();
|
||||
return createNewWrapper( key, owner, overridingEager, persister, session ).getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collection.setOwner( owner );
|
||||
|
||||
return collection.getValue();
|
||||
}
|
||||
|
||||
private PersistentCollection<?> createNewWrapper(
|
||||
Object key,
|
||||
Object owner,
|
||||
Boolean overridingEager,
|
||||
CollectionPersister persister,
|
||||
SharedSessionContractImplementor session) {
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
final PersistentCollection<?> collection = instantiate( session, persister, key );
|
||||
collection.setOwner( owner );
|
||||
persistenceContext.addUninitializedCollection( persister, collection, key );
|
||||
// some collections are not lazy:
|
||||
if ( initializeImmediately() ) {
|
||||
session.initializeCollection( collection, false );
|
||||
}
|
||||
else if ( overridingEager != null ? overridingEager : !persister.isLazy() ) {
|
||||
persistenceContext.addNonLazyCollection( collection );
|
||||
}
|
||||
if ( hasHolder() ) {
|
||||
persistenceContext.addCollectionHolder( collection );
|
||||
}
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracef( "Created collection wrapper: %s",
|
||||
collectionInfoString( persister, collection, key, session ) );
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
public boolean hasHolder() {
|
||||
return false;
|
||||
}
|
||||
|
@ -823,6 +844,6 @@ public abstract class CollectionType extends AbstractType implements Association
|
|||
|
||||
@Override
|
||||
public boolean[] toColumnNullness(Object value, MappingContext mapping) {
|
||||
return ArrayHelper.EMPTY_BOOLEAN_ARRAY;
|
||||
return EMPTY_BOOLEAN_ARRAY;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue