code cleanups to MappingMetamodelImpl

This commit is contained in:
Gavin King 2024-12-11 23:57:10 +01:00
parent 1c93f10adf
commit ea202ebbfb
1 changed files with 45 additions and 91 deletions

View File

@ -5,7 +5,6 @@
package org.hibernate.metamodel.model.domain.internal; package org.hibernate.metamodel.model.domain.internal;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -20,13 +19,9 @@ import java.util.stream.Stream;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.EntityNameResolver; import org.hibernate.EntityNameResolver;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.UnknownEntityTypeException; import org.hibernate.UnknownEntityTypeException;
import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cache.spi.CacheImplementor; 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.graph.RootGraph; import org.hibernate.graph.RootGraph;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
@ -40,7 +35,6 @@ import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.MappingModelExpressible; import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess; import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.BasicDomainType;
@ -81,7 +75,6 @@ import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.ManagedType; import jakarta.persistence.metamodel.ManagedType;
import jakarta.persistence.metamodel.Metamodel; import jakarta.persistence.metamodel.Metamodel;
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
import static org.hibernate.metamodel.internal.JpaMetamodelPopulationSetting.determineJpaMetaModelPopulationSetting; import static org.hibernate.metamodel.internal.JpaMetamodelPopulationSetting.determineJpaMetaModelPopulationSetting;
import static org.hibernate.metamodel.internal.JpaStaticMetamodelPopulationSetting.determineJpaStaticMetaModelPopulationSetting; import static org.hibernate.metamodel.internal.JpaStaticMetamodelPopulationSetting.determineJpaStaticMetaModelPopulationSetting;
@ -97,11 +90,8 @@ import static org.hibernate.metamodel.internal.JpaStaticMetamodelPopulationSetti
*/ */
public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
implements MappingMetamodelImplementor,JpaMetamodel, Metamodel, Serializable { implements MappingMetamodelImplementor,JpaMetamodel, Metamodel, Serializable {
// todo : Integrate EntityManagerLogger into CoreMessageLogger
private static final CoreMessageLogger log = CoreLogging.messageLogger( MappingMetamodelImpl.class );
//NOTE: we suppress deprecation warnings because at the moment we private static final CoreMessageLogger log = CoreLogging.messageLogger( MappingMetamodelImpl.class );
//implement a deprecated API so have to override deprecated things
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JpaMetamodel // JpaMetamodel
@ -110,7 +100,6 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
private final Map<Class<?>, String> entityProxyInterfaceMap = new ConcurrentHashMap<>(); private final Map<Class<?>, String> entityProxyInterfaceMap = new ConcurrentHashMap<>();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// RuntimeModel // RuntimeModel
@ -119,6 +108,7 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
private final Map<String, Set<String>> collectionRolesByEntityParticipant = new ConcurrentHashMap<>(); private final Map<String, Set<String>> collectionRolesByEntityParticipant = new ConcurrentHashMap<>();
private final Map<NavigableRole, EmbeddableValuedModelPart> embeddableValuedModelPart = new ConcurrentHashMap<>(); private final Map<NavigableRole, EmbeddableValuedModelPart> embeddableValuedModelPart = new ConcurrentHashMap<>();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DomainMetamodel // DomainMetamodel
@ -128,19 +118,19 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: Relational/mapping information is not part of the JPA metamodel // NOTE: Relational/mapping information is not part of the JPA metamodel
// (type system). However, this relational/mapping info *is* part of the // (type system). However, this relational/mapping info *is* part of the
// Hibernate metamodel. This is a mismatch. Normally this is not a // Hibernate metamodel. This is a mismatch. Normally this is not a problem
// problem - ignoring Hibernate's representation mode (entity mode), // - ignoring Hibernate's representation mode (entity mode), the Class
// an entity (or mapped superclass) *Class* always refers to the same // object for an entity (or mapped superclass) always refers to the same
// EntityType (JPA) and EntityPersister (Hibernate).. The problem is // JPA EntityType and Hibernate EntityPersister. The problem arises with
// in regards to embeddables. For an embeddable, as with the rest of its // embeddables. For an embeddable, as with the rest of its metamodel,
// metamodel, Hibernate combines the embeddable's relational/mapping // Hibernate combines the embeddable's relational/mapping while JPA does
// while JPA does not. This is consistent with each's model paradigm. // not. This is perfectly consistent with each paradigm. But it results
// However, it causes a mismatch in that while JPA expects a single // in a mismatch since JPA expects a single "type descriptor" for a
// "type descriptor" for a given embeddable class, Hibernate incorporates // given embeddable class while Hibernate incorporates the
// the relational/mapping info so we have a "type descriptor" for each // relational/mapping info so we have a "type descriptor" for each usage
// usage of that embeddable. Think embeddable versus embedded. // of that embeddable type. (Think embeddable versus embedded.)
// //
// To account for this, we track both paradigms here... // To account for this, we track both paradigms here.
// There can be multiple instances of an Embeddable type, each one being relative to its parent entity. // There can be multiple instances of an Embeddable type, each one being relative to its parent entity.
@ -225,54 +215,50 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
RuntimeModelCreationContext modelCreationContext) { RuntimeModelCreationContext modelCreationContext) {
for ( final PersistentClass model : entityBindings ) { for ( final PersistentClass model : entityBindings ) {
final NavigableRole rootEntityRole = new NavigableRole( model.getRootClass().getEntityName() ); final NavigableRole rootEntityRole = new NavigableRole( model.getRootClass().getEntityName() );
final EntityDataAccess accessStrategy = cacheImplementor.getEntityRegionAccess( rootEntityRole ); final EntityPersister entityPersister =
final NaturalIdDataAccess naturalIdAccessStrategy = cacheImplementor persisterFactory.createEntityPersister(
.getNaturalIdCacheRegionAccessStrategy( rootEntityRole );
final EntityPersister cp = persisterFactory.createEntityPersister(
model, model,
accessStrategy, cacheImplementor.getEntityRegionAccess( rootEntityRole ),
naturalIdAccessStrategy, cacheImplementor.getNaturalIdCacheRegionAccessStrategy( rootEntityRole ),
modelCreationContext modelCreationContext
); );
entityPersisterMap.put( model.getEntityName(), cp ); entityPersisterMap.put( model.getEntityName(), entityPersister );
// Also register the persister under the class name if available, // Also register the persister under the class name if available,
// otherwise the getEntityDescriptor(Class) won't work for entities with custom entity names // otherwise the getEntityDescriptor(Class) won't work for entities with custom entity names
if ( model.getClassName() != null && !model.getClassName().equals( model.getEntityName() ) ) { if ( model.getClassName() != null && !model.getClassName().equals( model.getEntityName() ) ) {
// But only if the class name is not registered already, // But only if the class name is not registered already,
// as we can have the same class mapped to multiple entity names // as we can have the same class mapped to multiple entity names
entityPersisterMap.putIfAbsent( model.getClassName(), cp ); entityPersisterMap.putIfAbsent( model.getClassName(), entityPersister );
} }
if ( cp.getConcreteProxyClass() != null if ( entityPersister.getConcreteProxyClass() != null
&& cp.getConcreteProxyClass().isInterface() && entityPersister.getConcreteProxyClass().isInterface()
&& !Map.class.isAssignableFrom( cp.getConcreteProxyClass() ) && !Map.class.isAssignableFrom( entityPersister.getConcreteProxyClass() )
&& cp.getMappedClass() != cp.getConcreteProxyClass() ) { && entityPersister.getMappedClass() != entityPersister.getConcreteProxyClass() ) {
// IMPL NOTE : we exclude Map based proxy interfaces here because that should // IMPL NOTE : we exclude Map based proxy interfaces here because that should
// indicate MAP entity mode.0 // indicate MAP entity mode.0
if ( cp.getMappedClass().equals( cp.getConcreteProxyClass() ) ) { if ( entityPersister.getMappedClass().equals( entityPersister.getConcreteProxyClass() ) ) {
// this part handles an odd case in the Hibernate test suite where we map an interface // 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 // as the class and the proxy. I cannot think of a real-life use case for this.
// specific test, but..
if ( log.isDebugEnabled() ) { if ( log.isDebugEnabled() ) {
log.debugf( log.debugf(
"Entity [%s] mapped same interface [%s] as class and proxy", "Entity [%s] mapped same interface [%s] as class and proxy",
cp.getEntityName(), entityPersister.getEntityName(),
cp.getMappedClass() entityPersister.getMappedClass()
); );
} }
} }
else { else {
final String old = entityProxyInterfaceMap.put( cp.getConcreteProxyClass(), cp.getEntityName() ); final String old = entityProxyInterfaceMap.put( entityPersister.getConcreteProxyClass(), entityPersister.getEntityName() );
if ( old != null ) { if ( old != null ) {
throw new HibernateException( throw new HibernateException(
String.format( String.format(
Locale.ENGLISH, Locale.ENGLISH,
"Multiple entities [%s, %s] named the same interface [%s] as their proxy which is not supported", "Multiple entities [%s, %s] named the same interface [%s] as their proxy which is not supported",
old, old,
cp.getEntityName(), entityPersister.getEntityName(),
cp.getConcreteProxyClass().getName() entityPersister.getConcreteProxyClass().getName()
) )
); );
} }
@ -288,13 +274,10 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
RuntimeModelCreationContext modelCreationContext) { RuntimeModelCreationContext modelCreationContext) {
for ( final Collection model : collectionBindings ) { for ( final Collection model : collectionBindings ) {
final NavigableRole navigableRole = new NavigableRole( model.getRole() ); final NavigableRole navigableRole = new NavigableRole( model.getRole() );
final CollectionPersister persister =
final CollectionDataAccess accessStrategy = cacheImplementor.getCollectionRegionAccess( persisterFactory.createCollectionPersister(
navigableRole );
final CollectionPersister persister = persisterFactory.createCollectionPersister(
model, model,
accessStrategy, cacheImplementor.getCollectionRegionAccess( navigableRole ),
modelCreationContext modelCreationContext
); );
collectionPersisterMap.put( model.getRole(), persister ); collectionPersisterMap.put( model.getRole(), persister );
@ -400,7 +383,7 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
public EntityPersister getEntityDescriptor(Class<?> entityJavaType) { public EntityPersister getEntityDescriptor(Class<?> entityJavaType) {
EntityPersister entityPersister = entityPersisterMap.get( entityJavaType.getName() ); EntityPersister entityPersister = entityPersisterMap.get( entityJavaType.getName() );
if ( entityPersister == null ) { if ( entityPersister == null ) {
String mappedEntityName = entityProxyInterfaceMap.get( entityJavaType ); final String mappedEntityName = entityProxyInterfaceMap.get( entityJavaType );
if ( mappedEntityName != null ) { if ( mappedEntityName != null ) {
entityPersister = entityPersisterMap.get( mappedEntityName ); entityPersister = entityPersisterMap.get( mappedEntityName );
} }
@ -417,7 +400,7 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
public EntityPersister locateEntityDescriptor(Class<?> byClass) { public EntityPersister locateEntityDescriptor(Class<?> byClass) {
EntityPersister entityPersister = entityPersisterMap.get( byClass.getName() ); EntityPersister entityPersister = entityPersisterMap.get( byClass.getName() );
if ( entityPersister == null ) { if ( entityPersister == null ) {
String mappedEntityName = entityProxyInterfaceMap.get( byClass ); final String mappedEntityName = entityProxyInterfaceMap.get( byClass );
if ( mappedEntityName != null ) { if ( mappedEntityName != null ) {
entityPersister = entityPersisterMap.get( mappedEntityName ); entityPersister = entityPersisterMap.get( mappedEntityName );
} }
@ -655,35 +638,6 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
return null; return null;
} }
private String[] doGetImplementors(Class<?> clazz) throws MappingException {
final ArrayList<String> results = new ArrayList<>();
forEachEntityDescriptor( descriptor -> {
final String checkQueryableEntityName = ((EntityMappingType) descriptor).getEntityName();
final boolean isMappedClass = clazz.getName().equals( checkQueryableEntityName );
if ( isMappedClass ) {
results.add( checkQueryableEntityName );
}
else {
final Class<?> mappedClass = descriptor.getMappedClass();
if ( mappedClass != null && clazz.isAssignableFrom( mappedClass ) ) {
final boolean assignableSuperclass;
if ( descriptor.isInherited() ) {
final String superTypeName = descriptor.getSuperMappingType().getEntityName();
final Class<?> mappedSuperclass = getEntityDescriptor( superTypeName ).getMappedClass();
assignableSuperclass = clazz.isAssignableFrom( mappedSuperclass );
}
else {
assignableSuperclass = false;
}
if ( !assignableSuperclass ) {
results.add( checkQueryableEntityName );
}
}
}
} );
return results.toArray( EMPTY_STRING_ARRAY );
}
@Override @Override
public MappingModelExpressible<?> resolveMappingExpressible( public MappingModelExpressible<?> resolveMappingExpressible(
SqmExpressible<?> sqmExpressible, SqmExpressible<?> sqmExpressible,