From e8c1eacf26ec72ea2fc51bf43f86319ccf18c361 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 7 Apr 2025 12:02:28 +0200 Subject: [PATCH] refactor a much too long and confusing method on AbstractEntityPersister --- .../entity/AbstractEntityPersister.java | 258 +++++++++--------- .../spi/SqmMultiTableInsertStrategy.java | 9 + .../spi/SqmMultiTableMutationStrategy.java | 9 + 3 files changed, 143 insertions(+), 133 deletions(-) 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 0d453da7fa7d..19763c3c8137 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 @@ -514,11 +514,12 @@ public AbstractEntityPersister( // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - representationStrategy = creationContext.getBootstrapContext().getRepresentationStrategySelector() - .resolveStrategy( persistentClass, this, creationContext ); - + representationStrategy = + creationContext.getBootstrapContext().getRepresentationStrategySelector() + .resolveStrategy( persistentClass, this, creationContext ); javaType = representationStrategy.getLoadJavaType(); assert javaType != null; + accessOptimizer = accessOptimizer( representationStrategy ); concreteProxy = entityMetamodel.isPolymorphic() && ( getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() || hasProxy() ) @@ -4438,13 +4439,9 @@ protected List initUpdateGeneratedProperties(List action) { } @Override - public void forEachAttributeMapping(final IndexedConsumer consumer) { + public void forEachAttributeMapping(IndexedConsumer consumer) { attributeMappings.indexedForEach( consumer ); } @Override public void prepareMappingModel(MappingModelCreationProcess creationProcess) { - if ( identifierMapping != null ) { - return; + if ( identifierMapping == null ) { + prepareMappings( creationProcess ); + handleSubtypeMappings( creationProcess ); + prepareMultiTableMutationStrategy( creationProcess ); + prepareMultiTableInsertStrategy( creationProcess ); } + } - final RuntimeModelCreationContext creationContext = creationProcess.getCreationContext(); + private void handleSubtypeMappings(MappingModelCreationProcess creationProcess) { + // Register a callback for after all `#prepareMappingModel` calls have finished. Here we want to delay the + // generation of `staticFetchableList` because we need to wait until after all subclasses have had their + // `#prepareMappingModel` called (and their declared attribute mappings resolved) + creationProcess.registerInitializationCallback( + "Entity(" + getEntityName() + ") `staticFetchableList` generator", + () -> { + final var builder = new ImmutableAttributeMappingList.Builder( attributeMappings.size() ); + visitSubTypeAttributeMappings( builder::add ); + assert superMappingType != null || builder.assertFetchableIndexes(); + staticFetchableList = builder.build(); + return true; + } + ); + } - final PersistentClass bootEntityDescriptor = creationContext - .getBootModel() - .getEntityBinding( getEntityName() ); + private static ReflectionOptimizer.AccessOptimizer accessOptimizer(EntityRepresentationStrategy strategy) { + final ReflectionOptimizer reflectionOptimizer = strategy.getReflectionOptimizer(); + return reflectionOptimizer == null ? null : reflectionOptimizer.getAccessOptimizer(); + } -// EntityMappingType rootEntityDescriptor; + private void prepareMappings(MappingModelCreationProcess creationProcess) { + final PersistentClass bootEntityDescriptor = + creationProcess.getCreationContext().getBootModel() + .getEntityBinding( getEntityName() ); + initializeSpecialAttributeMappings( creationProcess, bootEntityDescriptor ); + versionGenerator = createVersionGenerator( entityMetamodel, versionMapping ); + buildDeclaredAttributeMappings( creationProcess, bootEntityDescriptor ); + getAttributeMappings(); + initializeNaturalIdMapping( creationProcess, bootEntityDescriptor ); + } + + private void initializeSpecialAttributeMappings + (MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { if ( superMappingType != null ) { - ( (InFlightEntityMappingType) superMappingType ).prepareMappingModel( creationProcess ); + ((InFlightEntityMappingType) superMappingType).prepareMappingModel( creationProcess ); if ( shouldProcessSuperMapping() ) { - discriminatorMapping = superMappingType.getDiscriminatorMapping(); - identifierMapping = superMappingType.getIdentifierMapping(); - naturalIdMapping = superMappingType.getNaturalIdMapping(); - versionMapping = superMappingType.getVersionMapping(); - rowIdMapping = superMappingType.getRowIdMapping(); - softDeleteMapping = superMappingType.getSoftDeleteMapping(); + inheritSupertypeSpecialAttributeMappings(); } else { prepareMappingModel( creationProcess, bootEntityDescriptor ); } -// rootEntityDescriptor = superMappingType.getRootEntityDescriptor(); } else { prepareMappingModel( creationProcess, bootEntityDescriptor ); -// rootEntityDescriptor = this; } + } - final EntityMetamodel currentEntityMetamodel = getEntityMetamodel(); - - if ( currentEntityMetamodel.isVersioned() ) { - final BeforeExecutionGenerator generator = currentEntityMetamodel.getVersionGenerator(); - // need to do this here because EntityMetamodel doesn't have the EntityVersionMapping :-( - versionGenerator = generator == null ? new VersionGeneration( versionMapping ) : generator; - } + private void inheritSupertypeSpecialAttributeMappings() { + discriminatorMapping = superMappingType.getDiscriminatorMapping(); + identifierMapping = superMappingType.getIdentifierMapping(); + naturalIdMapping = superMappingType.getNaturalIdMapping(); + versionMapping = superMappingType.getVersionMapping(); + rowIdMapping = superMappingType.getRowIdMapping(); + softDeleteMapping = superMappingType.getSoftDeleteMapping(); + } + private void buildDeclaredAttributeMappings + (MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { int stateArrayPosition = getStateArrayInitialPosition( creationProcess ); - - final NonIdentifierAttribute[] properties = currentEntityMetamodel.getProperties(); - AttributeMappingsMap.Builder mappingsBuilder = AttributeMappingsMap.builder(); + final NonIdentifierAttribute[] properties = entityMetamodel.getProperties(); + final AttributeMappingsMap.Builder mappingsBuilder = AttributeMappingsMap.builder(); int fetchableIndex = getFetchableIndexOffset(); - for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) { - final NonIdentifierAttribute runtimeAttrDefinition = properties[i]; - final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() ); - + for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) { + final NonIdentifierAttribute runtimeAttributeDefinition = properties[i]; + final String attributeName = runtimeAttributeDefinition.getName(); + final Property bootProperty = bootEntityDescriptor.getProperty( attributeName ); if ( superMappingType == null || superMappingType.findAttributeMapping( bootProperty.getName() ) == null ) { mappingsBuilder.put( - runtimeAttrDefinition.getName(), + attributeName, generateNonIdAttributeMapping( - runtimeAttrDefinition, + runtimeAttributeDefinition, bootProperty, stateArrayPosition++, fetchableIndex++, @@ -4747,35 +4771,24 @@ public void prepareMappingModel(MappingModelCreationProcess creationProcess) { ); } declaredAttributeMappings = mappingsBuilder.build(); -// else { - // its defined on the supertype, skip it here -// } + // otherwise, it's defined on the supertype, skip it here } + } - getAttributeMappings(); - - postProcessAttributeMappings( creationProcess, bootEntityDescriptor ); - - final ReflectionOptimizer reflectionOptimizer = representationStrategy.getReflectionOptimizer(); - accessOptimizer = reflectionOptimizer != null ? reflectionOptimizer.getAccessOptimizer() : null; - - // register a callback for after all `#prepareMappingModel` calls have finished. here we want to delay the - // generation of `staticFetchableList` because we need to wait until after all subclasses have had their - // `#prepareMappingModel` called (and their declared attribute mappings resolved) - creationProcess.registerInitializationCallback( - "Entity(" + getEntityName() + ") `staticFetchableList` generator", - () -> { - final ImmutableAttributeMappingList.Builder builder = - new ImmutableAttributeMappingList.Builder( attributeMappings.size() ); - visitSubTypeAttributeMappings( builder::add ); - assert superMappingType != null || builder.assertFetchableIndexes(); - staticFetchableList = builder.build(); - return true; - } - ); + private static BeforeExecutionGenerator createVersionGenerator + (EntityMetamodel currentEntityMetamodel, EntityVersionMapping versionMapping) { + if ( currentEntityMetamodel.isVersioned() ) { + final BeforeExecutionGenerator generator = currentEntityMetamodel.getVersionGenerator(); + // need to do this here because EntityMetamodel doesn't have the EntityVersionMapping :-( + return generator == null ? new VersionGeneration( versionMapping ) : generator; + } + else { + return null; + } + } - boolean needsMultiTableInsert = hasMultipleTables(); - if ( needsMultiTableInsert ) { + private void prepareMultiTableMutationStrategy(MappingModelCreationProcess creationProcess) { + if ( hasMultipleTables() ) { creationProcess.registerInitializationCallback( "Entity(" + getEntityName() + ") `sqmMultiTableMutationStrategy` interpretation", () -> { @@ -4785,28 +4798,16 @@ public void prepareMappingModel(MappingModelCreationProcess creationProcess) { return false; } else { - sqmMultiTableMutationStrategy.prepare( - creationProcess, - creationContext.getJdbcServices().getBootstrapJdbcConnectionAccess() - ); + sqmMultiTableMutationStrategy.prepare( creationProcess ); return true; } } ); - - } - else { - sqmMultiTableMutationStrategy = null; - } - - if ( !needsMultiTableInsert && getGenerator() instanceof BulkInsertionCapableIdentifierGenerator ) { - if ( getGenerator() instanceof OptimizableGenerator ) { - final Optimizer optimizer = ( (OptimizableGenerator) getGenerator() ).getOptimizer(); - needsMultiTableInsert = optimizer != null && optimizer.getIncrementSize() > 1; - } } + } - if ( needsMultiTableInsert ) { + private void prepareMultiTableInsertStrategy(MappingModelCreationProcess creationProcess) { + if ( hasMultipleTables() || generatorNeedsMultiTableInsert() ) { creationProcess.registerInitializationCallback( "Entity(" + getEntityName() + ") `sqmMultiTableInsertStrategy` interpretation", () -> { @@ -4816,18 +4817,23 @@ public void prepareMappingModel(MappingModelCreationProcess creationProcess) { return false; } else { - sqmMultiTableInsertStrategy.prepare( - creationProcess, - creationContext.getJdbcServices().getBootstrapJdbcConnectionAccess() - ); + sqmMultiTableInsertStrategy.prepare( creationProcess ); return true; } } ); + } + } + private boolean generatorNeedsMultiTableInsert() { + final Generator generator = getGenerator(); + if ( generator instanceof BulkInsertionCapableIdentifierGenerator + && generator instanceof OptimizableGenerator optimizableGenerator ) { + final Optimizer optimizer = optimizableGenerator.getOptimizer(); + return optimizer != null && optimizer.getIncrementSize() > 1; } else { - sqmMultiTableInsertStrategy = null; + return false; } } @@ -4842,11 +4848,10 @@ private int getFetchableIndexOffset() { // Determining the number of attribute mappings unfortunately has to be done this way, // because calling `subMappingType.getNumberOfDeclaredAttributeMappings()` at this point // may produce wrong results because subMappingType might not have completed prepareMappingModel yet - final int propertySpan = subMappingType.getEntityPersister().getEntityMetamodel().getPropertySpan(); - final int superPropertySpan = subMappingType.getSuperMappingType() - .getEntityPersister() - .getEntityMetamodel() - .getPropertySpan(); + final int propertySpan = + subMappingType.getEntityPersister().getEntityMetamodel().getPropertySpan(); + final int superPropertySpan = + subMappingType.getSuperMappingType().getEntityPersister().getEntityMetamodel().getPropertySpan(); final int numberOfDeclaredAttributeMappings = propertySpan - superPropertySpan; offset += numberOfDeclaredAttributeMappings; } @@ -4858,26 +4863,12 @@ private int getFetchableIndexOffset() { private void prepareMappingModel(MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { final EntityInstantiator instantiator = getRepresentationStrategy().getInstantiator(); final Supplier instantiate = instantiator.canBeInstantiated() ? instantiator::instantiate : null; - - identifierMapping = creationProcess.processSubPart( - EntityIdentifierMapping.ID_ROLE_NAME, - (role, process) - -> generateIdentifierMapping( instantiate, bootEntityDescriptor, process ) - ); - + identifierMapping = creationProcess.processSubPart( EntityIdentifierMapping.ID_ROLE_NAME, + (role, process) -> generateIdentifierMapping( instantiate, bootEntityDescriptor, process ) ); versionMapping = generateVersionMapping( instantiate, bootEntityDescriptor, creationProcess ); - - if ( rowIdName == null ) { - rowIdMapping = null; - } - else { - rowIdMapping = creationProcess.processSubPart( - rowIdName, - (role, process) - -> new EntityRowIdMappingImpl( rowIdName, getTableName(), this ) - ); - } - + rowIdMapping = rowIdName == null ? null + : creationProcess.processSubPart( rowIdName, + (role, process) -> new EntityRowIdMappingImpl( rowIdName, getTableName(), this ) ); discriminatorMapping = generateDiscriminatorMapping( bootEntityDescriptor ); softDeleteMapping = resolveSoftDeleteMapping( this, @@ -4885,7 +4876,6 @@ private void prepareMappingModel(MappingModelCreationProcess creationProcess, Pe getIdentifierTableName(), creationProcess ); - if ( softDeleteMapping != null ) { if ( bootEntityDescriptor.getRootClass().getCustomSQLDelete() != null ) { throw new UnsupportedMappingException( "Entity may not define both @SoftDelete and @SQLDelete" ); @@ -4893,7 +4883,8 @@ private void prepareMappingModel(MappingModelCreationProcess creationProcess, Pe } } - private void postProcessAttributeMappings(MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { + private void initializeNaturalIdMapping + (MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { if ( superMappingType != null ) { naturalIdMapping = superMappingType.getNaturalIdMapping(); } @@ -4905,7 +4896,8 @@ else if ( bootEntityDescriptor.hasNaturalId() ) { } } - protected NaturalIdMapping generateNaturalIdMapping(MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { + protected NaturalIdMapping generateNaturalIdMapping + (MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { //noinspection AssertWithSideEffects assert bootEntityDescriptor.hasNaturalId(); @@ -4922,7 +4914,7 @@ protected NaturalIdMapping generateNaturalIdMapping(MappingModelCreationProcess // collect the names of the attributes making up the natural-id. final Set attributeNames = setOfSize( naturalIdAttributeIndexes.length ); for ( int naturalIdAttributeIndex : naturalIdAttributeIndexes ) { - attributeNames.add( this.getPropertyNames()[ naturalIdAttributeIndex ] ); + attributeNames.add( getPropertyNames()[ naturalIdAttributeIndex ] ); } // then iterate over the attribute mappings finding the ones having names @@ -5644,7 +5636,7 @@ public AttributeMappingsList getAttributeMappings() { for ( AttributeMapping am : declaredAttributeMappings.valueIterator() ) { builder.add( am ); } - this.attributeMappings = builder.build(); + attributeMappings = builder.build(); final Getter[] getters = new Getter[attributeMappings.size()]; final Setter[] setters = new Setter[attributeMappings.size()]; for ( int i = 0; i < attributeMappings.size(); i++ ) { @@ -5652,8 +5644,8 @@ public AttributeMappingsList getAttributeMappings() { getters[i] = propertyAccess.getGetter(); setters[i] = propertyAccess.getSetter(); } - this.getterCache = getters; - this.setterCache = setters; + getterCache = getters; + setterCache = setters; // subclasses? it depends on the usage } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/spi/SqmMultiTableInsertStrategy.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/spi/SqmMultiTableInsertStrategy.java index c3b662819cf4..d29a662885e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/spi/SqmMultiTableInsertStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/spi/SqmMultiTableInsertStrategy.java @@ -35,6 +35,15 @@ default void prepare( // by default, nothing to do... } + /** + * Prepare the strategy for use. Called one time as the SessionFactory + * is being built. + */ + default void prepare(MappingModelCreationProcess mappingModelCreationProcess) { + prepare( mappingModelCreationProcess, + mappingModelCreationProcess.getCreationContext().getJdbcServices().getBootstrapJdbcConnectionAccess() ); + } + /** * Release the strategy. Called one time as the SessionFactory is * being shut down. diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/spi/SqmMultiTableMutationStrategy.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/spi/SqmMultiTableMutationStrategy.java index 0ec1f5978c9b..139656eef5f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/spi/SqmMultiTableMutationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/spi/SqmMultiTableMutationStrategy.java @@ -39,6 +39,15 @@ default void prepare( // by default, nothing to do... } + /** + * Prepare the strategy for use. Called one time as the SessionFactory + * is being built. + */ + default void prepare(MappingModelCreationProcess mappingModelCreationProcess) { + prepare( mappingModelCreationProcess, + mappingModelCreationProcess.getCreationContext().getJdbcServices().getBootstrapJdbcConnectionAccess() ); + } + /** * Release the strategy. Called one time as the SessionFactory is * being shut down.