HHH-15522 Implement a LazyInitializable interface that PersistentCollection and Envers collections extend or implement. Improve related tests.

This commit is contained in:
Fabricio Gregorio 2022-09-17 18:55:26 -03:00 committed by Yoann Rodière
parent e218b8f127
commit 1987d699ed
9 changed files with 110 additions and 56 deletions

View File

@ -20,6 +20,7 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.LazyInitializer;
import org.hibernate.collection.spi.LazyInitializable;
/** /**
* <ul> * <ul>
@ -61,8 +62,8 @@ public final class Hibernate {
if ( proxy instanceof HibernateProxy ) { if ( proxy instanceof HibernateProxy ) {
( (HibernateProxy) proxy ).getHibernateLazyInitializer().initialize(); ( (HibernateProxy) proxy ).getHibernateLazyInitializer().initialize();
} }
else if ( proxy instanceof PersistentCollection ) { else if ( proxy instanceof LazyInitializable ) {
( (PersistentCollection) proxy ).forceInitialization(); ( (LazyInitializable) proxy ).forceInitialization();
} }
else if ( proxy instanceof PersistentAttributeInterceptable ) { else if ( proxy instanceof PersistentAttributeInterceptable ) {
final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) proxy; final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) proxy;
@ -91,8 +92,8 @@ public final class Hibernate {
} }
return true; return true;
} }
else if ( proxy instanceof PersistentCollection ) { else if ( proxy instanceof LazyInitializable ) {
return ( (PersistentCollection) proxy ).wasInitialized(); return ( (LazyInitializable) proxy ).wasInitialized();
} }
else { else {
return true; return true;

View File

@ -0,0 +1,33 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.collection.spi;
import org.hibernate.Incubating;
/**
* Hibernate "wraps" a java collection in an instance of PersistentCollection. Envers uses custom collection
* wrappers (ListProxy, SetProxy, etc). All of them need to extend LazyInitializable, so the
* Hibernate.isInitialized method can check if the collection is initialized or not.
*
* @author Fabricio Gregorio
*/
@Incubating
public interface LazyInitializable {
/**
* Is this instance initialized?
*
* @return Was this collection initialized? Or is its data still not (fully) loaded?
*/
boolean wasInitialized();
/**
* To be called internally by the session, forcing immediate initialization.
*/
void forceInitialization();
}

View File

@ -45,7 +45,7 @@ import org.hibernate.type.Type;
* *
* @author Gavin King * @author Gavin King
*/ */
public interface PersistentCollection { public interface PersistentCollection extends LazyInitializable {
/** /**
* Get the owning entity. Note that the owner is only * Get the owning entity. Note that the owner is only
* set during the flush cycle, and when a new collection * set during the flush cycle, and when a new collection
@ -271,11 +271,6 @@ public interface PersistentCollection {
*/ */
Serializable getSnapshot(CollectionPersister persister); Serializable getSnapshot(CollectionPersister persister);
/**
* To be called internally by the session, forcing immediate initialization.
*/
void forceInitialization();
/** /**
* Does the given element/entry exist in the collection? * Does the given element/entry exist in the collection?
* *
@ -335,13 +330,6 @@ public interface PersistentCollection {
*/ */
boolean isWrapper(Object collection); boolean isWrapper(Object collection);
/**
* Is this instance initialized?
*
* @return Was this collection initialized? Or is its data still not (fully) loaded?
*/
boolean wasInitialized();
/** /**
* Does this instance have any "queued" operations? * Does this instance have any "queued" operations?
* *

View File

@ -9,13 +9,15 @@ package org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import org.hibernate.collection.spi.LazyInitializable;
import org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor; import org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public abstract class CollectionProxy<U, T extends Collection<U>> implements Collection<U>, Serializable { public abstract class CollectionProxy<U, T extends Collection<U>> implements Collection<U>, LazyInitializable, Serializable {
private static final long serialVersionUID = 8698249863871832402L; private static final long serialVersionUID = 8698249863871832402L;
private transient org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor<T> initializor; private transient org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor<T> initializor;
@ -34,6 +36,16 @@ public abstract class CollectionProxy<U, T extends Collection<U>> implements Col
} }
} }
@Override
public final boolean wasInitialized() {
return delegate != null;
}
@Override
public final void forceInitialization() {
checkInit();
}
@Override @Override
public int size() { public int size() {
checkInit(); checkInit();
@ -118,7 +130,7 @@ public abstract class CollectionProxy<U, T extends Collection<U>> implements Col
return delegate.toString(); return delegate.toString();
} }
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"}) @SuppressWarnings({ "EqualsWhichDoesntCheckParameterClass" })
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
checkInit(); checkInit();

View File

@ -10,13 +10,14 @@ import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hibernate.collection.spi.LazyInitializable;
import org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor; import org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class MapProxy<K, V> implements Map<K, V>, Serializable { public class MapProxy<K, V> implements Map<K, V>, LazyInitializable, Serializable {
private static final long serialVersionUID = 8418037541773074646L; private static final long serialVersionUID = 8418037541773074646L;
private transient Initializor<Map<K, V>> initializor; private transient Initializor<Map<K, V>> initializor;
@ -35,6 +36,16 @@ public class MapProxy<K, V> implements Map<K, V>, Serializable {
} }
} }
@Override
public final boolean wasInitialized() {
return delegate != null;
}
@Override
public final void forceInitialization() {
checkInit();
}
@Override @Override
public int size() { public int size() {
checkInit(); checkInit();
@ -114,7 +125,7 @@ public class MapProxy<K, V> implements Map<K, V>, Serializable {
} }
@Override @Override
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"}) @SuppressWarnings({ "EqualsWhichDoesntCheckParameterClass" })
public boolean equals(Object obj) { public boolean equals(Object obj) {
checkInit(); checkInit();
return delegate.equals( obj ); return delegate.equals( obj );

View File

@ -12,13 +12,14 @@ import java.util.Comparator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import org.hibernate.collection.spi.LazyInitializable;
import org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor; import org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
*/ */
public class SortedMapProxy<K, V> implements SortedMap<K, V>, Serializable { public class SortedMapProxy<K, V> implements SortedMap<K, V>, LazyInitializable, Serializable {
private static final long serialVersionUID = 2645817952901452375L; private static final long serialVersionUID = 2645817952901452375L;
private transient Initializor<SortedMap<K, V>> initializor; private transient Initializor<SortedMap<K, V>> initializor;
@ -37,6 +38,16 @@ public class SortedMapProxy<K, V> implements SortedMap<K, V>, Serializable {
} }
} }
@Override
public final boolean wasInitialized() {
return delegate != null;
}
@Override
public final void forceInitialization() {
checkInit();
}
@Override @Override
public int size() { public int size() {
checkInit(); checkInit();
@ -146,7 +157,7 @@ public class SortedMapProxy<K, V> implements SortedMap<K, V>, Serializable {
} }
@Override @Override
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"}) @SuppressWarnings({ "EqualsWhichDoesntCheckParameterClass" })
public boolean equals(Object o) { public boolean equals(Object o) {
checkInit(); checkInit();
return delegate.equals( o ); return delegate.equals( o );

View File

@ -7,8 +7,9 @@
package org.hibernate.envers.test.entities.collection; package org.hibernate.envers.test.entities.collection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import javax.persistence.CascadeType; import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
@ -26,6 +27,7 @@ import org.hibernate.envers.Audited;
@Entity @Entity
@Audited @Audited
public class MultipleCollectionEntity { public class MultipleCollectionEntity {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", length = 10) @Column(name = "ID", length = 10)
@ -65,7 +67,7 @@ public class MultipleCollectionEntity {
} }
public List<MultipleCollectionRefEntity1> getRefEntities1() { public List<MultipleCollectionRefEntity1> getRefEntities1() {
return Collections.unmodifiableList( refEntities1 ); return refEntities1;
} }
public void addRefEntity1(MultipleCollectionRefEntity1 refEntity1) { public void addRefEntity1(MultipleCollectionRefEntity1 refEntity1) {
@ -77,7 +79,7 @@ public class MultipleCollectionEntity {
} }
public List<MultipleCollectionRefEntity2> getRefEntities2() { public List<MultipleCollectionRefEntity2> getRefEntities2() {
return Collections.unmodifiableList( refEntities2 ); return refEntities2;
} }
public void addRefEntity2(MultipleCollectionRefEntity2 refEntity2) { public void addRefEntity2(MultipleCollectionRefEntity2 refEntity2) {
@ -110,34 +112,20 @@ public class MultipleCollectionEntity {
} }
@Override @Override
public boolean equals(Object o) { public int hashCode() {
if ( this == o ) { return Objects.hash( id );
return true;
}
if ( !(o instanceof MultipleCollectionEntity) ) {
return false;
}
MultipleCollectionEntity that = (MultipleCollectionEntity) o;
if ( refEntities1 != null ? !refEntities1.equals( that.refEntities1 ) : that.refEntities1 != null ) {
return false;
}
if ( refEntities2 != null ? !refEntities2.equals( that.refEntities2 ) : that.refEntities2 != null ) {
return false;
}
if ( text != null ? !text.equals( that.text ) : that.text != null ) {
return false;
}
return true;
} }
@Override @Override
public int hashCode() { public boolean equals(Object obj) {
int result = text != null ? text.hashCode() : 0; if ( this == obj )
result = 31 * result + (refEntities1 != null ? refEntities1.hashCode() : 0); return true;
result = 31 * result + (refEntities2 != null ? refEntities2.hashCode() : 0); if ( obj == null )
return result; return false;
if ( getClass() != obj.getClass() )
return false;
MultipleCollectionEntity other = (MultipleCollectionEntity) obj;
return Objects.equals( id, other.id );
} }
} }

View File

@ -77,6 +77,7 @@ public class IsCollectionInitializedBytecodeEnhancementTest extends BaseEnversJP
} }
@Test @Test
@SuppressWarnings("unchecked")
public void testIsInitialized() { public void testIsInitialized() {
EntityManager em = getEntityManager(); EntityManager em = getEntityManager();
@ -89,5 +90,9 @@ public class IsCollectionInitializedBytecodeEnhancementTest extends BaseEnversJP
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), false ); assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), false );
Hibernate.initialize(ret.getRefEntities1());
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), true );
} }
} }

View File

@ -72,6 +72,7 @@ public class IsCollectionInitializedTest extends BaseEnversJPAFunctionalTestCase
} }
@Test @Test
@SuppressWarnings("unchecked")
public void testIsInitialized() { public void testIsInitialized() {
EntityManager em = getEntityManager(); EntityManager em = getEntityManager();
@ -84,5 +85,9 @@ public class IsCollectionInitializedTest extends BaseEnversJPAFunctionalTestCase
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), false ); assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), false );
Hibernate.initialize(ret.getRefEntities1());
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), true );
} }
} }