From 3838bb19fa7e6360807357bf12c29402f9065827 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 16 Sep 2024 17:52:13 +0200 Subject: [PATCH] HHH-18608 NPE in EntityInitializerImpl.resolveInstanceSubInitializers --- .../OracleUserDefinedTypeExporter.java | 6 ++++-- .../entity/AbstractEntityPersister.java | 10 +++++++++ .../internal/EntityInitializerImpl.java | 21 +++++++++++++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java index b4d7fd0e3968..c9cbe4837203 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java @@ -312,7 +312,8 @@ public String[] getSqlDropStrings(UserDefinedArrayType userDefinedType, Metadata private String buildDropTypeSqlString(String arrayTypeName) { if ( dialect.supportsIfExistsBeforeTypeName() ) { return "drop type if exists " + arrayTypeName + " force"; - } else { + } + else { return "drop type " + arrayTypeName + " force"; } } @@ -320,7 +321,8 @@ private String buildDropTypeSqlString(String arrayTypeName) { private String buildDropFunctionSqlString(String functionTypeName) { if ( supportsIfExistsBeforeFunctionName() ) { return "drop function if exists " + functionTypeName; - } else { + } + else { return "drop function " + functionTypeName; } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index c54a747c14e4..97c05015cd3c 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -276,6 +276,7 @@ import org.hibernate.type.ComponentType; import org.hibernate.type.CompositeType; import org.hibernate.type.EntityType; +import org.hibernate.type.ManyToOneType; import org.hibernate.type.Type; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.MutabilityPlan; @@ -1183,6 +1184,15 @@ private static List initUniqueKeyEntries(final AbstractEntityPer uniqueKeys.add( new UniqueKeyEntry( ukName, index, type ) ); } } + else if ( associationType instanceof ManyToOneType manyToOneType + && manyToOneType.isLogicalOneToOne() && manyToOneType.isReferenceToPrimaryKey() ) { + final AttributeMapping attributeMapping = aep.findAttributeMapping( manyToOneType.getPropertyName() ); + if ( attributeMapping != null ) { + final int index = attributeMapping.getStateArrayPosition(); + final Type type = aep.getPropertyTypes()[index]; + uniqueKeys.add( new UniqueKeyEntry( manyToOneType.getPropertyName(), index, type ) ); + } + } } } return toSmallList( uniqueKeys ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java index 2b8a64324576..77099a5e3111 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java @@ -23,6 +23,7 @@ import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.entry.CacheEntry; +import org.hibernate.engine.internal.ForeignKeys; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityHolder; import org.hibernate.engine.spi.EntityKey; @@ -75,6 +76,7 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.stat.spi.StatisticsImplementor; +import org.hibernate.type.ManyToOneType; import org.hibernate.type.Type; import org.hibernate.type.descriptor.java.MutabilityPlan; @@ -622,6 +624,8 @@ private boolean areKeysEqual(Object key1, Object key2) { protected void resolveInstanceSubInitializers(EntityInitializerData data) { final int subclassId = data.concreteDescriptor.getSubclassId(); final EntityEntry entityEntry = data.entityHolder.getEntityEntry(); + assert entityEntry != null : "This method should only be called if the entity is already initialized"; + final Initializer[] initializers; final ImmutableBitSet maybeLazySet; if ( data.entityHolder.getEntityInitializer() == this ) { @@ -981,11 +985,13 @@ else if ( lazyInitializer.isUninitialized() ) { registerLoadingEntity( data, data.entityInstanceForNotify ); } else { - data.setState( State.INITIALIZED ); data.entityInstanceForNotify = lazyInitializer.getImplementation(); data.concreteDescriptor = session.getEntityPersister( null, data.entityInstanceForNotify ); resolveEntityKey( data, lazyInitializer.getIdentifier() ); data.entityHolder = persistenceContext.getEntityHolder( data.entityKey ); + // Even though the lazyInitializer reports it is initialized, check if the entity holder reports initialized, + // because in a nested initialization scenario, this nested initializer must initialize the entity + data.setState( data.entityHolder.isInitialized() ? State.INITIALIZED : State.RESOLVED ); } if ( identifierAssembler != null ) { final Initializer initializer = identifierAssembler.getInitializer(); @@ -1582,11 +1588,22 @@ protected void registerPossibleUniqueKeyEntries( // one used here, which it will be if ( resolvedEntityState[index] != null ) { + final Object key; + if ( type instanceof ManyToOneType manyToOneType ) { + key = ForeignKeys.getEntityIdentifierIfNotUnsaved( + manyToOneType.getAssociatedEntityName(), + resolvedEntityState[index], + session + ); + } + else { + key = resolvedEntityState[index]; + } final EntityUniqueKey entityUniqueKey = new EntityUniqueKey( data.concreteDescriptor.getRootEntityDescriptor().getEntityName(), //polymorphism comment above ukName, - resolvedEntityState[index], + key, type, session.getFactory() );