diff --git a/hibernate-core/src/main/java/org/hibernate/Hibernate.java b/hibernate-core/src/main/java/org/hibernate/Hibernate.java index 2f4bf4106e..f63ce225b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/Hibernate.java +++ b/hibernate-core/src/main/java/org/hibernate/Hibernate.java @@ -35,7 +35,9 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.hibernate.collection.spi.LazyInitializable; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; /** @@ -126,8 +128,8 @@ public final class Hibernate { return; } - if ( proxy instanceof HibernateProxy ) { - ( (HibernateProxy) proxy ).getHibernateLazyInitializer().initialize(); + if ( isHibernateProxy( proxy ) ) { + asHibernateProxy( proxy ).getHibernateLazyInitializer().initialize(); } else if ( proxy instanceof LazyInitializable ) { ( (LazyInitializable) proxy ).forceInitialization(); @@ -149,8 +151,9 @@ public final class Hibernate { * @return true if the argument is already initialized, or is not a proxy or collection */ public static boolean isInitialized(Object proxy) { - if ( proxy instanceof HibernateProxy ) { - return !( (HibernateProxy) proxy ).getHibernateLazyInitializer().isUninitialized(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy ); + if ( lazyInitializer != null ) { + return !lazyInitializer.isUninitialized(); } else if ( isPersistentAttributeInterceptable( proxy ) ) { final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable( proxy ).$$_hibernate_getInterceptor(); @@ -241,8 +244,9 @@ public final class Hibernate { @SuppressWarnings("unchecked") public static Class getClass(T proxy) { Class result; - if ( proxy instanceof HibernateProxy ) { - result = ( (HibernateProxy) proxy ).getHibernateLazyInitializer() + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy ); + if ( lazyInitializer != null ) { + result = lazyInitializer .getImplementation() .getClass(); } @@ -280,13 +284,13 @@ public final class Hibernate { */ public static boolean isPropertyInitialized(Object proxy, String propertyName) { final Object entity; - if ( proxy instanceof HibernateProxy ) { - final LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer(); - if ( li.isUninitialized() ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.isUninitialized() ) { return false; } else { - entity = li.getImplementation(); + entity = lazyInitializer.getImplementation(); } } else { @@ -315,8 +319,8 @@ public final class Hibernate { * uninitialized proxy that is not associated with an open session. */ public static Object unproxy(Object proxy) { - if ( proxy instanceof HibernateProxy ) { - HibernateProxy hibernateProxy = (HibernateProxy) proxy; + if ( isHibernateProxy( proxy ) ) { + HibernateProxy hibernateProxy = asHibernateProxy( proxy ); LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer(); return initializer.getImplementation(); } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java index 9c204b6254..c65575a286 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java @@ -6,6 +6,7 @@ */ package org.hibernate.bytecode.internal.bytebuddy; +import static net.bytebuddy.matcher.ElementMatchers.anyOf; import static net.bytebuddy.matcher.ElementMatchers.isFinalizer; import static net.bytebuddy.matcher.ElementMatchers.isSynthetic; import static net.bytebuddy.matcher.ElementMatchers.isVirtual; @@ -26,6 +27,7 @@ import java.util.function.Function; import org.hibernate.HibernateException; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.bytecode.spi.BasicProxyFactory; +import org.hibernate.engine.spi.PrimeAmongSecondarySupertypes; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.securitymanager.SystemSecurityManager; import org.hibernate.proxy.ProxyConfiguration; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java index 35075372d2..868456c14f 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java @@ -34,6 +34,7 @@ import org.hibernate.pretty.MessageHelper; import org.hibernate.proxy.HibernateProxy; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; /** @@ -347,9 +348,8 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry { return !enhancementAsProxyLazinessInterceptor.hasWrittenFieldNames(); } } - else if ( entity instanceof HibernateProxy ) { - uninitializedProxy = ( (HibernateProxy) entity ).getHibernateLazyInitializer() - .isUninitialized(); + else if ( isHibernateProxy( entity ) ) { + uninitializedProxy = HibernateProxy.extractLazyInitializer( entity ).isUninitialized(); } // we never have to check an uninitialized proxy return uninitializedProxy || !persister.hasCollections() diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java index 4b08f11a73..dfaffa7a1c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/ForeignKeys.java @@ -21,6 +21,8 @@ import org.hibernate.type.CompositeType; import org.hibernate.type.EntityType; import org.hibernate.type.Type; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * Algorithms related to foreign key constraint transparency * @@ -198,20 +200,20 @@ public final class ForeignKeys { final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - if ( object instanceof HibernateProxy ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { // if it's an uninitialized proxy it can only be // transient if we did an unloaded-delete on the // proxy itself, in which case there is no entry // for it, but its key has already been registered // as nullifiable - final LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); - Object entity = li.getImplementation( session ); + Object entity = lazyInitializer.getImplementation( session ); if ( entity == null ) { return persistenceContext.containsDeletedUnloadedEntityKey( session.generateEntityKey( - li.getIdentifier(), + lazyInitializer.getIdentifier(), session.getFactory().getRuntimeMetamodels().getMappingMetamodel() - .getEntityDescriptor( li.getEntityName() ) + .getEntityDescriptor( lazyInitializer.getEntityName() ) ) ); } @@ -255,7 +257,7 @@ public final class ForeignKeys { * @return {@code true} if the given entity is not transient (meaning it is either detached/persistent) */ public static boolean isNotTransient(String entityName, Object entity, Boolean assumed, SharedSessionContractImplementor session) { - return entity instanceof HibernateProxy + return isHibernateProxy( entity ) || session.getPersistenceContextInternal().isEntryFor( entity ) // todo : shouldn't assumed be reversed here? || !isTransient( entityName, entity, assumed, session ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java index f6fc6b7f19..c7e8577f05 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/ManagedTypeHelper.java @@ -14,6 +14,7 @@ import org.hibernate.engine.spi.ManagedEntity; import org.hibernate.engine.spi.ManagedMappedSuperclass; import org.hibernate.engine.spi.PersistentAttributeInterceptable; import org.hibernate.engine.spi.SelfDirtinessTracker; +import org.hibernate.proxy.HibernateProxy; import java.util.Objects; import java.util.function.BiConsumer; @@ -106,6 +107,18 @@ public final class ManagedTypeHelper { return false; } + /** + * @param entity + * @return true if and only if the entity implements {@see HibernateProxy} + */ + public static boolean isHibernateProxy(final Object entity) { + if ( entity instanceof PrimeAmongSecondarySupertypes ) { + PrimeAmongSecondarySupertypes t = (PrimeAmongSecondarySupertypes) entity; + return t.asHibernateProxy() != null; + } + return false; + } + /** * @param entity * @return true if and only if the entity implements {@see PersistentAttributeInterceptable} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java index 4a9c93652a..0023b5b80a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java @@ -68,8 +68,10 @@ import org.hibernate.type.CollectionType; import org.jboss.logging.Logger; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; /** @@ -228,7 +230,7 @@ public class StatefulPersistenceContext implements PersistenceContext { if ( proxiesByKey != null ) { proxiesByKey.forEach( (k,o) -> { if ( o != null) { - ((HibernateProxy) o).getHibernateLazyInitializer().unsetSession(); + HibernateProxy.extractLazyInitializer( o ).unsetSession(); } } ); } @@ -600,8 +602,8 @@ public class StatefulPersistenceContext implements PersistenceContext { if ( ! Hibernate.isInitialized( value ) ) { // could be a proxy.... - if ( value instanceof HibernateProxy ) { - final HibernateProxy proxy = (HibernateProxy) value; + if ( isHibernateProxy( value ) ) { + final HibernateProxy proxy = asHibernateProxy( value ); final LazyInitializer li = proxy.getHibernateLazyInitializer(); reassociateProxy( li, proxy ); return true; @@ -624,9 +626,9 @@ public class StatefulPersistenceContext implements PersistenceContext { @Override public void reassociateProxy(Object value, Object id) throws MappingException { - if ( value instanceof HibernateProxy ) { + if ( isHibernateProxy( value ) ) { LOG.debugf( "Setting proxy identifier: %s", id ); - final HibernateProxy proxy = (HibernateProxy) value; + final HibernateProxy proxy = asHibernateProxy( value ); final LazyInitializer li = proxy.getHibernateLazyInitializer(); li.setIdentifier( id ); reassociateProxy( li, proxy ); @@ -654,8 +656,8 @@ public class StatefulPersistenceContext implements PersistenceContext { @Override public Object unproxy(Object maybeProxy) throws HibernateException { - if ( maybeProxy instanceof HibernateProxy ) { - final HibernateProxy proxy = (HibernateProxy) maybeProxy; + if ( isHibernateProxy( maybeProxy ) ) { + final HibernateProxy proxy = asHibernateProxy( maybeProxy ); final LazyInitializer li = proxy.getHibernateLazyInitializer(); if ( li.isUninitialized() ) { throw new PersistentObjectException( @@ -672,8 +674,8 @@ public class StatefulPersistenceContext implements PersistenceContext { @Override public Object unproxyAndReassociate(Object maybeProxy) throws HibernateException { - if ( maybeProxy instanceof HibernateProxy ) { - final HibernateProxy proxy = (HibernateProxy) maybeProxy; + if ( isHibernateProxy( maybeProxy ) ) { + final HibernateProxy proxy = asHibernateProxy( maybeProxy ); final LazyInitializer li = proxy.getHibernateLazyInitializer(); reassociateProxy( li, proxy ); //initialize + unwrap the object and return it @@ -722,7 +724,7 @@ public class StatefulPersistenceContext implements PersistenceContext { // Similarly, if the original HibernateProxy is initialized, there // is again no point in creating a proxy. Just return the impl - final HibernateProxy originalHibernateProxy = (HibernateProxy) proxy; + final HibernateProxy originalHibernateProxy = asHibernateProxy( proxy ); if ( !originalHibernateProxy.getHibernateLazyInitializer().isUninitialized() ) { final Object impl = originalHibernateProxy.getHibernateLazyInitializer().getImplementation(); // can we return it? @@ -734,7 +736,7 @@ public class StatefulPersistenceContext implements PersistenceContext { // Otherwise, create the narrowed proxy - final HibernateProxy narrowedProxy = (HibernateProxy) persister.createProxy( key.getIdentifier(), session ); + final HibernateProxy narrowedProxy = asHibernateProxy( persister.createProxy( key.getIdentifier(), session ) ); // set the read-only/modifiable mode in the new proxy to what it was in the original proxy final boolean readOnlyOrig = originalHibernateProxy.getHibernateLazyInitializer().isReadOnly(); @@ -744,7 +746,7 @@ public class StatefulPersistenceContext implements PersistenceContext { } else { if ( object != null ) { - final LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer(); + final LazyInitializer li = asHibernateProxy( proxy ).getHibernateLazyInitializer(); li.setImplementation( object ); } return proxy; @@ -1316,8 +1318,8 @@ public class StatefulPersistenceContext implements PersistenceContext { if ( mergeMap != null ) { for ( Object o : mergeMap.entrySet() ) { final Entry mergeMapEntry = (Entry) o; - if ( mergeMapEntry.getKey() instanceof HibernateProxy ) { - final HibernateProxy proxy = (HibernateProxy) mergeMapEntry.getKey(); + if ( isHibernateProxy( mergeMapEntry.getKey() ) ) { + final HibernateProxy proxy = asHibernateProxy( mergeMapEntry.getKey() ); if ( persister.isSubclassEntityName( proxy.getHibernateLazyInitializer().getEntityName() ) ) { boolean found = isFoundInParent( propertyName, @@ -1480,8 +1482,9 @@ public class StatefulPersistenceContext implements PersistenceContext { throw new AssertionFailure( "object must be non-null." ); } boolean isReadOnly; - if ( entityOrProxy instanceof HibernateProxy ) { - isReadOnly = ( (HibernateProxy) entityOrProxy ).getHibernateLazyInitializer().isReadOnly(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entityOrProxy ); + if ( lazyInitializer != null ) { + isReadOnly = lazyInitializer.isReadOnly(); } else { final EntityEntry ee = getEntry( entityOrProxy ); @@ -1501,8 +1504,8 @@ public class StatefulPersistenceContext implements PersistenceContext { if ( isReadOnly( object ) == readOnly ) { return; } - if ( object instanceof HibernateProxy ) { - final HibernateProxy proxy = (HibernateProxy) object; + if ( isHibernateProxy( object ) ) { + final HibernateProxy proxy = asHibernateProxy( object ); setProxyReadOnly( proxy, readOnly ); if ( Hibernate.isInitialized( proxy ) ) { setEntityReadOnly( @@ -1516,8 +1519,8 @@ public class StatefulPersistenceContext implements PersistenceContext { // PersistenceContext.proxyFor( entity ) returns entity if there is no proxy for that entity // so need to check the return value to be sure it is really a proxy final Object maybeProxy = getSession().getPersistenceContextInternal().proxyFor( object ); - if ( maybeProxy instanceof HibernateProxy ) { - setProxyReadOnly( (HibernateProxy) maybeProxy, readOnly ); + if ( isHibernateProxy( maybeProxy ) ) { + setProxyReadOnly( asHibernateProxy( maybeProxy ), readOnly ); } } } @@ -1689,7 +1692,8 @@ public class StatefulPersistenceContext implements PersistenceContext { rtn.hasNonReadOnlyEntities = ois.readBoolean(); int count = ois.readInt(); - if ( LOG.isTraceEnabled() ) { + final boolean traceEnabled = LOG.isTraceEnabled(); + if ( traceEnabled ) { LOG.trace( "Starting deserialization of [" + count + "] entitiesByKey entries" ); } rtn.entitiesByKey = CollectionHelper.mapOfSize(Math.max(count, INIT_COLL_SIZE)); @@ -1698,7 +1702,7 @@ public class StatefulPersistenceContext implements PersistenceContext { } count = ois.readInt(); - if ( LOG.isTraceEnabled() ) { + if ( traceEnabled ) { LOG.trace( "Starting deserialization of [" + count + "] entitiesByUniqueKey entries" ); } if ( count != 0 ) { @@ -1709,26 +1713,27 @@ public class StatefulPersistenceContext implements PersistenceContext { } count = ois.readInt(); - if ( LOG.isTraceEnabled() ) { + if ( traceEnabled ) { LOG.trace( "Starting deserialization of [" + count + "] proxiesByKey entries" ); } for ( int i = 0; i < count; i++ ) { final EntityKey ek = EntityKey.deserialize( ois, sfi ); final Object proxy = ois.readObject(); - if ( proxy instanceof HibernateProxy ) { - ( (HibernateProxy) proxy ).getHibernateLazyInitializer().setSession( session ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy ); + if ( lazyInitializer != null ) { + lazyInitializer.setSession( session ); rtn.getOrInitializeProxiesByKey().put( ek, proxy ); } else { // otherwise, the proxy was pruned during the serialization process - if ( LOG.isTraceEnabled() ) { + if ( traceEnabled ) { LOG.trace( "Encountered pruned proxy" ); } } } count = ois.readInt(); - if ( LOG.isTraceEnabled() ) { + if ( traceEnabled ) { LOG.trace( "Starting deserialization of [" + count + "] entitySnapshotsByKey entries" ); } rtn.entitySnapshotsByKey = CollectionHelper.mapOfSize(Math.max(count, INIT_COLL_SIZE)); @@ -1739,7 +1744,7 @@ public class StatefulPersistenceContext implements PersistenceContext { rtn.entityEntryContext = EntityEntryContext.deserialize( ois, rtn ); count = ois.readInt(); - if ( LOG.isTraceEnabled() ) { + if ( traceEnabled ) { LOG.trace( "Starting deserialization of [" + count + "] collectionsByKey entries" ); } rtn.collectionsByKey = CollectionHelper.mapOfSize(Math.max(count, INIT_COLL_SIZE)); @@ -1751,7 +1756,7 @@ public class StatefulPersistenceContext implements PersistenceContext { } count = ois.readInt(); - if ( LOG.isTraceEnabled() ) { + if ( traceEnabled ) { LOG.trace( "Starting deserialization of [" + count + "] collectionEntries entries" ); } for ( int i = 0; i < count; i++ ) { @@ -1762,7 +1767,7 @@ public class StatefulPersistenceContext implements PersistenceContext { } count = ois.readInt(); - if ( LOG.isTraceEnabled() ) { + if ( traceEnabled ) { LOG.trace( "Starting deserialization of [" + count + "] arrayHolders entries" ); } if ( count != 0 ) { @@ -1773,7 +1778,7 @@ public class StatefulPersistenceContext implements PersistenceContext { } count = ois.readInt(); - if ( LOG.isTraceEnabled() ) { + if ( traceEnabled ) { LOG.trace( "Starting deserialization of [" + count + "] nullifiableEntityKey entries" ); } rtn.nullifiableEntityKeys = new HashSet<>(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java index 6ccc262dd0..60d5728af1 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java @@ -844,10 +844,10 @@ public class ActionQueue { } public void unScheduleDeletion(EntityEntry entry, Object rescuedEntity) { - if ( rescuedEntity instanceof HibernateProxy ) { - LazyInitializer initializer = ( (HibernateProxy) rescuedEntity ).getHibernateLazyInitializer(); - if ( !initializer.isUninitialized() ) { - rescuedEntity = initializer.getImplementation( session ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( rescuedEntity ); + if ( lazyInitializer != null ) { + if ( !lazyInitializer.isUninitialized() ) { + rescuedEntity = lazyInitializer.getImplementation( session ); } } if ( deletions != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/PrimeAmongSecondarySupertypes.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/PrimeAmongSecondarySupertypes.java index 625513c368..79ac598ae5 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/PrimeAmongSecondarySupertypes.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/PrimeAmongSecondarySupertypes.java @@ -7,6 +7,7 @@ package org.hibernate.engine.spi; import org.hibernate.engine.internal.ManagedTypeHelper; +import org.hibernate.proxy.HibernateProxy; /** * For a full explanation of the purpose of this interface @@ -53,4 +54,8 @@ public interface PrimeAmongSecondarySupertypes { return null; } + default HibernateProxy asHibernateProxy() { + return null; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java index 080ac1f2f0..b652875a92 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java @@ -98,14 +98,13 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback private boolean optimizeUnloadedDelete(DeleteEvent event) { final Object object = event.getObject(); - if ( object instanceof HibernateProxy ) { - HibernateProxy proxy = (HibernateProxy) object; - LazyInitializer initializer = proxy.getHibernateLazyInitializer(); - if ( initializer.isUninitialized() ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.isUninitialized() ) { final EventSource source = event.getSession(); final EntityPersister persister = source.getFactory().getMappingMetamodel() - .findEntityDescriptor( initializer.getEntityName() ); - final Object id = initializer.getIdentifier(); + .findEntityDescriptor( lazyInitializer.getEntityName() ); + final Object id = lazyInitializer.getIdentifier(); final EntityKey key = source.generateEntityKey( id, persister ); final PersistenceContext persistenceContext = source.getPersistenceContextInternal(); if ( !persistenceContext.containsEntity( key ) diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java index b8c228da57..cc517e6919 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java @@ -47,25 +47,25 @@ public class DefaultEvictEventListener implements EvictEventListener { if ( object == null ) { throw new NullPointerException( "null passed to Session.evict()" ); } - if ( object instanceof HibernateProxy ) { - final LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); - final Object id = li.getInternalIdentifier(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + final Object id = lazyInitializer.getInternalIdentifier(); if ( id == null ) { throw new IllegalArgumentException( "Could not determine identifier of proxy passed to evict()" ); } final EntityPersister persister = source.getFactory() .getMappingMetamodel() - .getEntityDescriptor( li.getEntityName() ); + .getEntityDescriptor( lazyInitializer.getEntityName() ); final EntityKey key = source.generateEntityKey( id, persister ); persistenceContext.removeProxy( key ); - if ( !li.isUninitialized() ) { + if ( !lazyInitializer.isUninitialized() ) { final Object entity = persistenceContext.removeEntity( key ); if ( entity != null ) { EntityEntry entry = persistenceContext.removeEntry( entity ); doEvict( entity, key, entry.getPersister(), event.getSession() ); } } - li.unsetSession(); + lazyInitializer.unsetSession(); } else { EntityEntry entry = persistenceContext.getEntry( object ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java index 3735850889..ee46fb707a 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java @@ -6,8 +6,6 @@ */ package org.hibernate.event.internal; -import java.util.List; - import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.NonUniqueObjectException; @@ -298,11 +296,8 @@ public class DefaultLoadEventListener implements LoadEventListener { // existing proxy associated with the PC - and if so, use it final Object proxy = persistenceContext.getProxy( keyToLoad ); if ( proxy != null ) { - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Entity proxy found in session cache" ); - } - if ( LOG.isDebugEnabled() - && ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isUnwrap() ) { + LOG.trace( "Entity proxy found in session cache" ); + if ( LOG.isDebugEnabled() && HibernateProxy.extractLazyInitializer( proxy ).isUnwrap() ) { LOG.debug( "Ignoring NO_PROXY to honor laziness" ); } return persistenceContext.narrowProxy( proxy, persister, keyToLoad, null ); @@ -378,7 +373,7 @@ public class DefaultLoadEventListener implements LoadEventListener { if ( LOG.isTraceEnabled() ) { LOG.trace( "Entity proxy found in session cache" ); } - final LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer(); + LazyInitializer li = HibernateProxy.extractLazyInitializer( proxy ); if ( li.isUnwrap() ) { return li.getImplementation(); } @@ -601,8 +596,9 @@ public class DefaultLoadEventListener implements LoadEventListener { // persister/loader/initializer sensitive to this fact - possibly // passing LoadType along - if ( entity instanceof HibernateProxy ) { - entity = ( (HibernateProxy) entity ).getHibernateLazyInitializer().getImplementation(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + entity = lazyInitializer.getImplementation(); } final StatisticsImplementor statistics = event.getSession().getFactory().getStatistics(); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index fb44bd1bcd..45dab9d6f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -103,14 +103,14 @@ public class DefaultMergeEventListener // NOTE : `original` is the value being merged if ( original != null ) { final EventSource source = event.getSession(); - if ( original instanceof HibernateProxy ) { - LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer(); - if ( li.isUninitialized() ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( original ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.isUninitialized() ) { LOG.trace( "Ignoring uninitialized proxy" ); - event.setResult( source.load( li.getEntityName(), li.getInternalIdentifier() ) ); + event.setResult( source.load( lazyInitializer.getEntityName(), lazyInitializer.getInternalIdentifier() ) ); } else { - doMerge( event, copiedAlready, li.getImplementation() ); + doMerge( event, copiedAlready, lazyInitializer.getImplementation() ); } } else if ( isPersistentAttributeInterceptable( original ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java index 13ba03f4eb..f51530af60 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java @@ -62,15 +62,15 @@ public class DefaultPersistEventListener */ public void onPersist(PersistEvent event, PersistContext createCache) throws HibernateException { final Object object = event.getObject(); - if ( object instanceof HibernateProxy ) { - LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); - if ( li.isUninitialized() ) { - if ( li.getSession() != event.getSession() ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.isUninitialized() ) { + if ( lazyInitializer.getSession() != event.getSession() ) { throw new PersistentObjectException( "uninitialized proxy passed to persist()" ); } } else { - persist( event, createCache, li.getImplementation() ); + persist( event, createCache, lazyInitializer.getImplementation() ); } } else { diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java index 480dc41bac..0ea80c2aff 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java @@ -32,6 +32,7 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.pretty.MessageHelper; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; /** * Defines the default listener used by Hibernate for handling save-update @@ -57,8 +58,9 @@ public class DefaultSaveOrUpdateEventListener if ( requestedId != null ) { //assign the requested id to the proxy, *before* //reassociating the proxy - if ( object instanceof HibernateProxy ) { - ( (HibernateProxy) object ).getHibernateLazyInitializer().setIdentifier( requestedId ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + lazyInitializer.setIdentifier( requestedId ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index e128931642..ebe08ad813 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -697,8 +697,8 @@ public class SessionFactoryImpl implements SessionFactoryImplementor { @Override public String bestGuessEntityName(Object object) { - if ( object instanceof HibernateProxy ) { - LazyInitializer initializer = ( (HibernateProxy) object ).getHibernateLazyInitializer(); + final LazyInitializer initializer = HibernateProxy.extractLazyInitializer( object ); + if ( initializer != null ) { // it is possible for this method to be called during flush processing, // so make certain that we do not accidentally initialize an uninitialized proxy if ( initializer.isUninitialized() ) { @@ -1081,10 +1081,9 @@ public class SessionFactoryImpl implements SessionFactoryImplementor { } Class clazz; - if (bindValue instanceof HibernateProxy) { - HibernateProxy proxy = (HibernateProxy) bindValue; - LazyInitializer li = proxy.getHibernateLazyInitializer(); - clazz = li.getPersistentClass(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( bindValue ); + if ( lazyInitializer != null ) { + clazz = lazyInitializer.getPersistentClass(); } else { clazz = bindValue.getClass(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index ab69f2c72f..4f8dd5f33e 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -162,6 +162,7 @@ import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE; import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; import static org.hibernate.jpa.HibernateHints.HINT_READ_ONLY; import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_LOCK_TIMEOUT; import static org.hibernate.jpa.LegacySpecHints.HINT_JAVAEE_QUERY_TIMEOUT; @@ -534,8 +535,9 @@ public class SessionImpl throw new NullPointerException( "null object passed to getCurrentLockMode()" ); } - if ( object instanceof HibernateProxy ) { - object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation( this ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + object = lazyInitializer.getImplementation( this ); if ( object == null ) { return LockMode.NONE; } @@ -1034,8 +1036,9 @@ public class SessionImpl fireLoadNoChecks( event, LoadEventListener.IMMEDIATE_LOAD ); Object result = event.getResult(); finishWithEventInstance( event ); - if ( result instanceof HibernateProxy ) { - return ( (HibernateProxy) result ).getHibernateLazyInitializer().getImplementation(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( result ); + if ( lazyInitializer != null ) { + return lazyInitializer.getImplementation(); } return result; } @@ -1496,12 +1499,12 @@ public class SessionImpl public Object getIdentifier(Object object) throws HibernateException { checkOpen(); checkTransactionSynchStatus(); - if ( object instanceof HibernateProxy ) { - LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); - if ( li.getSession() != this ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.getSession() != this ) { throw new TransientObjectException( "The proxy was not associated with this session" ); } - return li.getInternalIdentifier(); + return lazyInitializer.getInternalIdentifier(); } else { EntityEntry entry = persistenceContext.getEntry( object ); @@ -1529,7 +1532,13 @@ public class SessionImpl } private Object getProxyIdentifier(Object proxy) { - return ( (HibernateProxy) proxy ).getHibernateLazyInitializer().getInternalIdentifier(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy ); + if ( lazyInitializer != null ) { + return lazyInitializer.getInternalIdentifier(); + } + else { + throw new HibernateException( "Argument was not an HibernateProxy, which is a requirement for this method" ); + } } @Override @@ -1542,23 +1551,23 @@ public class SessionImpl } try { - if ( object instanceof HibernateProxy ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { //do not use proxiesByKey, since not all //proxies that point to this session's //instances are in that collection! - LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); - if ( li.isUninitialized() ) { + if ( lazyInitializer.isUninitialized() ) { //if it is an uninitialized proxy, pointing //with this session, then when it is accessed, //the underlying instance will be "contained" - return li.getSession() == this; + return lazyInitializer.getSession() == this; } else { //if it is initialized, see if the underlying //instance is contained, since we need to //account for the fact that it might have been //evicted - object = li.getImplementation(); + object = lazyInitializer.getImplementation(); } } @@ -1569,7 +1578,7 @@ public class SessionImpl delayedAfterCompletion(); if ( entry == null ) { - if ( !(object instanceof HibernateProxy) && persistenceContext.getEntry( object ) == null ) { + if ( ! ( isHibernateProxy( object ) ) && persistenceContext.getEntry( object ) == null ) { // check if it is even an entity -> if not throw an exception (per JPA) try { final String entityName = getEntityNameResolver().resolveEntityName( object ); @@ -1620,11 +1629,11 @@ public class SessionImpl } } - if ( object instanceof HibernateProxy ) { + final LazyInitializer li = HibernateProxy.extractLazyInitializer( object ); + if ( li != null ) { //do not use proxiesByKey, since not all //proxies that point to this session's //instances are in that collection! - LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); if ( li.isUninitialized() ) { //if it is an uninitialized proxy, pointing //with this session, then when it is accessed, @@ -1693,14 +1702,14 @@ public class SessionImpl @Override public String bestGuessEntityName(Object object) { - if ( object instanceof HibernateProxy ) { - LazyInitializer initializer = ( (HibernateProxy) object ).getHibernateLazyInitializer(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { // it is possible for this method to be called during flush processing, // so make certain that we do not accidentally initialize an uninitialized proxy - if ( initializer.isUninitialized() ) { - return initializer.getEntityName(); + if ( lazyInitializer.isUninitialized() ) { + return lazyInitializer.getEntityName(); } - object = initializer.getImplementation(); + object = lazyInitializer.getImplementation(); } EntityEntry entry = persistenceContext.getEntry( object ); if ( entry == null ) { @@ -1715,11 +1724,12 @@ public class SessionImpl public String getEntityName(Object object) { checkOpen(); // checkTransactionSynchStatus(); - if ( object instanceof HibernateProxy ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { if ( !persistenceContext.containsProxy( object ) ) { throw new TransientObjectException( "proxy was not associated with the session" ); } - object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation(); + object = lazyInitializer.getImplementation(); } EntityEntry entry = persistenceContext.getEntry( object ); @@ -1732,9 +1742,9 @@ public class SessionImpl @Override @SuppressWarnings("unchecked") public T getReference(T object) { checkOpen(); - if ( object instanceof HibernateProxy ) { - LazyInitializer initializer = ( (HibernateProxy) object ).getHibernateLazyInitializer(); - return (T) getReference( initializer.getPersistentClass(), initializer.getIdentifier() ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + return (T) getReference( lazyInitializer.getPersistentClass(), lazyInitializer.getIdentifier() ); } else { EntityPersister persister = getEntityPersister( null, object ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 5563dc962d..ec3a5b03f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -328,7 +328,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen if ( LOG.isTraceEnabled() ) { LOG.trace( "Entity proxy found in session cache" ); } - if ( LOG.isDebugEnabled() && ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isUnwrap() ) { + if ( LOG.isDebugEnabled() && HibernateProxy.extractLazyInitializer( proxy ).isUnwrap() ) { LOG.debug( "Ignoring NO_PROXY to honor laziness" ); } @@ -387,8 +387,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen checkOpen(); PersistenceContext persistenceContext = getPersistenceContext(); if ( association instanceof HibernateProxy ) { - LazyInitializer initializer = - ((HibernateProxy) association).getHibernateLazyInitializer(); + final LazyInitializer initializer = HibernateProxy.extractLazyInitializer( association ); if ( initializer.isUninitialized() ) { String entityName = initializer.getEntityName(); Object id = initializer.getIdentifier(); @@ -479,8 +478,9 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen @Override public String bestGuessEntityName(Object object) { - if ( object instanceof HibernateProxy ) { - object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + object = lazyInitializer.getImplementation(); } return guessEntityName( object ); } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java index 3a87e6d4a2..53ad51f54e 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java @@ -17,6 +17,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.jpa.internal.util.PersistenceUtilHelper; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.jboss.logging.Logger; @@ -69,8 +70,9 @@ public class PersistenceUnitUtilImpl implements PersistenceUnitUtil, Serializabl throw new IllegalArgumentException( "Passed entity cannot be null" ); } - if ( entity instanceof HibernateProxy ) { - return ((HibernateProxy) entity).getHibernateLazyInitializer().getInternalIdentifier(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + return lazyInitializer.getInternalIdentifier(); } else if ( isManagedEntity( entity ) ) { EntityEntry entityEntry = asManagedEntity( entity ).$$_hibernate_getEntityEntry(); diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUtilHelper.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUtilHelper.java index 6a4b13fe6e..509d19ec97 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUtilHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUtilHelper.java @@ -80,8 +80,9 @@ public final class PersistenceUtilHelper { * @return The appropriate LoadState (see above) */ public static LoadState isLoaded(Object reference) { - if ( reference instanceof HibernateProxy ) { - final boolean isInitialized = !( (HibernateProxy) reference ).getHibernateLazyInitializer().isUninitialized(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( reference ); + if ( lazyInitializer != null ) { + final boolean isInitialized = !lazyInitializer.isUninitialized(); return isInitialized ? LoadState.LOADED : LoadState.NOT_LOADED; } else if ( isPersistentAttributeInterceptable( reference ) ) { @@ -118,15 +119,15 @@ public final class PersistenceUtilHelper { */ public static LoadState isLoadedWithoutReference(Object entity, String attributeName, MetadataCache cache) { boolean sureFromUs = false; - if ( entity instanceof HibernateProxy ) { - LazyInitializer li = ( (HibernateProxy) entity ).getHibernateLazyInitializer(); - if ( li.isUninitialized() ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.isUninitialized() ) { // we have an uninitialized proxy, the attribute cannot be loaded return LoadState.NOT_LOADED; } else { // swap the proxy with target (for proper class name resolution) - entity = li.getImplementation(); + entity = lazyInitializer.getImplementation(); } sureFromUs = true; } @@ -200,15 +201,15 @@ public final class PersistenceUtilHelper { * @return The LoadState */ public static LoadState isLoadedWithReference(Object entity, String attributeName, MetadataCache cache) { - if ( entity instanceof HibernateProxy ) { - final LazyInitializer li = ( (HibernateProxy) entity ).getHibernateLazyInitializer(); - if ( li.isUninitialized() ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.isUninitialized() ) { // we have an uninitialized proxy, the attribute cannot be loaded return LoadState.NOT_LOADED; } else { // swap the proxy with target (for proper class name resolution) - entity = li.getImplementation(); + entity = lazyInitializer.getImplementation(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/access/BaseNaturalIdLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/access/BaseNaturalIdLoadAccessImpl.java index 68ae66b1e9..7cbbfb5631 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/access/BaseNaturalIdLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/access/BaseNaturalIdLoadAccessImpl.java @@ -200,8 +200,8 @@ public abstract class BaseNaturalIdLoadAccessImpl implements NaturalIdLoadOpt if ( loaded != null ) { final EntityEntry entry; - if ( loaded instanceof HibernateProxy ) { - LazyInitializer lazyInitializer = ( (HibernateProxy) loaded ).getHibernateLazyInitializer(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( loaded ); + if ( lazyInitializer != null ) { entry = persistenceContext.getEntry( lazyInitializer.getImplementation() ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/access/IdentifierLoadAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/access/IdentifierLoadAccessImpl.java index 601d1942d9..ab17fe24b5 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/access/IdentifierLoadAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/access/IdentifierLoadAccessImpl.java @@ -31,6 +31,9 @@ import org.hibernate.proxy.LazyInitializer; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.spi.TypeConfiguration; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * @author Steve Ebersole */ @@ -210,8 +213,8 @@ public class IdentifierLoadAccessImpl implements IdentifierLoadAccess, Jav return; } - if ( result instanceof HibernateProxy ) { - final HibernateProxy hibernateProxy = (HibernateProxy) result; + if ( isHibernateProxy( result ) ) { + final HibernateProxy hibernateProxy = asHibernateProxy( result ); final LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer(); if ( initializer.isUninitialized() ) { initializer.initialize(); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/CacheEntityLoaderHelper.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/CacheEntityLoaderHelper.java index df6f4dd179..1c27cbc294 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/CacheEntityLoaderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/CacheEntityLoaderHelper.java @@ -431,7 +431,7 @@ public class CacheEntityLoaderHelper { if ( proxy != null ) { // there is already a proxy for this impl // only set the status to read-only if the proxy is read-only - isReadOnly = ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isReadOnly(); + isReadOnly = HibernateProxy.extractLazyInitializer( proxy ).isReadOnly(); } else { isReadOnly = source.isDefaultReadOnly(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java index af42d01cf5..9414ca4d8f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java @@ -28,6 +28,7 @@ import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.spi.SqlAstCreationState; @@ -144,16 +145,18 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa @Override public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - if ( entity instanceof HibernateProxy ) { - return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + return lazyInitializer.getIdentifier(); } return propertyAccess.getGetter().get( entity ); } @Override public Object getIdentifier(Object entity) { - if ( entity instanceof HibernateProxy ) { - return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + return lazyInitializer.getIdentifier(); } return propertyAccess.getGetter().get( entity ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java index b20d06d28e..ba2f269acc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java @@ -15,6 +15,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.spi.SqlSelection; @@ -85,16 +86,18 @@ public class EmbeddedIdentifierMappingImpl @Override public Object getIdentifier(Object entity, SharedSessionContractImplementor session) { - if ( entity instanceof HibernateProxy ) { - return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + return lazyInitializer.getIdentifier(); } return propertyAccess.getGetter().get( entity ); } @Override public Object getIdentifier(Object entity) { - if ( entity instanceof HibernateProxy ) { - return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + return lazyInitializer.getIdentifier(); } return propertyAccess.getGetter().get( entity ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java index 9f854f603b..6ea4dce997 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java @@ -31,6 +31,7 @@ import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.hibernate.query.sqm.ComparisonOperator; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.Clause; @@ -429,8 +430,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa if ( targetObject == null ) { return null; } - if ( refersToPrimaryKey && targetObject instanceof HibernateProxy ) { - return ( (HibernateProxy) targetObject ).getHibernateLazyInitializer().getIdentifier(); + if ( refersToPrimaryKey ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( targetObject ); + if ( lazyInitializer != null ) { + return lazyInitializer.getIdentifier(); + } } final ModelPart modelPart = side.getModelPart(); if ( modelPart instanceof EntityIdentifierMapping ) { diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/spi/SetterFieldImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/spi/SetterFieldImpl.java index 18d2e0497d..7c555ca431 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/spi/SetterFieldImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/spi/SetterFieldImpl.java @@ -15,6 +15,7 @@ import org.hibernate.PropertyAccessException; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.property.access.internal.AbstractFieldSerialForm; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; /** * Field-based implementation of Setter @@ -68,8 +69,9 @@ public class SetterFieldImpl implements Setter { } else { final String valueType; - if ( value instanceof HibernateProxy ) { - valueType = ( (HibernateProxy) value ).getHibernateLazyInitializer().getEntityName(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( value ); + if ( lazyInitializer != null ) { + valueType = lazyInitializer.getEntityName(); } else { valueType = value.getClass().getTypeName(); diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/HibernateProxy.java b/hibernate-core/src/main/java/org/hibernate/proxy/HibernateProxy.java index b0fd612d73..25eb14a6ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/HibernateProxy.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/HibernateProxy.java @@ -7,12 +7,33 @@ package org.hibernate.proxy; import java.io.Serializable; +import org.hibernate.engine.spi.PrimeAmongSecondarySupertypes; + /** * Marker interface for entity proxies * * @author Gavin King */ -public interface HibernateProxy extends Serializable { +public interface HibernateProxy extends Serializable, PrimeAmongSecondarySupertypes { + + /** + * Extract the LazyInitializer from the object, if + * and only if the object is actually an HibernateProxy. + * If not, null is returned. + * @param object any entity + * @return either null (if object is not an HibernateProxy) or the LazyInitializer of the HibernateProxy. + */ + static LazyInitializer extractLazyInitializer(final Object object) { + if ( object instanceof PrimeAmongSecondarySupertypes ) { + PrimeAmongSecondarySupertypes t = (PrimeAmongSecondarySupertypes) object; + final HibernateProxy hibernateProxy = t.asHibernateProxy(); + if ( hibernateProxy != null ) { + return hibernateProxy.getHibernateLazyInitializer(); + } + } + return null; + } + /** * Perform serialization-time write-replacement of this proxy. * @@ -26,4 +47,14 @@ public interface HibernateProxy extends Serializable { * @return The lazy initializer. */ LazyInitializer getHibernateLazyInitializer(); + + /** + * Special internal contract to optimize type checking + * @see PrimeAmongSecondarySupertypes + * @return this same instance + */ + @Override + default HibernateProxy asHibernateProxy() { + return this; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyFactory.java b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyFactory.java index 875107d583..41183f90de 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyFactory.java @@ -13,6 +13,7 @@ import java.security.PrivilegedAction; import java.util.Set; import org.hibernate.HibernateException; +import org.hibernate.engine.spi.PrimeAmongSecondarySupertypes; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; @@ -105,7 +106,12 @@ public class ByteBuddyProxyFactory implements ProxyFactory, Serializable { public HibernateProxy run() { try { - return (HibernateProxy) proxyClass.getConstructor().newInstance(); + PrimeAmongSecondarySupertypes instance = (PrimeAmongSecondarySupertypes) proxyClass.getConstructor().newInstance(); + final HibernateProxy hibernateProxy = instance.asHibernateProxy(); + if ( hibernateProxy == null ) { + throw new HibernateException( "Produced proxy does not correctly implement HibernateProxy" ); + } + return hibernateProxy; } catch (NoSuchMethodException e) { String logMessage = LOG.bytecodeEnhancementFailedBecauseOfDefaultConstructor( entityName ); diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyHelper.java b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyHelper.java index 44186a09aa..4c05dce420 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyProxyHelper.java @@ -6,6 +6,10 @@ */ package org.hibernate.proxy.pojo.bytebuddy; +import static net.bytebuddy.matcher.ElementMatchers.anyOf; +import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; import static org.hibernate.internal.CoreLogging.messageLogger; import java.io.Serializable; @@ -19,6 +23,15 @@ import java.util.function.Function; import org.hibernate.HibernateException; import org.hibernate.bytecode.internal.bytebuddy.ByteBuddyState; +import org.hibernate.engine.spi.CompositeOwner; +import org.hibernate.engine.spi.CompositeTracker; +import org.hibernate.engine.spi.Managed; +import org.hibernate.engine.spi.ManagedComposite; +import org.hibernate.engine.spi.ManagedEntity; +import org.hibernate.engine.spi.ManagedMappedSuperclass; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.PrimeAmongSecondarySupertypes; +import org.hibernate.engine.spi.SelfDirtinessTracker; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.proxy.HibernateProxy; @@ -33,6 +46,7 @@ import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeList; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy; +import net.bytebuddy.implementation.DefaultMethodCall; import net.bytebuddy.implementation.SuperMethodCall; import net.bytebuddy.pool.TypePool; @@ -92,7 +106,25 @@ public class ByteBuddyProxyHelper implements Serializable { .intercept( SuperMethodCall.INSTANCE ) .defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE ) .implement( ProxyConfiguration.class ) - .intercept( helpers.getInterceptorFieldAccessor() ); + .intercept( helpers.getInterceptorFieldAccessor() ) + .ignoreAlso( isDeclaredBy( ManagedEntity.class ).and( named( "asManagedEntity" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asManagedEntity" ) ) ) + .ignoreAlso( isDeclaredBy( PersistentAttributeInterceptable.class ).and( named( "asPersistentAttributeInterceptable" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asPersistentAttributeInterceptable" ) ) ) + .ignoreAlso( isDeclaredBy( SelfDirtinessTracker.class ).and( named( "asSelfDirtinessTracker" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asSelfDirtinessTracker" ) ) ) + .ignoreAlso( isDeclaredBy( Managed.class ).and( named( "asManaged" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asManaged" ) ) ) + .ignoreAlso( isDeclaredBy( ManagedComposite.class ).and( named( "asManagedComposite" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asManagedComposite" ) ) ) + .ignoreAlso( isDeclaredBy( ManagedMappedSuperclass.class ).and( named( "asManagedMappedSuperclass" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asManagedMappedSuperclass" ) ) ) + .ignoreAlso( isDeclaredBy( CompositeOwner.class ).and( named( "asCompositeOwner" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asCompositeOwner" ) ) ) + .ignoreAlso( isDeclaredBy( CompositeTracker.class ).and( named( "asCompositeTracker" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asCompositeTracker" ) ) ) + .ignoreAlso( isDeclaredBy( HibernateProxy.class ).and( named( "asHibernateProxy" ) ) ) + .ignoreAlso( isDeclaredBy( PrimeAmongSecondarySupertypes.class ).and( named( "asHibernateProxy" ) ) ); } public HibernateProxy deserializeProxy(SerializableProxy serializableProxy) { @@ -114,7 +146,7 @@ public class ByteBuddyProxyHelper implements Serializable { serializableProxy.getPersistentClass(), serializableProxy.getInterfaces() ); - final HibernateProxy proxy = (HibernateProxy) proxyClass.newInstance(); + final HibernateProxy proxy = asHibernateProxy( proxyClass.newInstance() ); ( (ProxyConfiguration) proxy ).$$_hibernate_set_interceptor( interceptor ); return proxy; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java index 0654383565..da84ca15c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java @@ -24,6 +24,7 @@ import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.ValueAccess; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AbstractFetchParentAccess; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -196,7 +197,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA if ( compositeInstance != NULL_MARKER ) { notifyResolutionListeners( compositeInstance ); - if ( compositeInstance instanceof HibernateProxy ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( compositeInstance ); + if ( lazyInitializer != null ) { final Initializer parentInitializer = processingState.resolveInitializer( navigablePath.getParent() ); if ( parentInitializer != this ) { ( (FetchParentAccess) parentInitializer ).registerResolutionListener( (entity) -> { @@ -215,7 +217,7 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA .getInstantiator() .instantiate( this, sessionFactory); stateInjected = true; - ( (HibernateProxy) compositeInstance ).getHibernateLazyInitializer().setImplementation( target ); + lazyInitializer.setImplementation( target ); } } else if ( stateAllNull == FALSE && stateInjected != TRUE ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java index 6a2c8ae654..fba5bbceab 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java @@ -648,9 +648,8 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); final PersistenceContext persistenceContext = session.getPersistenceContext(); - if ( entityInstance instanceof HibernateProxy ) { - LazyInitializer hibernateLazyInitializer = ( (HibernateProxy) entityInstance ).getHibernateLazyInitializer(); - + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entityInstance ); + if ( lazyInitializer != null ) { Object instance = persistenceContext.getEntity( entityKey ); if ( instance == null ) { instance = resolveInstance( @@ -662,7 +661,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces initializeEntity( instance, rowProcessingState, session, persistenceContext ); } - hibernateLazyInitializer.setImplementation( instance ); + lazyInitializer.setImplementation( instance ); entityInstanceForNotify = instance; } else { @@ -865,10 +864,11 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces isReallyReadOnly = true; } else { - if ( entityInstance instanceof HibernateProxy) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entityInstance ); + if ( lazyInitializer != null ) { // there is already a proxy for this impl // only set the status to read-only if the proxy is read-only - isReallyReadOnly = ( (HibernateProxy) entityInstance ).getHibernateLazyInitializer().isReadOnly(); + isReallyReadOnly = lazyInitializer.isReadOnly(); } } if ( isReallyReadOnly ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java index de725ea871..615c982295 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java @@ -19,6 +19,7 @@ import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.UniqueKeyLoadable; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AbstractFetchParentAccess; import org.hibernate.sql.results.graph.DomainResultAssembler; @@ -168,9 +169,9 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp ); } - if ( entityInstance instanceof HibernateProxy ) { - ( (HibernateProxy) entityInstance ).getHibernateLazyInitializer() - .setUnwrap( referencedModelPart.isUnwrapProxy() && concreteDescriptor.isInstrumented() ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entityInstance ); + if ( lazyInitializer != null ) { + lazyInitializer.setUnwrap( referencedModelPart.isUnwrapProxy() && concreteDescriptor.isInstrumented() ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchInitializer.java index 9508c065a6..6b13b93679 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchInitializer.java @@ -20,6 +20,7 @@ import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.spi.EntityIdentifierNavigablePath; import org.hibernate.sql.results.graph.AbstractFetchParentAccess; @@ -216,8 +217,9 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl } final boolean unwrapProxy = toOneMapping.isUnwrapProxy() && isEnhancedForLazyLoading; - if ( entityInstance instanceof HibernateProxy ) { - ( (HibernateProxy) entityInstance ).getHibernateLazyInitializer().setUnwrap( unwrapProxy ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entityInstance ); + if ( lazyInitializer != null ) { + lazyInitializer.setUnwrap( unwrapProxy ); } isInitialized = true; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularBiDirectionalFetchImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularBiDirectionalFetchImpl.java index d735ddf9de..6ec71a655f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularBiDirectionalFetchImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularBiDirectionalFetchImpl.java @@ -28,6 +28,7 @@ import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.UniqueKeyLoadable; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.spi.SqlSelection; @@ -275,12 +276,13 @@ public class CircularBiDirectionalFetchImpl implements BiDirectionalFetch, Assoc initializer.resolveInstance( rowProcessingState ); } final Object initializedInstance = initializer.getInitializedInstance(); - if ( initializedInstance instanceof HibernateProxy ) { + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( initializedInstance ); + if ( lazyInitializer != null ) { if ( initializedInstance.getClass().isAssignableFrom( javaType.getJavaTypeClass() ) ) { return initializedInstance; } initializer.initializeInstance( rowProcessingState ); - return ( (HibernateProxy) initializedInstance ).getHibernateLazyInitializer().getImplementation(); + return lazyInitializer.getImplementation(); } return initializedInstance; } diff --git a/hibernate-core/src/main/java/org/hibernate/type/AnyType.java b/hibernate-core/src/main/java/org/hibernate/type/AnyType.java index 3b03142d36..627baf3144 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/AnyType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/AnyType.java @@ -155,12 +155,12 @@ public class AnyType extends AbstractType implements CompositeType, AssociationT // this code is largely copied from Session's bestGuessEntityName Object entity = object; - if ( entity instanceof HibernateProxy ) { - final LazyInitializer initializer = ( (HibernateProxy) entity ).getHibernateLazyInitializer(); - if ( initializer.isUninitialized() ) { - entityName = initializer.getEntityName(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity ); + if ( lazyInitializer != null ) { + if ( lazyInitializer.isUninitialized() ) { + entityName = lazyInitializer.getEntityName(); } - entity = initializer.getImplementation(); + entity = lazyInitializer.getImplementation(); } if ( entityName == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java b/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java index 2a18a78463..6d7e4b640f 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java @@ -91,8 +91,8 @@ public abstract class CollectionType extends AbstractType implements Association while ( elems.hasNext() ) { Object element = elems.next(); // worrying about proxies is perhaps a little bit of overkill here... - if ( element instanceof HibernateProxy ) { - LazyInitializer li = ( (HibernateProxy) element ).getHibernateLazyInitializer(); + final LazyInitializer li = HibernateProxy.extractLazyInitializer( element ); + if ( li != null ) { if ( !li.isUninitialized() ) { element = li.getImplementation(); } diff --git a/hibernate-core/src/main/java/org/hibernate/type/EntityType.java b/hibernate-core/src/main/java/org/hibernate/type/EntityType.java index dc41a19c5f..b8b155ff43 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/EntityType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/EntityType.java @@ -24,8 +24,12 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.UniqueKeyLoadable; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; import org.hibernate.type.spi.TypeConfiguration; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * Base for types which map associations to persistent entities. * @@ -320,8 +324,9 @@ public abstract class EntityType extends AbstractType implements AssociationType } final Object id; - if ( x instanceof HibernateProxy ) { - id = ( (HibernateProxy) x ).getHibernateLazyInitializer().getInternalIdentifier(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( x ); + if ( lazyInitializer != null ) { + id = lazyInitializer.getInternalIdentifier(); } else { final Class mappedClass = persister.getMappedClass(); @@ -349,9 +354,9 @@ public abstract class EntityType extends AbstractType implements AssociationType final Class mappedClass = persister.getMappedClass(); Object xid; - if ( x instanceof HibernateProxy ) { - xid = ( (HibernateProxy) x ).getHibernateLazyInitializer() - .getInternalIdentifier(); + final LazyInitializer lazyInitializerX = HibernateProxy.extractLazyInitializer( x ); + if ( lazyInitializerX != null ) { + xid = lazyInitializerX.getInternalIdentifier(); } else { if ( mappedClass.isAssignableFrom( x.getClass() ) ) { @@ -364,9 +369,9 @@ public abstract class EntityType extends AbstractType implements AssociationType } Object yid; - if ( y instanceof HibernateProxy ) { - yid = ( (HibernateProxy) y ).getHibernateLazyInitializer() - .getInternalIdentifier(); + final LazyInitializer lazyInitializerY = HibernateProxy.extractLazyInitializer( y ); + if ( lazyInitializerY != null ) { + yid = lazyInitializerY.getInternalIdentifier(); } else { if ( mappedClass.isAssignableFrom( y.getClass() ) ) { @@ -505,8 +510,8 @@ public abstract class EntityType extends AbstractType implements AssociationType if ( persister.hasIdentifierProperty() ) { final Object id; - if ( value instanceof HibernateProxy ) { - HibernateProxy proxy = (HibernateProxy) value; + if ( isHibernateProxy( value ) ) { + HibernateProxy proxy = asHibernateProxy( value ); id = proxy.getHibernateLazyInitializer().getInternalIdentifier(); } else { @@ -652,9 +657,9 @@ public abstract class EntityType extends AbstractType implements AssociationType isNullable() ); - if ( proxyOrEntity instanceof HibernateProxy ) { - ( (HibernateProxy) proxyOrEntity ).getHibernateLazyInitializer() - .setUnwrap( isProxyUnwrapEnabled ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxyOrEntity ); + if ( lazyInitializer != null ) { + lazyInitializer.setUnwrap( isProxyUnwrapEnabled ); } return proxyOrEntity; diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/SuperTypesEnhancementTest.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/SuperTypesEnhancementTest.java new file mode 100644 index 0000000000..42eb30db72 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/SuperTypesEnhancementTest.java @@ -0,0 +1,117 @@ +/* + * 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 . + */ +package org.hibernate.bytecode.internal.bytebuddy; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Stream; + +import org.hibernate.LazyInitializationException; +import org.hibernate.engine.spi.PrimeAmongSecondarySupertypes; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.ProxyFactory; +import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyFactory; +import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyHelper; + +import org.hibernate.testing.TestForIssue; +import org.junit.Assert; +import org.junit.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * Verifies that proxies being generated by ByteBuddyProxyHelper + * do not break the contract with PrimeAmongSecondarySupertypes. + * A problem in this are could obviously manifest as a semantic + * issue, but could also manifest solely as a performance issue; + * therefore we check implementation details via unit tests + * rather than the typical integration test we'd have in such cases. + * + * @author Sanne Grinovero + */ +@TestForIssue( jiraKey = "HHH-15790" ) +public class SuperTypesEnhancementTest { + + private static final ByteBuddyProxyHelper helper = new ByteBuddyProxyHelper( new ByteBuddyState() ); + + private static Stream superTypeMethods() { + return Arrays.stream( PrimeAmongSecondarySupertypes.class.getDeclaredMethods() ).map( e -> Arguments.of( e ) ); + } + + private static Stream interfaces() { + return Arrays.stream( PrimeAmongSecondarySupertypes.class.getDeclaredMethods() ).map( m -> m.getReturnType() ).map( e -> Arguments.of( e ) ); + } + + @ParameterizedTest + @MethodSource("superTypeMethods") + public void testNamingConventions(Method m) { + final Class returnType = m.getReturnType(); + final String expectedMethodName = "as" + returnType.getSimpleName(); + Assert.assertEquals( expectedMethodName, m.getName() ); + Assert.assertNotNull( m.isDefault() ); + } + + @ParameterizedTest + @MethodSource("superTypeMethods") + public void testSubInterfaceOverrides(Method m) throws NoSuchMethodException { + final Class returnType = m.getReturnType(); + final Method subMethod = returnType.getMethod( m.getName(), m.getParameterTypes() ); + Assert.assertNotNull( subMethod ); + Assert.assertNotNull( subMethod.isDefault() ); + } + + @ParameterizedTest + @MethodSource("interfaces") + public void testAllProxyGeneration(Class secondarySuper) { + ProxyFactory enhancer = createProxyFactory( SampleClass.class, secondarySuper ); + final Object proxy = enhancer.getProxy( Integer.valueOf( 1 ), null ); + Assert.assertTrue( secondarySuper.isAssignableFrom( proxy.getClass() ) ); + PrimeAmongSecondarySupertypes casted = (PrimeAmongSecondarySupertypes) proxy; + testForLIE( (SampleClass) proxy ); + } + + @Test + public void testGeneratedHibernateProxy() { + ProxyFactory enhancer = createProxyFactory( SampleClass.class, HibernateProxy.class ); + final Object proxy = enhancer.getProxy( Integer.valueOf( 1 ), null ); + Assert.assertTrue( HibernateProxy.class.isAssignableFrom( proxy.getClass() ) ); + Assert.assertTrue( proxy instanceof HibernateProxy ); + PrimeAmongSecondarySupertypes casted = (PrimeAmongSecondarySupertypes) proxy; + final HibernateProxy extracted = casted.asHibernateProxy(); + Assert.assertNotNull( extracted ); + Assert.assertSame( proxy, extracted ); + testForLIE( (SampleClass) proxy ); + } + + /** + * Self-check: verify that this is in fact a lazy proxy + */ + private void testForLIE(SampleClass sampleProxy) { + SampleClass other = new SampleClass(); + Assert.assertEquals( 7, other.additionMethod( 3,4 ) ); + Assert.assertThrows( LazyInitializationException.class, () -> sampleProxy.additionMethod( 3, 4 ) ); + } + + private ProxyFactory createProxyFactory(Class persistentClass, Class... interfaces) { + ByteBuddyProxyFactory proxyFactory = new ByteBuddyProxyFactory( helper ); + proxyFactory.postInstantiate( "", persistentClass, Set.of( interfaces ), null, null, null ); + return proxyFactory; + } + + //Just a class with some fields and methods to proxy + static class SampleClass { + int intField; + String stringField; + + public int additionMethod(int a, int b) { + return a + b; + } + } + +} diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java b/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java index 262ef40ca6..8d6bd06c6d 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java @@ -20,6 +20,9 @@ import org.hibernate.envers.internal.tools.EntityTools; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.HibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * Base class for all Envers event listeners * @@ -92,8 +95,8 @@ public abstract class BaseEnversEventListener implements EnversListener { String toEntityName; Object id; - if ( value instanceof HibernateProxy ) { - final HibernateProxy hibernateProxy = (HibernateProxy) value; + if ( isHibernateProxy( value ) ) { + final HibernateProxy hibernateProxy = asHibernateProxy( value ); id = hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier(); // We've got to initialize the object from the proxy to later read its state. value = EntityTools.getTargetFromProxy( session.getFactory(), hibernateProxy ); diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/EntityInstantiator.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/EntityInstantiator.java index f6c1de5862..3f80d442e7 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/EntityInstantiator.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/EntityInstantiator.java @@ -19,6 +19,9 @@ import org.hibernate.envers.internal.tools.ReflectionTools; import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * @author Adam Warski (adam at warski dot org) * @author Hernán Chanfreau @@ -105,8 +108,8 @@ public class EntityInstantiator { final Map originalId = (Map) versionsEntity.get( enversService.getConfig().getOriginalIdPropertyName() ); for ( Object key : originalId.keySet() ) { final Object value = originalId.get( key ); - if ( value instanceof HibernateProxy ) { - final HibernateProxy hibernateProxy = (HibernateProxy) value; + if ( isHibernateProxy( value ) ) { + final HibernateProxy hibernateProxy = asHibernateProxy( value ); final LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer(); final String entityName = initializer.getEntityName(); final Object entityId = initializer.getInternalIdentifier(); diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/SingleIdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/SingleIdMapper.java index 905d311ffb..b3b65425eb 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/SingleIdMapper.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/SingleIdMapper.java @@ -15,6 +15,9 @@ import org.hibernate.envers.internal.entities.PropertyData; import org.hibernate.proxy.HibernateProxy; import org.hibernate.service.ServiceRegistry; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * An implementation of an identifier mapper for a single basic attribute property. * @@ -77,8 +80,8 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu return null; } - if ( data instanceof HibernateProxy ) { - final HibernateProxy hibernateProxy = (HibernateProxy) data; + if ( isHibernateProxy( data ) ) { + final HibernateProxy hibernateProxy = asHibernateProxy( data ); return hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier(); } else { @@ -99,8 +102,8 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu data.put( propertyData.getName(), null ); } else { - if ( obj instanceof HibernateProxy ) { - final HibernateProxy hibernateProxy = (HibernateProxy) obj; + if ( isHibernateProxy( obj ) ) { + final HibernateProxy hibernateProxy = asHibernateProxy( obj ); data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier() ); } else { diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java index a814275010..2e77cf9aa1 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java @@ -20,6 +20,9 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.EntityType; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * An extension to the {@link SingleIdMapper} implementation that supports the use case of an {@code @IdClass} * mapping that contains an entity association where the {@code @IdClass} stores the primary key of the @@ -130,8 +133,8 @@ public class VirtualEntitySingleIdMapper extends SingleIdMapper { data.put( propertyData.getName(), null ); } else { - if ( obj instanceof HibernateProxy ) { - final HibernateProxy proxy = (HibernateProxy) obj; + if ( isHibernateProxy( obj ) ) { + final HibernateProxy proxy = asHibernateProxy( obj ); data.put( propertyData.getName(), proxy.getHibernateLazyInitializer().getInternalIdentifier() ); } else { diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java index ff081dc6a6..9beb80c1ba 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java @@ -15,6 +15,9 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.HibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) */ @@ -31,8 +34,8 @@ public abstract class EntityTools { return null; } - if ( obj instanceof HibernateProxy ) { - final HibernateProxy hibernateProxy = (HibernateProxy) obj; + if ( isHibernateProxy( obj ) ) { + final HibernateProxy hibernateProxy = asHibernateProxy( obj ); return hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier(); } diff --git a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/manytoone/unidirectional/RelationNotAuditedTarget.java b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/manytoone/unidirectional/RelationNotAuditedTarget.java index 075cbde180..675ed4bc11 100644 --- a/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/manytoone/unidirectional/RelationNotAuditedTarget.java +++ b/hibernate-envers/src/test/java/org/hibernate/orm/test/envers/integration/manytoone/unidirectional/RelationNotAuditedTarget.java @@ -20,6 +20,9 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.junit.Test; +import static org.hibernate.engine.internal.ManagedTypeHelper.asHibernateProxy; +import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy; + /** * @author Tomasz Bech */ @@ -114,10 +117,9 @@ public class RelationNotAuditedTarget extends BaseEnversJPAFunctionalTestCase { } static Class getClassWithoutInitializingProxy(Object object) { - if (object instanceof HibernateProxy) { - HibernateProxy proxy = (HibernateProxy) object; - LazyInitializer li = proxy.getHibernateLazyInitializer(); - return li.getPersistentClass(); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object ); + if ( lazyInitializer != null ) { + return lazyInitializer.getPersistentClass(); } else { return object.getClass();