Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade orm to 6.4 #1789

Merged
merged 1 commit into from
Nov 24, 2023
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Hibernate Reactive has been tested with:
- CockroachDB 22.1
- MS SQL Server 2019
- Oracle 21.3
- [Hibernate ORM][] 6.3.2.Final
- [Hibernate ORM][] 6.4.0.Final
- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.0
- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.0
- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.0
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ version = projectVersion
// ./gradlew clean build -PhibernateOrmVersion=5.6.15-SNAPSHOT
ext {
if ( !project.hasProperty('hibernateOrmVersion') ) {
hibernateOrmVersion = '6.3.2.Final'
hibernateOrmVersion = '6.4.0.Final'
}
if ( !project.hasProperty( 'hibernateOrmGradlePluginVersion' ) ) {
// Same as ORM as default
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ org.gradle.java.installations.auto-download=false
#enableMavenLocalRepo = true

# Override default Hibernate ORM version
#hibernateOrmVersion = 6.2.3.Final
#hibernateOrmVersion = 6.4.0.Final

# Override default Hibernate ORM Gradle plugin version
# Using the stable version because I don't know how to configure the build to download the snapshot version from
# a remote repository
#hibernateOrmGradlePluginVersion = 6.2.3.Final
#hibernateOrmGradlePluginVersion = 6.4.0.Final

# If set to true, skip Hibernate ORM version parsing (default is true, if set to null)
# this is required when using intervals or weird versions or the build will fail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.reactive.logging.impl.Log;
import org.hibernate.reactive.logging.impl.LoggerFactory;
import org.hibernate.reactive.session.ReactiveSession;
Expand All @@ -40,6 +39,7 @@
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;

import static org.hibernate.engine.internal.ManagedTypeHelper.isHibernateProxy;
import static org.hibernate.pretty.MessageHelper.infoString;
import static org.hibernate.reactive.util.impl.CompletionStages.loop;
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
Expand Down Expand Up @@ -111,9 +111,9 @@ public static CompletionStage<?> fetchLazyAssociationsBeforeCascade(
* Cascade an action from the parent entity instance to all its children.
*/
public CompletionStage<Void> cascade() throws HibernateException {
return voidFuture().thenCompose(v -> {
return voidFuture().thenCompose( v -> {
CacheMode cacheMode = eventSource.getCacheMode();
if ( action==CascadingActions.DELETE ) {
if ( action == CascadingActions.DELETE ) {
eventSource.setCacheMode( CacheMode.GET );
}
eventSource.getPersistenceContextInternal().incrementCascadeLevel();
Expand All @@ -125,18 +125,23 @@ public CompletionStage<Void> cascade() throws HibernateException {
}

private CompletionStage<Void> cascadeInternal() throws HibernateException {

if ( persister.hasCascades() || action.requiresNoCascadeChecking() ) { // performance opt
final boolean traceEnabled = LOG.isTraceEnabled();
if ( traceEnabled ) {
LOG.tracev( "Processing cascade {0} for: {1}", action, persister.getEntityName() );
}
final PersistenceContext persistenceContext = eventSource.getPersistenceContextInternal();
final EntityEntry entry = persistenceContext.getEntry( parent );
if ( entry != null && entry.getLoadedState() == null && entry.getStatus() == Status.MANAGED && persister.getBytecodeEnhancementMetadata()
.isEnhancedForLazyLoading() ) {
return voidFuture();
}

final Type[] types = persister.getPropertyTypes();
final String[] propertyNames = persister.getPropertyNames();
final CascadeStyle[] cascadeStyles = persister.getPropertyCascadeStyles();
final boolean hasUninitializedLazyProperties = persister.hasUninitializedLazyProperties( parent );

for ( int i = 0; i < types.length; i++) {
final CascadeStyle style = cascadeStyles[ i ];
final String propertyName = propertyNames[ i ];
Expand All @@ -154,7 +159,7 @@ private CompletionStage<Void> cascadeInternal() throws HibernateException {
// If parent is a detached entity being merged,
// then parent will not be in the PersistenceContext
// (so lazy attributes must not be initialized).
if ( persistenceContext.getEntry( parent ) == null ) {
if ( entry == null ) {
// parent was not in the PersistenceContext
continue;
}
Expand Down Expand Up @@ -295,91 +300,88 @@ private void cascadeLogicalOneToOneOrphanRemoval(
final String propertyName,
final boolean isCascadeDeleteEnabled) throws HibernateException {

// potentially we need to handle orphan deletes for one-to-ones here...
if ( isLogicalOneToOne( type ) ) {
// We have a physical or logical one-to-one. See if the attribute cascade settings and action-type require
// orphan checking
if ( style.hasOrphanDelete() && action.deleteOrphans() ) {
// value is orphaned if loaded state for this property shows not null
// because it is currently null.
final PersistenceContext persistenceContext = eventSource.getPersistenceContextInternal();
final EntityEntry entry = persistenceContext.getEntry( parent );
if ( entry != null && entry.getStatus() != Status.SAVING ) {
Object loadedValue;
if ( componentPath == null ) {
// association defined on entity
loadedValue = entry.getLoadedValue( propertyName );
// We have a physical or logical one-to-one. See if the attribute cascade settings and action-type require
// orphan checking
if ( style.hasOrphanDelete() && action.deleteOrphans() ) {
// value is orphaned if loaded state for this property shows not null
// because it is currently null.
final PersistenceContext persistenceContext = eventSource.getPersistenceContextInternal();
final EntityEntry entry = persistenceContext.getEntry( parent );
if ( entry != null && entry.getStatus() != Status.SAVING ) {
Object loadedValue;
if ( componentPath == null ) {
// association defined on entity
loadedValue = entry.getLoadedValue( propertyName );
}
else {
// association defined on component
// Since the loadedState in the EntityEntry is a flat domain type array
// We first have to extract the component object and then ask the component type
// recursively to give us the value of the sub-property of that object
final AttributeMapping propertyType = entry.getPersister().findAttributeMapping( componentPath.get( 0) );
if ( propertyType instanceof ComponentType) {
loadedValue = entry.getLoadedValue( componentPath.get( 0 ) );
ComponentType componentType = (ComponentType) propertyType;
if ( componentPath.size() != 1 ) {
for ( int i = 1; i < componentPath.size(); i++ ) {
final int subPropertyIndex = componentType.getPropertyIndex( componentPath.get( i ) );
loadedValue = componentType.getPropertyValue( loadedValue, subPropertyIndex );
componentType = (ComponentType) componentType.getSubtypes()[subPropertyIndex];
}
}

loadedValue = componentType.getPropertyValue( loadedValue, componentType.getPropertyIndex( propertyName ) );
}
else {
// association defined on component
// Since the loadedState in the EntityEntry is a flat domain type array
// We first have to extract the component object and then ask the component type
// recursively to give us the value of the sub-property of that object
final AttributeMapping propertyType = entry.getPersister().findAttributeMapping( componentPath.get( 0) );
if ( propertyType instanceof ComponentType) {
loadedValue = entry.getLoadedValue( componentPath.get( 0 ) );
ComponentType componentType = (ComponentType) propertyType;
if ( componentPath.size() != 1 ) {
for ( int i = 1; i < componentPath.size(); i++ ) {
final int subPropertyIndex = componentType.getPropertyIndex( componentPath.get( i ) );
loadedValue = componentType.getPropertyValue( loadedValue, subPropertyIndex );
componentType = (ComponentType) componentType.getSubtypes()[subPropertyIndex];
}
}
// Association is probably defined in an element collection, so we can't do orphan removals
loadedValue = null;
}
}

loadedValue = componentType.getPropertyValue( loadedValue, componentType.getPropertyIndex( propertyName ) );
}
else {
// Association is probably defined in an element collection, so we can't do orphan removals
loadedValue = null;
// orphaned if the association was nulled (child == null) or receives a new value while the
// entity is managed (without first nulling and manually flushing).
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
// useful for @OneToOne defined as FetchType.LAZY
loadedValue = persistenceContext.unproxyAndReassociate( loadedValue );
valueEntry = persistenceContext.getEntry( loadedValue );

// HHH-11965
// Should the unwrapped proxy value be equal via reference to the entity's property value
// provided by the 'child' variable, we should not trigger the orphan removal of the
// associated one-to-one.
if ( child == loadedValue ) {
// do nothing
return;
}
}

// orphaned if the association was nulled (child == null) or receives a new value while the
// entity is managed (without first nulling and manually flushing).
if ( child == null || loadedValue != null && child != loadedValue ) {
EntityEntry valueEntry = persistenceContext.getEntry( loadedValue );

if ( valueEntry == null && loadedValue instanceof HibernateProxy ) {
// un-proxy and re-associate for cascade operation
// useful for @OneToOne defined as FetchType.LAZY
loadedValue = persistenceContext.unproxyAndReassociate( loadedValue );
valueEntry = persistenceContext.getEntry( loadedValue );

// HHH-11965
// Should the unwrapped proxy value be equal via reference to the entity's property value
// provided by the 'child' variable, we should not trigger the orphan removal of the
// associated one-to-one.
if ( child == loadedValue ) {
// do nothing
return;
}
if ( valueEntry != null ) {
final EntityPersister persister = valueEntry.getPersister();
final String entityName = persister.getEntityName();
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
"Deleting orphaned entity instance: {0}",
infoString( entityName, persister.getIdentifier( loadedValue, eventSource ) )
);
}

if ( valueEntry != null ) {
final EntityPersister persister = valueEntry.getPersister();
final String entityName = persister.getEntityName();
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
"Deleting orphaned entity instance: {0}",
infoString( entityName, persister.getIdentifier( loadedValue, eventSource ) )
);
}

final Object loaded = loadedValue;
if ( type.isAssociationType()
&& ( (AssociationType) type ).getForeignKeyDirection().equals(TO_PARENT) ) {
// If FK direction is to-parent, we must remove the orphan *before* the queued update(s)
// occur. Otherwise, replacing the association on a managed entity, without manually
// nulling and flushing, causes FK constraint violations.
stage = stage.thenCompose( v -> ( (ReactiveSession) eventSource )
.reactiveRemoveOrphanBeforeUpdates( entityName, loaded ) );
}
else {
// Else, we must delete after the updates.
stage = stage.thenCompose( v -> ( (ReactiveSession) eventSource )
.reactiveRemove( entityName, loaded, isCascadeDeleteEnabled, DeleteContext.create() ) );
}
final Object loaded = loadedValue;
if ( type.isAssociationType()
&& ( (AssociationType) type ).getForeignKeyDirection().equals(TO_PARENT) ) {
// If FK direction is to-parent, we must remove the orphan *before* the queued update(s)
// occur. Otherwise, replacing the association on a managed entity, without manually
// nulling and flushing, causes FK constraint violations.
stage = stage.thenCompose( v -> ( (ReactiveSession) eventSource )
.reactiveRemoveOrphanBeforeUpdates( entityName, loaded ) );
}
else {
// Else, we must delete after the updates.
stage = stage.thenCompose( v -> ( (ReactiveSession) eventSource )
.reactiveRemove( entityName, loaded, isCascadeDeleteEnabled, DeleteContext.create() ) );
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ protected void logFlushResults(FlushEvent event) {
persistenceContext.getCollectionEntriesSize()
);
new EntityPrinter( session.getFactory() ).toString(
persistenceContext.getEntitiesByKey().entrySet()
persistenceContext.getEntityHoldersByKey().entrySet()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
*/
package org.hibernate.reactive.event.impl;

import static org.hibernate.pretty.MessageHelper.collectionInfoString;
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;

import java.lang.invoke.MethodHandles;
import java.util.concurrent.CompletionStage;

Expand All @@ -29,6 +26,9 @@
import org.hibernate.sql.results.internal.ResultsHelper;
import org.hibernate.stat.spi.StatisticsImplementor;

import static org.hibernate.pretty.MessageHelper.collectionInfoString;
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;

public class DefaultReactiveInitializeCollectionEventListener implements InitializeCollectionEventListener {

private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() );
Expand Down Expand Up @@ -144,7 +144,7 @@ private boolean initializeCollectionFromCache(
final SessionFactoryImplementor factory = source.getFactory();
final CollectionDataAccess cacheAccessStrategy = persister.getCacheAccessStrategy();
final Object ck = cacheAccessStrategy.generateCacheKey( id, persister, factory, source.getTenantIdentifier() );
final Object ce = CacheHelper.fromSharedCache( source, ck, cacheAccessStrategy );
final Object ce = CacheHelper.fromSharedCache( source, ck, persister, cacheAccessStrategy );

final StatisticsImplementor statistics = factory.getStatistics();
if ( statistics.isStatisticsEnabled() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ public CompletionStage<Void> reactiveOnRefresh(RefreshEvent event) throws Hibern

@Override
public void onRefresh(RefreshEvent event) throws HibernateException {
throw new UnsupportedOperationException();
throw LOG.nonReactiveMethodCall( "reactiveOnRefresh" );
}

@Override
public void onRefresh(RefreshEvent event, RefreshContext refreshedAlready) throws HibernateException {
throw new UnsupportedOperationException();
throw LOG.nonReactiveMethodCall( "reactiveOnRefresh" );
}

/**
Expand All @@ -83,16 +83,25 @@ public CompletionStage<Void> reactiveOnRefresh(RefreshEvent event, RefreshContex

if ( detached ) {
// Hibernate Reactive doesn't support detached instances in refresh()
throw new IllegalArgumentException("unmanaged instance passed to refresh()");
throw new IllegalArgumentException( "Unmanaged instance passed to refresh()" );
}
return ( (ReactiveSession) source ).reactiveFetch( event.getObject(), true )
return ( (ReactiveSession) source )
.reactiveFetch( event.getObject(), true )
.thenCompose( entity -> reactiveOnRefresh( event, refreshedAlready, entity ) );
}

private CompletionStage<Void> reactiveOnRefresh(RefreshEvent event, RefreshContext refreshedAlready, Object entity) {
private CompletionStage<Void> reactiveOnRefresh(RefreshEvent event, RefreshContext refreshedAlready, Object object) {
final EventSource source = event.getSession();
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();

if ( persistenceContext.reassociateIfUninitializedProxy( object ) ) {
if ( isTransient( event, source, object ) ) {
source.setReadOnly( object, source.isDefaultReadOnly() );
}
return voidFuture();
}

Object entity = persistenceContext.unproxyAndReassociate( object );
if ( !refreshedAlready.add( entity) ) {
LOG.trace( "Already refreshed" );
return voidFuture();
Expand Down Expand Up @@ -169,6 +178,11 @@ private CompletionStage<Void> reactiveOnRefresh(RefreshEvent event, RefreshConte
} );
}

private static boolean isTransient(RefreshEvent event, EventSource source, Object object) {
final String entityName = event.getEntityName();
return entityName != null ? !source.contains( entityName, object) : !source.contains(object);
}

private static void evictEntity(Object entity, EntityPersister persister, Object id, EventSource source) {
if ( persister.canWriteToCache() ) {
Object previousVersion = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
*/
package org.hibernate.reactive.loader.ast.internal;

import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.EntityHolder;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.sql.exec.internal.BaseExecutionContext;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;

/**
* Copy and paste of {@link org.hibernate.loader.ast.internal.ExecutionContextWithSubselectFetchHandler}
Expand All @@ -25,9 +24,9 @@ public ExecutionContextWithSubselectFetchHandler(SharedSessionContractImplemento
}

@Override
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
public void registerLoadingEntityHolder(EntityHolder holder) {
if ( subSelectFetchableKeysHandler != null ) {
subSelectFetchableKeysHandler.addKey( entityKey, entry );
subSelectFetchableKeysHandler.addKey( holder );
}
}

Expand Down
Loading