HHH-16577 Bytecode enhancement and @DynamicUpdate causes Index Out of Bound Exception

This commit is contained in:
Andrea Boriero 2023-08-09 16:22:49 +02:00 committed by Andrea Boriero
parent bcf13cc98a
commit 7170403fcf
1 changed files with 22 additions and 23 deletions

View File

@ -15,9 +15,9 @@ import org.hibernate.LockMode;
import org.hibernate.bytecode.BytecodeLogging;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
@ -102,36 +102,40 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter
return EnhancementHelper.performWork(
this,
(session, isTempSession) -> {
final Object[] writtenValues;
final Object[] writtenAttributeValues;
final AttributeMapping[] writtenAttributeMappings;
final EntityPersister entityPersister = session.getFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( getEntityName() );
final EntityPersister entityPersister =
session.getFactory().getMappingMetamodel()
.getEntityDescriptor( getEntityName() );
if ( writtenFieldNames != null && !writtenFieldNames.isEmpty() ) {
// enhancement has dirty-tracking available and at least one attribute was explicitly set
if ( writtenFieldNames.contains( attributeName ) ) {
// the requested attribute was one of the attributes explicitly set, we can just return the explicitly set value
// the requested attribute was one of the attributes explicitly set,
// we can just return the explicitly-set value
return entityPersister.getPropertyValue( target, attributeName );
}
// otherwise we want to save all of the explicitly set values in anticipation of
// otherwise we want to save all the explicitly-set values in anticipation of
// the force initialization below so that we can "replay" them after the
// initialization
writtenValues = new Object[writtenFieldNames.size()];
writtenAttributeValues = new Object[writtenFieldNames.size()];
writtenAttributeMappings = new AttributeMapping[writtenFieldNames.size()];
int index = 0;
for ( String writtenFieldName : writtenFieldNames ) {
writtenValues[index] = entityPersister.getPropertyValue( target, writtenFieldName );
writtenAttributeMappings[index] = entityPersister.findAttributeMapping( writtenFieldName );
writtenAttributeValues[index] = writtenAttributeMappings[index].getValue( target );
index++;
}
}
else {
writtenValues = null;
writtenAttributeValues = null;
writtenAttributeMappings = null;
}
final Object initializedValue = forceInitialize(
@ -143,18 +147,13 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter
setInitialized();
if ( writtenValues != null ) {
if ( writtenAttributeValues != null ) {
// here is the replaying of the explicitly set values we prepared above
for ( String writtenFieldName : writtenFieldNames ) {
final int size = entityPersister.getNumberOfAttributeMappings();
for ( int index = 0; index < size; index++ ) {
if ( writtenFieldName.contains( entityPersister.getAttributeMapping( index ).getAttributeName() ) ) {
entityPersister.setValue(
target,
index,
writtenValues[index]
);
}
for ( int i = 0; i < writtenAttributeMappings.length; i++ ) {
final AttributeMapping attribute = writtenAttributeMappings[i];
attribute.setValue( target, writtenAttributeValues[i] );
if ( inLineDirtyChecking ) {
asSelfDirtinessTracker( target ).$$_hibernate_trackChange( attribute.getAttributeName() );
}
}
writtenFieldNames.clear();
@ -246,7 +245,7 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter
if ( identifierAttributeNames.contains( attributeName ) ) {
// it is illegal for the identifier value to be changed. Normally Hibernate
// validates this during flush. However, here it is dangerous to just allow the
// validates this during flush. However, here it's dangerous to just allow the
// new value to be set and continue on waiting for the flush for validation
// because this interceptor manages the entity's entry in the PC itself. So
// just do the check here up-front