Fix empty collection not initialized

This commit is contained in:
Andrea Boriero 2020-02-13 15:32:02 +00:00 committed by Steve Ebersole
parent 08b08c0d81
commit 436060008b
11 changed files with 94 additions and 34 deletions

View File

@ -129,6 +129,13 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
return result; return result;
} }
@Override
public void initializeEmptyCollection(CollectionPersister persister) {
assert array == null;
array = Array.newInstance( persister.getElementClass(), 0 );
endRead();
}
@Override @Override
public void injectLoadedState(PluralAttributeMapping attributeMapping, List loadingState) { public void injectLoadedState(PluralAttributeMapping attributeMapping, List loadingState) {
assert isInitializing(); assert isInitializing();

View File

@ -260,6 +260,13 @@ public class PersistentBag extends AbstractPersistentCollection implements List
return getOrphans( sn, bag, entityName, getSession() ); return getOrphans( sn, bag, entityName, getSession() );
} }
@Override
public void initializeEmptyCollection(CollectionPersister persister) {
assert bag == null;
bag = (List) persister.getCollectionType().instantiate( 0 );
endRead();
}
@Override @Override
public Object disassemble(CollectionPersister persister) { public Object disassemble(CollectionPersister persister) {
final int length = bag.size(); final int length = bag.size();
@ -294,7 +301,6 @@ public class PersistentBag extends AbstractPersistentCollection implements List
return !persister.isOneToMany(); return !persister.isOneToMany();
} }
// For a one-to-many, a <bag> is not really a bag; // For a one-to-many, a <bag> is not really a bag;
// it is *really* a set, since it can't contain the // it is *really* a set, since it can't contain the
// same element twice. It could be considered a bug // same element twice. It could be considered a bug

View File

@ -372,6 +372,14 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
return getOrphans( sn.values(), values, entityName, getSession() ); return getOrphans( sn.values(), values, entityName, getSession() );
} }
@Override
public void initializeEmptyCollection(CollectionPersister persister) {
assert identifiers == null;
identifiers = new HashMap<>();
values = new ArrayList<>();
endRead();
}
@Override @Override
public void preInsert(CollectionPersister persister) throws HibernateException { public void preInsert(CollectionPersister persister) throws HibernateException {
final Iterator itr = values.iterator(); final Iterator itr = values.iterator();

View File

@ -98,6 +98,13 @@ public class PersistentList extends AbstractPersistentCollection implements List
return getOrphans( sn, list, entityName, getSession() ); return getOrphans( sn, list, entityName, getSession() );
} }
@Override
public void initializeEmptyCollection(CollectionPersister persister) {
assert list == null;
list = (List) persister.getCollectionType().instantiate( 0 );
endRead();
}
@Override @Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException { public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
final Type elementType = persister.getElementType(); final Type elementType = persister.getElementType();

View File

@ -109,6 +109,13 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
return getOrphans( sn.values(), map.values(), entityName, getSession() ); return getOrphans( sn.values(), map.values(), entityName, getSession() );
} }
@Override
public void initializeEmptyCollection(CollectionPersister persister) {
assert map == null;
map = (Map) persister.getCollectionType().instantiate( 0 );
endRead();
}
@Override @Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException { public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
final Type elementType = persister.getElementType(); final Type elementType = persister.getElementType();

View File

@ -113,6 +113,13 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
return getOrphans( sn.keySet(), set, entityName, getSession() ); return getOrphans( sn.keySet(), set, entityName, getSession() );
} }
@Override
public void initializeEmptyCollection(CollectionPersister persister) {
assert set == null;
set = (Set) persister.getCollectionType().instantiate( 0 );
endRead();
}
@Override @Override
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException { public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
final Type elementType = persister.getElementType(); final Type elementType = persister.getElementType();

View File

@ -447,4 +447,6 @@ public interface PersistentCollection {
* @return The orphans * @return The orphans
*/ */
Collection getOrphans(Serializable snapshot, String entityName); Collection getOrphans(Serializable snapshot, String entityName);
void initializeEmptyCollection(CollectionPersister persister);
} }

View File

@ -72,6 +72,7 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
LOG.trace( "Collection not cached" ); LOG.trace( "Collection not cached" );
} }
ceLoadedPersister.initialize( ce.getLoadedKey(), source ); ceLoadedPersister.initialize( ce.getLoadedKey(), source );
handlePotentiallyEmptyCollection( collection, source, ce, ceLoadedPersister );
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.trace( "Collection initialized" ); LOG.trace( "Collection initialized" );
} }
@ -86,6 +87,21 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
} }
} }
private void handlePotentiallyEmptyCollection(
PersistentCollection collection,
SessionImplementor source,
CollectionEntry ce, CollectionPersister ceLoadedPersister) {
if ( !collection.wasInitialized() ) {
collection.initializeEmptyCollection( ceLoadedPersister );
org.hibernate.sql.results.internal.Helper.finalizeCollectionLoading(
source.getPersistenceContext(),
ceLoadedPersister,
collection,
ce.getLoadedKey()
);
}
}
/** /**
* Try to initialize a collection from the cache * Try to initialize a collection from the cache
* *

View File

@ -10,7 +10,12 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.BatchFetchQueue;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.ResultsLogger; import org.hibernate.sql.results.ResultsLogger;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
@ -58,4 +63,31 @@ public class Helper {
} }
} }
public static void finalizeCollectionLoading(
PersistenceContext persistenceContext,
CollectionPersister collectionDescriptor,
PersistentCollection collectionInstance,
Object key) {
CollectionEntry collectionEntry = persistenceContext.getCollectionEntry( collectionInstance );
if ( collectionEntry == null ) {
collectionEntry = persistenceContext.addInitializedCollection(
collectionDescriptor,
collectionInstance,
key
);
}
else {
collectionEntry.postInitialize( collectionInstance );
}
if ( collectionDescriptor.getCollectionType().hasHolder() ) {
persistenceContext.addCollectionHolder( collectionInstance );
}
final BatchFetchQueue batchFetchQueue = persistenceContext.getBatchFetchQueue();
batchFetchQueue.removeBatchLoadableCollection( collectionEntry );
// todo (6.0) : there is other logic still needing to be implemented here. caching, etc
// see org.hibernate.engine.loading.internal.CollectionLoadContext#endLoadingCollection in 5.x
}
} }

View File

@ -11,10 +11,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.collection.internal.PersistentArrayHolder;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.BatchFetchQueue;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
@ -90,27 +87,7 @@ public class LoadingCollectionEntryImpl implements LoadingCollectionEntry {
final PersistenceContext persistenceContext = session.getPersistenceContext(); final PersistenceContext persistenceContext = session.getPersistenceContext();
final CollectionPersister collectionDescriptor = getCollectionDescriptor(); final CollectionPersister collectionDescriptor = getCollectionDescriptor();
CollectionEntry collectionEntry = persistenceContext.getCollectionEntry( collectionInstance ); Helper.finalizeCollectionLoading( persistenceContext, collectionDescriptor, collectionInstance, getKey() );
if ( collectionEntry == null ) {
collectionEntry = persistenceContext.addInitializedCollection(
collectionDescriptor,
getCollectionInstance(),
getKey()
);
}
else {
collectionEntry.postInitialize( collectionInstance );
}
if ( collectionDescriptor.getCollectionType().hasHolder() ) {
persistenceContext.addCollectionHolder( collectionInstance );
}
final BatchFetchQueue batchFetchQueue = persistenceContext.getBatchFetchQueue();
batchFetchQueue.removeBatchLoadableCollection( collectionEntry );
// todo (6.0) : there is other logic still needing to be implemented here. caching, etc
// see org.hibernate.engine.loading.internal.CollectionLoadContext#endLoadingCollection in 5.x
} }
@Override @Override

View File

@ -13,7 +13,6 @@ import org.hibernate.query.named.RowReaderMemento;
import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.graph.collection.CollectionInitializer; import org.hibernate.sql.results.graph.collection.CollectionInitializer;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.Initializer;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
@ -52,14 +51,6 @@ public class StandardRowReader<T> implements RowReader<T> {
this.callback = callback; this.callback = callback;
this.resultRow = new Object[assemblerCount]; this.resultRow = new Object[assemblerCount];
for ( int i = 0; i < initializers.size(); i++ ) {
final Initializer initializer = initializers.get( i );
if ( initializer instanceof EntityInitializer ) {
final EntityInitializer entityInitializer = (EntityInitializer) initializer;
}
}
} }
@Override @Override