remove some obsolete and unused code and simplify GeneratedValuesProcessor

This commit is contained in:
Gavin 2022-12-22 00:02:51 +01:00 committed by Gavin King
parent 39ffcc91f4
commit fb840ef84f
11 changed files with 23 additions and 489 deletions

View File

@ -1,238 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.metamodel.internal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.hibernate.EntityNameResolver;
import org.hibernate.HibernateException;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
import org.hibernate.internal.EntityManagerMessageLogger;
import org.hibernate.internal.HEMLogging;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.persister.spi.PersisterFactory;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Steve Ebersole
*/
public class InflightRuntimeMetamodel {
private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( InflightRuntimeMetamodel.class );
private final TypeConfiguration typeConfiguration;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Hibernate metamodel
private final Map<String, EntityPersister> entityPersisterMap = new ConcurrentHashMap<>();
private final Map<Class, String> entityProxyInterfaceMap = new ConcurrentHashMap<>();
private final Map<String, CollectionPersister> collectionPersisterMap = new ConcurrentHashMap<>();
private final Map<String, Set<String>> collectionRolesByEntityParticipant = new ConcurrentHashMap<>();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Misc
private final Map<String, String> nameToImportNameMap = new HashMap<>();
private final Set<EntityNameResolver> entityNameResolvers = new CopyOnWriteArraySet<>();
private final Map<String, String> imports = new ConcurrentHashMap<>( );
public InflightRuntimeMetamodel(TypeConfiguration typeConfiguration) {
this.typeConfiguration = typeConfiguration;
}
public void processBootMetaModel(
MetadataImplementor bootMetamodel,
CacheImplementor cacheImplementor,
PersisterFactory persisterFactory,
RuntimeModelCreationContext modelCreationContext) {
this.imports.putAll( bootMetamodel.getImports() );
processBootEntities(
bootMetamodel.getEntityBindings(),
cacheImplementor,
persisterFactory,
modelCreationContext
);
processBootCollections(
bootMetamodel.getCollectionBindings(),
cacheImplementor,
persisterFactory,
modelCreationContext
);
}
public TypeConfiguration getTypeConfiguration() {
return typeConfiguration;
}
public Map<String, EntityPersister> getEntityPersisterMap() {
return entityPersisterMap;
}
public Map<Class, String> getEntityProxyInterfaceMap() {
return entityProxyInterfaceMap;
}
public Map<String, CollectionPersister> getCollectionPersisterMap() {
return collectionPersisterMap;
}
public Map<String, Set<String>> getCollectionRolesByEntityParticipant() {
return collectionRolesByEntityParticipant;
}
public Map<String, String> getNameToImportNameMap() {
return nameToImportNameMap;
}
public Set<EntityNameResolver> getEntityNameResolvers() {
return entityNameResolvers;
}
/**
* Get an entity mapping descriptor based on its Hibernate entity-name
*
* @throws IllegalArgumentException if the name does not refer to an entity
*/
public EntityPersister getEntityDescriptor(String entityName) {
final EntityPersister entityPersister = entityPersisterMap.get( entityName );
if ( entityPersister == null ) {
throw new IllegalArgumentException( "Unable to locate persister: " + entityName );
}
return entityPersister;
}
/**
* Find an entity mapping descriptor based on its Hibernate entity-name.
*
* @apiNote Returns {@code null} rather than throwing exception
*/
public EntityPersister findEntityDescriptor(String entityName) {
return entityPersisterMap.get( entityName );
}
private void processBootEntities(
java.util.Collection<PersistentClass> entityBindings,
CacheImplementor cacheImplementor,
PersisterFactory persisterFactory,
RuntimeModelCreationContext modelCreationContext) {
for ( final PersistentClass model : entityBindings ) {
final NavigableRole rootEntityRole = new NavigableRole( model.getRootClass().getEntityName() );
final EntityDataAccess accessStrategy = cacheImplementor.getEntityRegionAccess( rootEntityRole );
final NaturalIdDataAccess naturalIdAccessStrategy = cacheImplementor
.getNaturalIdCacheRegionAccessStrategy( rootEntityRole );
final EntityPersister cp = persisterFactory.createEntityPersister(
model,
accessStrategy,
naturalIdAccessStrategy,
modelCreationContext
);
entityPersisterMap.put( model.getEntityName(), cp );
if ( cp.getConcreteProxyClass() != null
&& cp.getConcreteProxyClass().isInterface()
&& !Map.class.isAssignableFrom( cp.getConcreteProxyClass() )
&& cp.getMappedClass() != cp.getConcreteProxyClass() ) {
// IMPL NOTE : we exclude Map based proxy interfaces here because that should
// indicate MAP entity mode.0
if ( cp.getMappedClass().equals( cp.getConcreteProxyClass() ) ) {
// this part handles an odd case in the Hibernate test suite where we map an interface
// as the class and the proxy. I cannot think of a real life use case for that
// specific test, but..
if ( log.isDebugEnabled() ) {
log.debugf(
"Entity [%s] mapped same interface [%s] as class and proxy",
cp.getEntityName(),
cp.getMappedClass()
);
}
}
else {
final String old = entityProxyInterfaceMap.put( cp.getConcreteProxyClass(), cp.getEntityName() );
if ( old != null ) {
throw new HibernateException(
String.format(
Locale.ENGLISH,
"Multiple entities [%s, %s] named the same interface [%s] as their proxy which is not supported",
old,
cp.getEntityName(),
cp.getConcreteProxyClass().getName()
)
);
}
}
}
}
}
private void processBootCollections(
java.util.Collection<Collection> collectionBindings,
CacheImplementor cacheImplementor,
PersisterFactory persisterFactory,
PersisterCreationContext persisterCreationContext) {
for ( final Collection model : collectionBindings ) {
final NavigableRole navigableRole = new NavigableRole( model.getRole() );
final CollectionDataAccess accessStrategy = cacheImplementor.getCollectionRegionAccess(
navigableRole );
final CollectionPersister persister = persisterFactory.createCollectionPersister(
model,
accessStrategy,
persisterCreationContext
);
collectionPersisterMap.put( model.getRole(), persister );
Type indexType = persister.getIndexType();
if ( indexType != null && indexType.isEntityType() && !indexType.isAnyType() ) {
String entityName = ( (EntityType) indexType ).getAssociatedEntityName();
Set<String> roles = collectionRolesByEntityParticipant.get( entityName );
if ( roles == null ) {
roles = new HashSet<>();
collectionRolesByEntityParticipant.put( entityName, roles );
}
roles.add( persister.getRole() );
}
Type elementType = persister.getElementType();
if ( elementType.isEntityType() && !elementType.isAnyType() ) {
String entityName = ( (EntityType) elementType ).getAssociatedEntityName();
Set<String> roles = collectionRolesByEntityParticipant.get( entityName );
if ( roles == null ) {
roles = new HashSet<>();
collectionRolesByEntityParticipant.put( entityName, roles );
}
roles.add( persister.getRole() );
}
}
}
public Map<String, String> getImports() {
return imports;
}
}

View File

@ -1,37 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.metamodel.mapping;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Generalized contract covering an attribute's generation handling
*
* @author Steve Ebersole
*/
@Incubating
public interface GeneratedValueResolver {
// static GeneratedValueResolver from(
// Generator generator,
// GenerationTiming requestedTiming,
// int dbSelectionPosition) {
// assert requestedTiming.isNotNever();
//
// if ( generator == null || !generator.getGenerationTiming().includes( requestedTiming ) ) {
// return NoGeneratedValueResolver.INSTANCE;
// }
// else {
// return generator.generatedByDatabase()
// ? new InDatabaseGeneratedValueResolver( requestedTiming, dbSelectionPosition ) // in-db generation (column-default, function, etc)
// : new InMemoryGeneratedValueResolver( (BeforeExecutionGenerator) generator, requestedTiming );
// }
// }
// GenerationTiming getGenerationTiming();
Object resolveGeneratedValue(Object[] row, Object entity, SharedSessionContractImplementor session, Object currentValue);
}

View File

@ -1,38 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.metamodel.mapping;
import org.hibernate.Internal;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
/**
* GeneratedValueResolver impl for in-db generation. It extracts the generated value
* from a array of the ResultSet values
*
* @author Steve Ebersole
*/
@Internal
public class InDatabaseGeneratedValueResolver implements GeneratedValueResolver {
private final EventType eventType;
private final int resultPosition;
public InDatabaseGeneratedValueResolver(EventType eventType, int resultPosition) {
this.eventType = eventType;
this.resultPosition = resultPosition;
}
// @Override
// public GenerationTiming getGenerationTiming() {
// return timing;
// }
@Override
public Object resolveGeneratedValue(Object[] row, Object entity, SharedSessionContractImplementor session, Object currentValue) {
return row[resultPosition];
}
}

View File

@ -1,38 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.metamodel.mapping;
import org.hibernate.Internal;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.EventType;
import org.hibernate.generator.BeforeExecutionGenerator;
/**
* GeneratedValueResolver impl for in-memory generation
*
* @author Steve Ebersole
*/
@Internal
public class InMemoryGeneratedValueResolver implements GeneratedValueResolver {
private final EventType eventType;
private final BeforeExecutionGenerator generator;
public InMemoryGeneratedValueResolver(BeforeExecutionGenerator generator, EventType eventType) {
this.generator = generator;
this.eventType = eventType;
}
// @Override
// public GenerationTiming getGenerationTiming() {
// return generationTiming;
// }
@Override
public Object resolveGeneratedValue(Object[] row, Object entity, SharedSessionContractImplementor session, Object currentValue) {
return generator.generate( session, entity, currentValue, eventType );
}
}

View File

@ -1,13 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.metamodel.mapping;
/**
* @author Steve Ebersole
*/
public interface MappingModelVisitor {
}

View File

@ -1,13 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.metamodel.mapping;
/**
* @author Steve Ebersole
*/
public class MappingModelWalker {
}

View File

@ -21,22 +21,19 @@ import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
import org.hibernate.loader.ast.internal.NoCallbackExecutionContext;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.GeneratedValueResolver;
import org.hibernate.metamodel.mapping.InDatabaseGeneratedValueResolver;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import static org.hibernate.sql.results.spi.ListResultsConsumer.UniqueSemantic.FILTER;
/**
* Responsible for retrieving {@linkplain OnExecutionGenerator
* database-generated} attribute values after an {@code insert} statement is executed.
* Responsible for retrieving {@linkplain OnExecutionGenerator database-generated}
* attribute values after an {@code insert} or {@code update} statement is executed.
* <p>
* Note that this class has responsibility for regular attributes of the entity. The
* primary key / id attribute is handled separately, being the responsibility of an
@ -49,7 +46,7 @@ import static org.hibernate.sql.results.spi.ListResultsConsumer.UniqueSemantic.F
@Incubating
public class GeneratedValuesProcessor {
private final SelectStatement selectStatement;
private final List<GeneratedValueDescriptor> valueDescriptors = new ArrayList<>();
private final List<AttributeMapping> generatedValuesToSelect;
private final List<JdbcParameter> jdbcParameters = new ArrayList<>();
private final EntityMappingType entityDescriptor;
@ -62,7 +59,7 @@ public class GeneratedValuesProcessor {
this.entityDescriptor = entityDescriptor;
this.sessionFactory = sessionFactory;
final List<AttributeMapping> generatedValuesToSelect = getGeneratedAttributes( entityDescriptor, timing );
generatedValuesToSelect = getGeneratedAttributes( entityDescriptor, timing );
if ( generatedValuesToSelect.isEmpty() ) {
selectStatement = null;
}
@ -82,11 +79,11 @@ public class GeneratedValuesProcessor {
}
/**
* Find attributes generated by a {@link OnExecutionGenerator},
* populate the list of {@link GeneratedValueDescriptor}s by side effect, and
* return a list of {@link AttributeMapping}s.
* Find attributes generated by an {@link OnExecutionGenerator}.
*
* @return a list of {@link AttributeMapping}s.
*/
private List<AttributeMapping> getGeneratedAttributes(EntityMappingType entityDescriptor, EventType timing) {
private static List<AttributeMapping> getGeneratedAttributes(EntityMappingType entityDescriptor, EventType timing) {
// todo (6.0): For now, we rely on the entity metamodel as composite attributes report
// GenerationTiming.NEVER even if they have attributes that would need generation
final Generator[] generators = entityDescriptor.getEntityPersister().getEntityMetamodel().getGenerators();
@ -95,12 +92,7 @@ public class GeneratedValuesProcessor {
final Generator generator = generators[ mapping.getStateArrayPosition() ];
if ( generator != null
&& generator.generatedOnExecute()
&& generator.generatesSometimes() ) {
// this attribute is generated for the timing we are processing...
valueDescriptors.add( new GeneratedValueDescriptor(
new InDatabaseGeneratedValueResolver( timing, generatedValuesToSelect.size() ),
mapping
) );
&& generator.getEventTypes().contains(timing) ) {
generatedValuesToSelect.add( mapping );
}
} );
@ -114,7 +106,7 @@ public class GeneratedValuesProcessor {
if ( selectStatement != null ) {
final List<Object[]> results = executeSelect( id, session );
assert results.size() == 1;
setEntityAttributes( entity, state, session, results.get(0) );
setEntityAttributes( entity, state, results.get(0) );
}
}
@ -125,7 +117,7 @@ public class GeneratedValuesProcessor {
.buildSelectTranslator( sessionFactory, selectStatement )
.translate( jdbcParamBindings, QueryOptions.NONE );
return session.getFactory().getJdbcServices().getJdbcSelectExecutor()
.list( jdbcSelect, jdbcParamBindings, createExecutionContext( session ), (row) -> row, FILTER );
.list( jdbcSelect, jdbcParamBindings, new NoCallbackExecutionContext(session), (row) -> row, FILTER );
}
private JdbcParameterBindings getJdbcParameterBindings(Object id, SharedSessionContractImplementor session) {
@ -141,35 +133,12 @@ public class GeneratedValuesProcessor {
return jdbcParamBindings;
}
private void setEntityAttributes(
Object entity,
Object[] state,
SharedSessionContractImplementor session,
Object[] selectionResults) {
for ( int i = 0; i < valueDescriptors.size(); i++ ) {
final GeneratedValueDescriptor descriptor = valueDescriptors.get( i );
final Object generatedValue =
descriptor.resolver.resolveGeneratedValue( selectionResults, entity, session, state[i] );
state[ descriptor.attribute.getStateArrayPosition() ] = generatedValue;
descriptor.attribute.getAttributeMetadata()
.getPropertyAccess()
.getSetter()
.set( entity, generatedValue );
private void setEntityAttributes(Object entity, Object[] state, Object[] selectionResults) {
for ( int i = 0; i < generatedValuesToSelect.size(); i++ ) {
final AttributeMapping attribute = generatedValuesToSelect.get( i );
final Object generatedValue = selectionResults[i];
state[ attribute.getStateArrayPosition() ] = generatedValue;
attribute.getAttributeMetadata().getPropertyAccess().getSetter().set( entity, generatedValue );
}
}
private static ExecutionContext createExecutionContext(SharedSessionContractImplementor session) {
return new NoCallbackExecutionContext( session );
}
private static class GeneratedValueDescriptor {
public final GeneratedValueResolver resolver;
public final AttributeMapping attribute;
public GeneratedValueDescriptor(GeneratedValueResolver resolver, AttributeMapping attribute) {
this.resolver = resolver;
this.attribute = attribute;
}
}
}

View File

@ -1,31 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.metamodel.mapping.internal;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.UnsupportedMappingException;
import org.hibernate.metamodel.mapping.GeneratedValueResolver;
/**
* @author Steve Ebersole
*/
public class NoGeneratedValueResolver implements GeneratedValueResolver {
/**
* Singleton access
*/
public static final NoGeneratedValueResolver INSTANCE = new NoGeneratedValueResolver();
// @Override
// public GenerationTiming getGenerationTiming() {
// return GenerationTiming.NEVER;
// }
@Override
public Object resolveGeneratedValue(Object[] row, Object entity, SharedSessionContractImplementor session, Object currentValue) {
throw new UnsupportedMappingException( "NoGeneratedValueResolver does not support generated values" );
}
}

View File

@ -1943,7 +1943,7 @@ public abstract class AbstractEntityPersister
throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
}
if ( entityMetamodel.isVersionGeneratedByDatabase() ) {
if ( entityMetamodel.isVersionGeneratedOnExecute() ) {
// the difficulty here is exactly what we update in order to
// force the version to be incremented in the db...
throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
@ -2737,7 +2737,7 @@ public abstract class AbstractEntityPersister
private static final boolean[] SINGLE_TRUE = new boolean[] { true };
public final boolean checkVersion(final boolean[] includeProperty) {
return includeProperty[getVersionProperty()] || entityMetamodel.isVersionGeneratedByDatabase();
return includeProperty[getVersionProperty()] || entityMetamodel.isVersionGeneratedOnExecute();
}
@Override
@ -3945,8 +3945,8 @@ public abstract class AbstractEntityPersister
@Override
public boolean isVersionPropertyGenerated() {
return isVersioned()
&& ( getEntityMetamodel().isVersionGeneratedByDatabase()
|| getEntityMetamodel().isVersionGeneratedInMemory() );
&& ( getEntityMetamodel().isVersionGeneratedOnExecute()
|| getEntityMetamodel().isVersionGeneratedBeforeExecute() );
}
@Override

View File

@ -1,27 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.persister.spi;
/**
* Where to begin... :)
*
* This gets to the internal concept of 2-phase loading of entity data and how specifically it is done. Essentially
* for composite values, the process of hydration results in a tuple array comprising the composition "atomic" values.
* For example, a Name component's hydrated state might look like {@code ["Steve", "L", "Ebersole"]}.
*
* There are times when we need to be able to extract individual pieces out of the hydrated tuple array. For example,
* for an entity with a composite identifier part of which is an association (a key-many-to-one) we often need to
* attempt 2-phase processing on the association portion of the identifier's hydrated tuple array.
*
* This contract allows us access to portions of the hydrated tuple state.
*
* @author Steve Ebersole
*/
public interface HydratedCompoundValueHandler {
Object extract(Object hydratedState);
void inject(Object hydratedState, Object value);
}

View File

@ -689,12 +689,12 @@ public class EntityMetamodel implements Serializable {
return false;
}
public boolean isVersionGeneratedByDatabase() {
public boolean isVersionGeneratedOnExecute() {
final Generator strategy = generators[ versionPropertyIndex ];
return strategy != null && strategy.generatesSometimes() && strategy.generatedOnExecute();
}
public boolean isVersionGeneratedInMemory() {
public boolean isVersionGeneratedBeforeExecute() {
final Generator strategy = generators[ versionPropertyIndex ];
return strategy != null && strategy.generatesSometimes() && !strategy.generatedOnExecute();
}