Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate;

/**
* Thrown if a detached instance of an entity class is passed to
* a {@link Session} method that expects a managed instance.
*
* @author Gavin King
*
* @since 7.0
*/
@Incubating
public class DetachedObjectException extends HibernateException {
public DetachedObjectException(String message) {
super( message );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
Expand All @@ -22,8 +21,6 @@
import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.spi.TypedValue;
Expand All @@ -37,6 +34,7 @@

import org.checkerframework.checker.nullness.qual.Nullable;

import static java.util.Collections.emptyIterator;
import static java.util.Collections.emptyList;
import static org.hibernate.collection.internal.CollectionLogger.COLLECTION_LOGGER;
import static org.hibernate.engine.internal.ForeignKeys.getEntityIdentifier;
Expand Down Expand Up @@ -686,15 +684,17 @@ public final boolean unsetSession(SharedSessionContractImplementor currentSessio
if ( allowLoadOutsideTransaction
&& !initialized
&& session.getLoadQueryInfluencers().hasEnabledFilters() ) {
COLLECTION_LOGGER.enabledFiltersWhenDetachFromSession( collectionInfoString( getRole(), getKey() ) );
COLLECTION_LOGGER.enabledFiltersWhenDetachFromSession(
collectionInfoString( getRole(), getKey() ) );
}
session = null;
}
return true;
}
else {
if ( session != null ) {
COLLECTION_LOGGER.logCannotUnsetUnexpectedSessionInCollection( unexpectedSessionStateMessage( currentSession ) );
COLLECTION_LOGGER.logCannotUnsetUnexpectedSessionInCollection(
unexpectedSessionStateMessage( currentSession ) );
}
return false;
}
Expand All @@ -704,20 +704,23 @@ private void logDiscardedQueuedOperations() {
try {
if ( wasTransactionRolledBack() ) {
// It was due to a rollback.
if ( COLLECTION_LOGGER.isDebugEnabled()) {
COLLECTION_LOGGER.queuedOperationWhenDetachFromSessionOnRollback( collectionInfoString( getRole(), getKey() ) );
if ( COLLECTION_LOGGER.isDebugEnabled() ) {
COLLECTION_LOGGER.queuedOperationWhenDetachFromSessionOnRollback(
collectionInfoString( getRole(), getKey() ) );
}
}
else {
// We don't know why the collection is being detached.
// Just log the info.
COLLECTION_LOGGER.queuedOperationWhenDetachFromSession( collectionInfoString( getRole(), getKey() ) );
COLLECTION_LOGGER.queuedOperationWhenDetachFromSession(
collectionInfoString( getRole(), getKey() ) );
}
}
catch (Exception e) {
// We don't know why the collection is being detached.
// Just log the info.
COLLECTION_LOGGER.queuedOperationWhenDetachFromSession( collectionInfoString( getRole(), getKey() ) );
COLLECTION_LOGGER.queuedOperationWhenDetachFromSession(
collectionInfoString( getRole(), getKey() ) );
}
}

Expand Down Expand Up @@ -756,7 +759,8 @@ else if ( this.session != null ) {
}
}
if ( hasQueuedOperations() ) {
COLLECTION_LOGGER.queuedOperationWhenAttachToSession( collectionInfoString( getRole(), getKey() ) );
COLLECTION_LOGGER.queuedOperationWhenAttachToSession(
collectionInfoString( getRole(), getKey() ) );
}
this.session = session;
return true;
Expand Down Expand Up @@ -872,7 +876,7 @@ public void remove() {
};
}
else {
return Collections.emptyIterator();
return emptyIterator();
}
}

Expand Down Expand Up @@ -1070,8 +1074,8 @@ public <A> A[] toArray(A[] array) {
public final boolean equals(Object object) {
return object == this
|| object instanceof Set<?> that
&& that.size() == this.size()
&& containsAll( that );
&& that.size() == this.size()
&& containsAll( that );
}

@Override
Expand Down Expand Up @@ -1306,11 +1310,11 @@ protected static <E> Collection<E> getOrphans(
// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
final java.util.Set<Object> currentIds = new HashSet<>();
final java.util.Set<Object> currentSaving = new IdentitySet<>();
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final var persistenceContext = session.getPersistenceContextInternal();
for ( Object current : currentElements ) {
if ( current != null && isNotTransient( entityName, current, null, session ) ) {
final EntityEntry ee = persistenceContext.getEntry( current );
if ( ee != null && ee.getStatus() == Status.SAVING ) {
final var entityEntry = persistenceContext.getEntry( current );
if ( entityEntry != null && entityEntry.getStatus() == Status.SAVING ) {
currentSaving.add( current );
}
else {
Expand All @@ -1335,7 +1339,7 @@ protected static <E> Collection<E> getOrphans(

private static boolean mayUseIdDirect(Type idType) {
if ( idType instanceof BasicType<?> basicType ) {
final Class<?> javaType = basicType.getJavaType();
final var javaType = basicType.getJavaType();
return javaType == String.class
|| javaType == Integer.class
|| javaType == Long.class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,9 @@ private static <T> void cascadeLogicalOneToOneOrphanRemoval(
if ( child == null || loadedValue != null && child != loadedValue ) {
EntityEntry valueEntry = persistenceContext.getEntry( loadedValue );
if ( valueEntry == null && isHibernateProxy( loadedValue ) ) {
// un-proxy and re-associate for cascade operation
// unproxy and reassociate for cascade operation
// useful for @OneToOne defined as FetchType.LAZY
//TODO: what should really happen here???
loadedValue = persistenceContext.unproxyAndReassociate( loadedValue );
valueEntry = persistenceContext.getEntry( loadedValue );
// HHH-11965
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.engine.internal;

import org.hibernate.DetachedObjectException;
import org.hibernate.PersistentObjectException;
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;

import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;

/**
* @author Gavin King
* @since 7.2
*/
public class ProxyUtil {

/**
* Get the entity instance underlying the given proxy, throwing
* an exception if the proxy is uninitialized. If the given
* object is not a proxy, simply return the argument.
*/
public static Object assertInitialized(Object maybeProxy) {
final var lazyInitializer = extractLazyInitializer( maybeProxy );
if ( lazyInitializer != null ) {
if ( lazyInitializer.isUninitialized() ) {
throw new PersistentObjectException( "Object was an uninitialized proxy for "
+ lazyInitializer.getEntityName() );
}
//unwrap the object and return
return lazyInitializer.getImplementation();
}
else {
return maybeProxy;
}
}

/**
* Get the entity instance underlying the given proxy, forcing
* initialization if the proxy is uninitialized. If the given
* object is not a proxy, simply return the argument.
* @throws DetachedObjectException if the given proxy does not
* belong to the given session
*/
public static Object forceInitialize(Object maybeProxy, SharedSessionContractImplementor session) {
final var lazyInitializer = extractLazyInitializer( maybeProxy );
if ( lazyInitializer != null ) {
if ( lazyInitializer.getSession() != session ) {
throw new DetachedObjectException( "Given proxy does not belong to this persistence context" );
}
//initialize + unwrap the object and return it
return lazyInitializer.getImplementation();
}
else if ( isPersistentAttributeInterceptable( maybeProxy ) ) {
final var interceptor =
asPersistentAttributeInterceptable( maybeProxy )
.$$_hibernate_getInterceptor();
if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor lazinessInterceptor ) {
if ( lazinessInterceptor.getLinkedSession() != session ) {
throw new DetachedObjectException( "Given proxy does not belong to this persistence context" );
}
lazinessInterceptor.forceInitialize( maybeProxy, null );
}
return maybeProxy;
}
else {
return maybeProxy;
}
}

/**
* Determine of the given proxy is uninitialized. If the given
* object is not a proxy, simply return false.
* @throws DetachedObjectException if the given proxy does not
* belong to the given session
*/
public static boolean isUninitialized(Object value, SharedSessionContractImplementor session) {
// could be a proxy
final var lazyInitializer = extractLazyInitializer( value );
if ( lazyInitializer != null ) {
if ( lazyInitializer.getSession() != session ) {
throw new DetachedObjectException( "Given proxy does not belong to this persistence context" );
}
return lazyInitializer.isUninitialized();
}
// or an uninitialized enhanced entity ("bytecode proxy")
else if ( isPersistentAttributeInterceptable( value ) ) {
final var interceptor =
(BytecodeLazyAttributeInterceptor)
asPersistentAttributeInterceptable( value )
.$$_hibernate_getInterceptor();
if ( interceptor != null && interceptor.getLinkedSession() != session ) {
throw new DetachedObjectException( "Given proxy does not belong to this persistence context" );
}
return interceptor instanceof EnhancementAsProxyLazinessInterceptor enhancementInterceptor
&& !enhancementInterceptor.isInitialized();
}
else {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.PersistentObjectException;
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
import org.hibernate.collection.spi.PersistentCollection;
Expand Down Expand Up @@ -691,26 +690,35 @@ public boolean containsProxy(Object entity) {

@Override
public boolean reassociateIfUninitializedProxy(Object value) throws MappingException {
if ( !Hibernate.isInitialized( value ) ) {
// could be a proxy
final var lazyInitializer = extractLazyInitializer( value );
if ( lazyInitializer != null ) {
if ( Hibernate.isInitialized( value ) ) {
return false;
}
// could be a proxy
final var lazyInitializer = extractLazyInitializer( value );
if ( lazyInitializer != null ) {
final boolean uninitialized = lazyInitializer.isUninitialized();
if ( uninitialized ) {
reassociateProxy( lazyInitializer, asHibernateProxy( value ) );
return true;
}
// or an uninitialized enhanced entity ("bytecode proxy")
if ( isPersistentAttributeInterceptable( value ) ) {
final var bytecodeProxy = asPersistentAttributeInterceptable( value );
final var interceptor =
(BytecodeLazyAttributeInterceptor)
bytecodeProxy.$$_hibernate_getInterceptor();
if ( interceptor != null ) {
interceptor.setSession( getSession() );
}
return true;
return uninitialized;
}
// or an uninitialized enhanced entity ("bytecode proxy")
else if ( isPersistentAttributeInterceptable( value ) ) {
final var interceptor =
(BytecodeLazyAttributeInterceptor)
asPersistentAttributeInterceptable( value )
.$$_hibernate_getInterceptor();
final boolean uninitialized =
interceptor instanceof EnhancementAsProxyLazinessInterceptor enhancementInterceptor
&& !enhancementInterceptor.isInitialized();
if ( uninitialized ) {
interceptor.setSession( getSession() );
}
return uninitialized;
}
else {
return false;
}
return false;
}

@Override
Expand Down Expand Up @@ -750,22 +758,6 @@ private void reassociateProxy(LazyInitializer li, HibernateProxy proxy) {
}
}

@Override
public Object unproxy(Object maybeProxy) throws HibernateException {
final var lazyInitializer = extractLazyInitializer( maybeProxy );
if ( lazyInitializer != null ) {
if ( lazyInitializer.isUninitialized() ) {
throw new PersistentObjectException( "object was an uninitialized proxy for "
+ lazyInitializer.getEntityName() );
}
//unwrap the object and return
return lazyInitializer.getImplementation();
}
else {
return maybeProxy;
}
}

@Override
public Object unproxyAndReassociate(final Object maybeProxy) throws HibernateException {
final var lazyInitializer = extractLazyInitializer( maybeProxy );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.hibernate.Internal;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.ProxyUtil;
import org.hibernate.internal.util.MarkerObject;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
Expand Down Expand Up @@ -293,8 +294,12 @@ EntityEntry addReferenceEntry(
* Get the entity instance underlying the given proxy, throwing
* an exception if the proxy is uninitialized. If the given object
* is not a proxy, simply return the argument.
* @deprecated No longer used
*/
Object unproxy(Object maybeProxy);
@Deprecated(since = "7.2", forRemoval = true)
default Object unproxy(Object maybeProxy) {
return ProxyUtil.assertInitialized( maybeProxy );
}

/**
* Possibly unproxy the given reference and reassociate it with the current session.
Expand Down
Loading