ref #9204 uncritical updates to AbstractPersistentCollection
authorAndreas Müller <a.mueller@bgbm.org>
Tue, 25 Aug 2020 10:26:00 +0000 (12:26 +0200)
committerAndreas Müller <a.mueller@bgbm.org>
Tue, 25 Aug 2020 10:50:21 +0000 (12:50 +0200)
eu.etaxonomy.taxeditor.cdmlib/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java

index 18101250c9bf197a9495353f5fa9e3fe94be4945..be20e8d87c2b6dafdea9f71dacaa8bb01bdd4d05 100644 (file)
@@ -34,6 +34,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.Map;
 
 import javax.naming.NamingException;
 
@@ -41,6 +42,10 @@ import org.hibernate.AssertionFailure;
 import org.hibernate.HibernateException;
 import org.hibernate.LazyInitializationException;
 import org.hibernate.Session;
+import org.hibernate.collection.internal.AbstractPersistentCollection.DelayedOperation;
+import org.hibernate.collection.internal.AbstractPersistentCollection.IteratorProxy;
+import org.hibernate.collection.internal.AbstractPersistentCollection.ListIteratorProxy;
+import org.hibernate.collection.internal.AbstractPersistentCollection.ValueDelayedOperation;
 import org.hibernate.collection.spi.PersistentCollection;
 import org.hibernate.engine.internal.ForeignKeys;
 import org.hibernate.engine.spi.CollectionEntry;
@@ -56,7 +61,13 @@ import org.hibernate.internal.util.collections.IdentitySet;
 import org.hibernate.persister.collection.CollectionPersister;
 import org.hibernate.persister.entity.EntityPersister;
 import org.hibernate.pretty.MessageHelper;
+import org.hibernate.type.IntegerType;
+import org.hibernate.type.LongType;
+import org.hibernate.type.PostgresUUIDType;
+import org.hibernate.type.StringType;
 import org.hibernate.type.Type;
+import org.hibernate.type.UUIDBinaryType;
+import org.hibernate.type.UUIDCharType;
 import org.jboss.logging.Logger;
 
 import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteConfiguration;
@@ -116,48 +127,56 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
        private String sessionFactoryUuid;
        private boolean specjLazyLoad = false;
 
+       /**
+        * Not called by Hibernate, but used by non-JDK serialization,
+        * eg. SOAP libraries.
+        */
+       public AbstractPersistentCollection() {
+       }
+
+       protected AbstractPersistentCollection(SessionImplementor session) {
+               this.session = session;
+       }
+
        @Override
-    public final String getRole() {
+       public final String getRole() {
                return role;
        }
 
        @Override
-    public final Serializable getKey() {
+       public final Serializable getKey() {
                return key;
        }
 
        @Override
-    public final boolean isUnreferenced() {
+       public final boolean isUnreferenced() {
                return role == null;
        }
 
        @Override
-    public final boolean isDirty() {
+       public final boolean isDirty() {
                return dirty;
        }
 
        @Override
-    public final void clearDirty() {
+       public final void clearDirty() {
                dirty = false;
        }
 
        @Override
-    public final void dirty() {
+       public final void dirty() {
                dirty = true;
        }
 
        @Override
-    public final Serializable getStoredSnapshot() {
+       public final Serializable getStoredSnapshot() {
                return storedSnapshot;
        }
 
        //Careful: these methods do not initialize the collection.
 
-       /**
-        * Is the initialized collection empty?
-        */
        @Override
-    public abstract boolean empty();
+       public abstract boolean empty();
 
        /**
         * Called by any read-only method of the collection interface
@@ -217,7 +236,17 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                return false;
        }
 
+       /**
+        * TBH not sure why this is public
+        *
+        * @param <T> The java type of the return for this LazyInitializationWork
+        */
        public static interface LazyInitializationWork<T> {
+               /**
+                * Do the represented work and return the result.
+                *
+                * @return The result
+                */
                public T doWork();
        }
 
@@ -429,10 +458,14 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                return cachedSize;
        }
 
-       private boolean isConnectedToSession() {
-               return session != null &&
-                               session.isOpen() &&
-                               session.getPersistenceContext().containsCollection( this );
+       protected boolean isConnectedToSession() {
+               return session != null
+                               && session.isOpen()
+                               && session.getPersistenceContext().containsCollection( this );
+       }
+
+       protected boolean isInitialized() {
+               return initialized;
        }
 
        /**
@@ -449,9 +482,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
         */
        @SuppressWarnings({"JavaDoc"})
        protected boolean isOperationQueueEnabled() {
-               return !initialized &&
-                               isConnectedToSession() &&
-                               isInverseCollection();
+               return !initialized
+                               && isConnectedToSession()
+                               && isInverseCollection();
        }
 
        /**
@@ -461,9 +494,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
         */
        @SuppressWarnings({"JavaDoc"})
        protected boolean isPutQueueEnabled() {
-               return !initialized &&
-                               isConnectedToSession() &&
-                               isInverseOneToManyOrNoOrphanDelete();
+               return !initialized
+                               && isConnectedToSession()
+                               && isInverseOneToManyOrNoOrphanDelete();
        }
 
        /**
@@ -473,17 +506,17 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
         */
        @SuppressWarnings({"JavaDoc"})
        protected boolean isClearQueueEnabled() {
-               return !initialized &&
-                               isConnectedToSession() &&
-                               isInverseCollectionNoOrphanDelete();
+               return !initialized
+                               && isConnectedToSession()
+                               && isInverseCollectionNoOrphanDelete();
        }
 
        /**
         * Is this the "inverse" end of a bidirectional association?
         */
        @SuppressWarnings({"JavaDoc"})
-       private boolean isInverseCollection() {
-               CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
+       protected boolean isInverseCollection() {
+               final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
                return ce != null && ce.getLoadedPersister().isInverse();
        }
 
@@ -492,9 +525,10 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
         * no orphan delete enabled?
         */
        @SuppressWarnings({"JavaDoc"})
-       private boolean isInverseCollectionNoOrphanDelete() {
-               CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
-               return ce != null &&
+       protected boolean isInverseCollectionNoOrphanDelete() {
+               final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
+               return ce != null
+                               &&
                                ce.getLoadedPersister().isInverse() &&
                                !ce.getLoadedPersister().hasOrphanDelete();
        }
@@ -504,12 +538,11 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
         * of a collection with no orphan delete?
         */
        @SuppressWarnings({"JavaDoc"})
-       private boolean isInverseOneToManyOrNoOrphanDelete() {
-               CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
-               return ce != null && ce.getLoadedPersister().isInverse() && (
-                               ce.getLoadedPersister().isOneToMany() ||
-                                               !ce.getLoadedPersister().hasOrphanDelete()
-               );
+       protected boolean isInverseOneToManyOrNoOrphanDelete() {
+               final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
+               return ce != null
+                               && ce.getLoadedPersister().isInverse()
+                               && ( ce.getLoadedPersister().isOneToMany() || !ce.getLoadedPersister().hasOrphanDelete() );
        }
 
        /**
@@ -521,7 +554,22 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                        operationQueue = new ArrayList<DelayedOperation>( 10 );
                }
                operationQueue.add( operation );
-               dirty = true; //needed so that we remove this collection from the second-level cache
+               //needed so that we remove this collection from the second-level cache
+               dirty = true;
+       }
+
+       /**
+        * Replace entity instances with copy in {@code copyCache}/.
+        *
+        * @param copyCache - mapping from entity in the process of being
+        *                    merged to managed copy.
+        */
+       public final void replaceQueuedOperationValues(CollectionPersister persister, Map copyCache) {
+               for ( DelayedOperation operation : operationQueue ) {
+                       if ( ValueDelayedOperation.class.isInstance( operation ) ) {
+                               ( (ValueDelayedOperation) operation ).replace( persister, copyCache );
+                       }
+               }
        }
 
        /**
@@ -534,66 +582,39 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                }
        }
 
-       /**
-        * After flushing, re-init snapshot state.
-        */
        @Override
-    public void setSnapshot(Serializable key, String role, Serializable snapshot) {
+       public void setSnapshot(Serializable key, String role, Serializable snapshot) {
                this.key = key;
                this.role = role;
                this.storedSnapshot = snapshot;
        }
 
-       /**
-        * After flushing, clear any "queued" additions, since the
-        * database state is now synchronized with the memory state.
-        */
        @Override
-    public void postAction() {
+       public void postAction() {
                operationQueue = null;
                cachedSize = -1;
                clearDirty();
        }
 
-       /**
-        * Not called by Hibernate, but used by non-JDK serialization,
-        * eg. SOAP libraries.
-        */
-       public AbstractPersistentCollection() {
-       }
-
-       protected AbstractPersistentCollection(SessionImplementor session) {
-               this.session = session;
-       }
-
-       /**
-        * return the user-visible collection (or array) instance
-        */
        @Override
-    public Object getValue() {
+       public Object getValue() {
                return this;
        }
 
-       /**
-        * Called just before reading any rows from the JDBC result set
-        */
        @Override
-    public void beginRead() {
+       public void beginRead() {
                // override on some subclasses
                initializing = true;
        }
 
-       /**
-        * Called after reading all rows from the JDBC result set
-        */
        @Override
-    public boolean endRead() {
+       public boolean endRead() {
                //override on some subclasses
                return afterInitialize();
        }
 
        @Override
-    public boolean afterInitialize() {
+       public boolean afterInitialize() {
                setInitialized();
                //do this bit after setting initialized to true or it will recurse
                if ( operationQueue != null ) {
@@ -663,12 +684,8 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                this.directlyAccessible = directlyAccessible;
        }
 
-       /**
-        * Could the application possibly have a direct reference to
-        * the underlying collection implementation?
-        */
        @Override
-    public boolean isDirectlyAccessible() {
+       public boolean isDirectlyAccessible() {
                return directlyAccessible;
        }
 
@@ -780,48 +797,39 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                return session.getPersistenceContext().getSnapshot( this );
        }
 
-       /**
-        * Is this instance initialized?
-        */
        @Override
-    public final boolean wasInitialized() {
+       public final boolean wasInitialized() {
                return initialized;
        }
 
        @Override
-    public boolean isRowUpdatePossible() {
+       public boolean isRowUpdatePossible() {
                return true;
        }
 
-       /**
-        * Does this instance have any "queued" additions?
-        */
        @Override
-    public final boolean hasQueuedOperations() {
+       public final boolean hasQueuedOperations() {
                return operationQueue != null;
        }
 
-       /**
-        * Iterate the "queued" additions
-        */
        @Override
-    public final Iterator queuedAdditionIterator() {
+       public final Iterator queuedAdditionIterator() {
                if ( hasQueuedOperations() ) {
                        return new Iterator() {
-                               int i = 0;
+                               private int index;
 
                                @Override
-                public Object next() {
-                                       return operationQueue.get( i++ ).getAddedInstance();
+                               public Object next() {
+                                       return operationQueue.get( index++ ).getAddedInstance();
                                }
 
                                @Override
-                public boolean hasNext() {
-                                       return i < operationQueue.size();
+                               public boolean hasNext() {
+                                       return index < operationQueue.size();
                                }
 
                                @Override
-                public void remove() {
+                               public void remove() {
                                        throw new UnsupportedOperationException();
                                }
                        };
@@ -831,15 +839,12 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                }
        }
 
-       /**
-        * Iterate the "queued" additions
-        */
        @Override
-    @SuppressWarnings({"unchecked"})
+       @SuppressWarnings({"unchecked"})
        public final Collection getQueuedOrphans(String entityName) {
                if ( hasQueuedOperations() ) {
-                       Collection additions = new ArrayList( operationQueue.size() );
-                       Collection removals = new ArrayList( operationQueue.size() );
+                       final Collection additions = new ArrayList( operationQueue.size() );
+                       final Collection removals = new ArrayList( operationQueue.size() );
                        for ( DelayedOperation operation : operationQueue ) {
                                additions.add( operation.getAddedInstance() );
                                removals.add( operation.getOrphan() );
@@ -851,31 +856,22 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                }
        }
 
-       /**
-        * Called before inserting rows, to ensure that any surrogate keys
-        * are fully generated
-        */
        @Override
-    public void preInsert(CollectionPersister persister) throws HibernateException {
+       public void preInsert(CollectionPersister persister) throws HibernateException {
        }
 
-       /**
-        * Called after inserting a row, to fetch the natively generated id
-        */
        @Override
-    public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {
+       public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {
        }
 
-       /**
-        * get all "orphaned" elements
-        */
        @Override
-    public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
+       public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
 
        /**
-        * Get the current session
+        * Get the session currently associated with this collection.
+        *
+        * @return The session
         */
-       @SuppressWarnings({"JavaDoc"})
        public final SessionImplementor getSession() {
                return session;
        }
@@ -888,23 +884,22 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                }
 
                @Override
-        public boolean hasNext() {
+               public boolean hasNext() {
                        return itr.hasNext();
                }
 
                @Override
-        public Object next() {
+               public Object next() {
                        return itr.next();
                }
 
                @Override
-        public void remove() {
+               public void remove() {
                        write();
                        itr.remove();
                }
-
        }
-
+       
        protected final class ListIteratorProxy implements ListIterator {
                protected final ListIterator itr;
 
@@ -913,55 +908,54 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                }
 
                @Override
-        @SuppressWarnings({"unchecked"})
+               @SuppressWarnings({"unchecked"})
                public void add(Object o) {
                        write();
                        itr.add( o );
                }
 
                @Override
-        public boolean hasNext() {
+               public boolean hasNext() {
                        return itr.hasNext();
                }
 
                @Override
-        public boolean hasPrevious() {
+               public boolean hasPrevious() {
                        return itr.hasPrevious();
                }
 
                @Override
-        public Object next() {
+               public Object next() {
                        return itr.next();
                }
 
                @Override
-        public int nextIndex() {
+               public int nextIndex() {
                        return itr.nextIndex();
                }
 
                @Override
-        public Object previous() {
+               public Object previous() {
                        return itr.previous();
                }
 
                @Override
-        public int previousIndex() {
+               public int previousIndex() {
                        return itr.previousIndex();
                }
 
                @Override
-        public void remove() {
+               public void remove() {
                        write();
                        itr.remove();
                }
 
                @Override
-        @SuppressWarnings({"unchecked"})
+               @SuppressWarnings({"unchecked"})
                public void set(Object o) {
                        write();
                        itr.set( o );
                }
-
        }
 
        protected class SetProxy implements java.util.Set {
@@ -972,79 +966,81 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                }
 
                @Override
-        @SuppressWarnings({"unchecked"})
+               @SuppressWarnings({"unchecked"})
                public boolean add(Object o) {
                        write();
                        return set.add( o );
                }
 
                @Override
-        @SuppressWarnings({"unchecked"})
+               @SuppressWarnings({"unchecked"})
                public boolean addAll(Collection c) {
                        write();
                        return set.addAll( c );
                }
 
                @Override
-        public void clear() {
+               public void clear() {
                        write();
                        set.clear();
                }
 
                @Override
-        public boolean contains(Object o) {
+               public boolean contains(Object o) {
                        return set.contains( o );
                }
 
                @Override
-        public boolean containsAll(Collection c) {
+               @SuppressWarnings("unchecked")
+               public boolean containsAll(Collection c) {
                        return set.containsAll( c );
                }
 
                @Override
-        public boolean isEmpty() {
+               public boolean isEmpty() {
                        return set.isEmpty();
                }
 
                @Override
-        public Iterator iterator() {
+               public Iterator iterator() {
                        return new IteratorProxy( set.iterator() );
                }
 
                @Override
-        public boolean remove(Object o) {
+               public boolean remove(Object o) {
                        write();
                        return set.remove( o );
                }
 
                @Override
-        public boolean removeAll(Collection c) {
+               @SuppressWarnings("unchecked")
+               public boolean removeAll(Collection c) {
                        write();
                        return set.removeAll( c );
                }
 
                @Override
-        public boolean retainAll(Collection c) {
+               @SuppressWarnings("unchecked")
+               public boolean retainAll(Collection c) {
                        write();
                        return set.retainAll( c );
                }
 
                @Override
-        public int size() {
+               public int size() {
                        return set.size();
                }
 
                @Override
-        public Object[] toArray() {
+               public Object[] toArray() {
                        return set.toArray();
                }
 
                @Override
-        @SuppressWarnings({"unchecked"})
+               @SuppressWarnings({"unchecked"})
                public Object[] toArray(Object[] array) {
                        return set.toArray( array );
                }
-
        }
 
        protected final class ListProxy implements java.util.List {
@@ -1094,6 +1090,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                }
 
                @Override
+               @SuppressWarnings("unchecked")
                public boolean containsAll(Collection c) {
                        return list.containsAll( c );
                }
@@ -1146,12 +1143,14 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                }
 
                @Override
+               @SuppressWarnings("unchecked")
                public boolean removeAll(Collection c) {
                        write();
                        return list.removeAll( c );
                }
 
                @Override
+               @SuppressWarnings("unchecked")
                public boolean retainAll(Collection c) {
                        write();
                        return list.retainAll( c );
@@ -1197,6 +1196,40 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
 
                public Object getOrphan();
        }
+       
+       protected interface ValueDelayedOperation extends DelayedOperation {
+               void replace(CollectionPersister collectionPersister, Map copyCache);
+       }
+       
+       protected abstract class AbstractValueDelayedOperation implements ValueDelayedOperation {
+               private Object addedValue;
+               private Object orphan;
+
+               protected AbstractValueDelayedOperation(Object addedValue, Object orphan) {
+                       this.addedValue = addedValue;
+                       this.orphan = orphan;
+               }
+
+               public void replace(CollectionPersister persister, Map copyCache) {
+                       if ( addedValue != null ) {
+                               addedValue = getReplacement( persister.getElementType(), addedValue, copyCache );
+                       }
+               }
+
+               protected final Object getReplacement(Type type, Object current, Map copyCache) {
+                       return type.replace( current, null, session, owner, copyCache );
+               }
+
+               @Override
+               public final Object getAddedInstance() {
+                       return addedValue;
+               }
+
+               @Override
+               public final Object getOrphan() {
+                       return orphan;
+               }
+       }
 
        /**
         * Given a collection of entity instances that used to
@@ -1257,6 +1290,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
                return res;
        }
 
+       private static boolean mayUseIdDirect(Type idType) {
+               return idType == StringType.INSTANCE
+                       || idType == IntegerType.INSTANCE
+                       || idType == LongType.INSTANCE
+                       || idType == UUIDBinaryType.INSTANCE
+                       || idType == UUIDCharType.INSTANCE
+                       || idType == PostgresUUIDType.INSTANCE;
+       }
+
        public static void identityRemove(
                        Collection list,
                        Object object,
@@ -1281,17 +1323,17 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
        }
 
        @Override
-    public Object getIdentifier(Object entry, int i) {
+       public Object getIdentifier(Object entry, int i) {
                throw new UnsupportedOperationException();
        }
 
        @Override
-    public Object getOwner() {
+       public Object getOwner() {
                return owner;
        }
 
        @Override
-    public void setOwner(Object owner) {
+       public void setOwner(Object owner) {
                this.owner = owner;
        }