HHH-15522 Implement a LazyInitializable interface that PersistentCollection and Envers collections extend or implement. Improve related tests.
This commit is contained in:
parent
c3f1762f3b
commit
4ac2054784
|
@ -34,6 +34,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Various utility functions for working with proxies and lazy collection references.
|
* Various utility functions for working with proxies and lazy collection references.
|
||||||
|
@ -85,8 +86,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;
|
||||||
|
@ -111,8 +112,8 @@ public final class Hibernate {
|
||||||
final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) proxy ).$$_hibernate_getInterceptor();
|
final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) proxy ).$$_hibernate_getInterceptor();
|
||||||
return !(interceptor instanceof EnhancementAsProxyLazinessInterceptor);
|
return !(interceptor instanceof EnhancementAsProxyLazinessInterceptor);
|
||||||
}
|
}
|
||||||
else if ( proxy instanceof PersistentCollection ) {
|
else if ( proxy instanceof LazyInitializable ) {
|
||||||
return ( (PersistentCollection<?>) proxy ).wasInitialized();
|
return ( (LazyInitializable) proxy ).wasInitialized();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ import org.hibernate.type.Type;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
public interface PersistentCollection<E> {
|
public interface PersistentCollection<E> 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
|
||||||
|
@ -211,11 +211,6 @@ public interface PersistentCollection<E> {
|
||||||
*/
|
*/
|
||||||
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?
|
||||||
*
|
*
|
||||||
|
@ -280,13 +275,6 @@ public interface PersistentCollection<E> {
|
||||||
*/
|
*/
|
||||||
boolean isInitializing();
|
boolean isInitializing();
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this instance initialized?
|
|
||||||
*
|
|
||||||
* @return Was this collection initialized? Or is its data still not (fully) loaded?
|
|
||||||
*/
|
|
||||||
boolean wasInitialized();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called prior to the initialization of this yet-uninitialized collection. Pairs
|
* Called prior to the initialization of this yet-uninitialized collection. Pairs
|
||||||
* with {@link #afterInitialize}
|
* with {@link #afterInitialize}
|
||||||
|
|
|
@ -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 Initializor<T> initializor;
|
private transient 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();
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.orm.test.envers.entities.collection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
|
@ -26,6 +28,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 +68,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 +80,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 +113,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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
@ -88,6 +89,10 @@ public class IsCollectionInitializedBytecodeEnhancementTest extends BaseEnversJP
|
||||||
MultipleCollectionEntity ret = res.get( 0 );
|
MultipleCollectionEntity ret = res.get( 0 );
|
||||||
|
|
||||||
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), false );
|
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), false );
|
||||||
|
|
||||||
|
Hibernate.initialize(ret.getRefEntities1());
|
||||||
|
|
||||||
|
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), true );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
@ -81,8 +82,12 @@ public class IsCollectionInitializedTest extends BaseEnversJPAFunctionalTestCase
|
||||||
.getResultList();
|
.getResultList();
|
||||||
|
|
||||||
MultipleCollectionEntity ret = res.get( 0 );
|
MultipleCollectionEntity ret = res.get( 0 );
|
||||||
|
|
||||||
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), false );
|
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), false );
|
||||||
|
|
||||||
|
Hibernate.initialize(ret.getRefEntities1());
|
||||||
|
|
||||||
|
assertEquals( Hibernate.isInitialized( ret.getRefEntities1() ), true );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue