allow @Formulas to refer to columns of @SecondaryTables

(this is something that was previously only possible using hbm.xml)

also attempt a partial fixup of the initialization process where SessionFactoryImpl
constructor leaked out an uninitialized reference to itself (it still leaks, but
not as badly)
This commit is contained in:
Gavin 2023-01-02 10:55:51 +01:00 committed by Gavin King
parent 1eba25a466
commit 7aa92a7c05
25 changed files with 300 additions and 243 deletions

View File

@ -13,6 +13,7 @@ import jakarta.persistence.PersistenceException;
import jakarta.persistence.SecondaryTable;
import org.hibernate.annotations.Check;
import org.hibernate.annotations.Formula;
import org.hibernate.annotations.NaturalId;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.PostgreSQLDialect;
@ -53,6 +54,11 @@ public class CheckTest extends BaseEntityManagerFunctionalTestCase {
entityManager.persist(book);
});
doInJPA(this::entityManagerFactory, entityManager -> {
Book book = entityManager.find(Book.class, 0L);
assertEquals( 1, book.edition );
assertEquals( 2, book.nextEdition );
});
try {
doInJPA(this::entityManagerFactory, entityManager -> {
//tag::schema-generation-database-checks-persist-example[]
@ -142,6 +148,9 @@ public class CheckTest extends BaseEntityManagerFunctionalTestCase {
@Column(table = "BookEdition")
private int edition = 1;
@Formula("edition + 1")
private int nextEdition = 2;
@Column(table = "BookEdition")
private LocalDate editionDate;

View File

@ -17,13 +17,6 @@ import org.hibernate.metamodel.model.domain.JpaMetamodel;
*/
@Deprecated(since = "6.0")
public interface Metamodel extends JpaMetamodel {
/**
* Access to the SessionFactory that this Metamodel instance is bound to.
*
* @return The SessionFactory
*/
SessionFactory getSessionFactory();
/**
* Given the name of an entity class, determine all the class and interface names by which it can be
* referenced in an HQL query.

View File

@ -18,8 +18,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*
* @author Matthew Inger
*
* @deprecated Prefer the standard JPA {@link jakarta.persistence.OrderColumn} annotation and the Hibernate specific
* {@link ListIndexBase} (for replacing {@link #base()}).
* @deprecated Prefer the standard JPA {@link jakarta.persistence.OrderColumn} annotation,
* using {@link ListIndexBase} instead of {@link #base()}.
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)

View File

@ -13,8 +13,8 @@ import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* A grouping of Hibernate-specific {@link NamedNativeQuery} definitions. Effectively extends the named native
* query definitions made available through {@link jakarta.persistence.NamedNativeQueries}.
* A grouping of {@link NamedNativeQuery} definitions. Extends the named native query
* definitions made available through {@link jakarta.persistence.NamedNativeQueries}.
*
* @author Emmanuel Bernard
*/

View File

@ -13,8 +13,8 @@ import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* A grouping of Hibernate-specific {@link NamedQuery} definitions. Effectively extends the named query
* definitions made available through {@link jakarta.persistence.NamedQueries}.
* A grouping of {@link NamedQuery} definitions. Extends the named query definitions
* made available through {@link jakarta.persistence.NamedQueries}.
*
* @author Emmanuel Bernard
* @author Carlos Gonzalez-Cadenas

View File

@ -368,7 +368,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
);
}
if ( inheritanceState.isEmbeddableSuperclass() ) {
join.addMappedsuperclassProperty( property );
join.addMappedSuperclassProperty( property );
addPropertyToMappedSuperclass( property, declaringClass );
}
else {

View File

@ -55,6 +55,7 @@ import org.hibernate.context.internal.ManagedSessionContext;
import org.hibernate.context.internal.ThreadLocalSessionContext;
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices;
@ -83,8 +84,10 @@ import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.internal.RuntimeMetamodelsImpl;
import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.metamodel.spi.MetamodelImplementor;
import org.hibernate.metamodel.spi.RuntimeMetamodelsImplementor;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.SessionFactoryBasedWrapperOptions;
@ -100,6 +103,7 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.sql.spi.NativeQueryImplementor;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.spi.NamedSqmQueryMemento;
import org.hibernate.relational.SchemaManager;
import org.hibernate.relational.internal.SchemaManagerImpl;
@ -251,9 +255,79 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
queryEngine = QueryEngine.from( this, bootMetamodel );
bootstrapContext.getTypeConfiguration().scope( this );
final RuntimeMetamodelsImpl runtimeMetamodelsImpl = new RuntimeMetamodelsImpl();
runtimeMetamodels = runtimeMetamodelsImpl;
runtimeMetamodelsImpl.finishInitialization( bootMetamodel, bootstrapContext, this );
new RuntimeModelCreationContext() {
final MappingMetamodelImpl mappingMetamodelImpl =
new MappingMetamodelImpl( typeConfiguration, serviceRegistry, options.getJpaCompliance() );
{
// need to set this before calling finishInitialization()
runtimeMetamodelsImpl.setMappingMetamodel( mappingMetamodelImpl );
// because this calls back to the RuntimeMetamodelsImplementor
mappingMetamodelImpl.finishInitialization( this );
// need to set this after calling finishInitialization()
runtimeMetamodelsImpl.setJpaMetamodel( mappingMetamodelImpl.getJpaMetamodel() );
}
@Override
public BootstrapContext getBootstrapContext() {
return bootstrapContext;
}
@Override
public SessionFactoryImplementor getSessionFactory() {
// this is bad, we're not yet fully-initialized
return SessionFactoryImpl.this;
}
@Override
public MetadataImplementor getBootModel() {
return bootMetamodel;
}
@Override
public MappingMetamodelImplementor getDomainModel() {
return mappingMetamodelImpl;
}
@Override
public CacheImplementor getCache() {
return cacheAccess;
}
@Override
public Map<String, Object> getSettings() {
return settings;
}
@Override
public Dialect getDialect() {
return jdbcServices.getDialect();
}
@Override
public SqmFunctionRegistry getFunctionRegistry() {
return queryEngine.getSqmFunctionRegistry();
}
@Override
public TypeConfiguration getTypeConfiguration() {
return typeConfiguration;
}
@Override
public SessionFactoryOptions getSessionFactoryOptions() {
return options;
}
@Override
public JdbcServices getJdbcServices() {
return jdbcServices;
}
};
queryEngine.prepare( this, bootMetamodel, bootstrapContext );
if ( options.isNamedQueryStartupCheckingEnabled() ) {
@ -328,7 +402,7 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
return generators;
}
private SqlStringGenerationContext createSqlStringGenerationContext(
private static SqlStringGenerationContext createSqlStringGenerationContext(
MetadataImplementor bootMetamodel,
SessionFactoryOptions options,
JdbcServices jdbcServices) {

View File

@ -22,11 +22,10 @@ public final class LockModeConverter {
}
/**
* Convert from the Hibernate specific LockMode to the JPA defined LockModeType.
* Convert from the Hibernate-specific {@link LockMode} to the JPA defined {@link LockModeType}.
*
* @param lockMode The Hibernate LockMode.
*
* @return The JPA LockModeType
* @param lockMode The Hibernate {@link LockMode}.
* @return The JPA {@link LockModeType}
*/
public static LockModeType convertToLockModeType(LockMode lockMode) {
if ( lockMode == LockMode.NONE ) {
@ -54,11 +53,10 @@ public final class LockModeConverter {
/**
* Convert from JPA defined LockModeType to Hibernate specific LockMode.
* Convert from JPA defined {@link LockModeType} to Hibernate-specific {@link LockMode}.
*
* @param lockMode The JPA LockModeType
*
* @return The Hibernate LockMode.
* @param lockMode The JPA {@link LockModeType}
* @return The Hibernate {@link LockMode}.
*/
public static LockMode convertToLockMode(LockModeType lockMode) {
switch ( lockMode ) {

View File

@ -26,5 +26,7 @@ public interface AttributeContainer {
/**
* Add a property to this {@link PersistentClass} or {@link Join}.
*/
void addProperty(Property attribute);
void addProperty(Property property);
boolean contains(Property property);
Table getTable();
}

View File

@ -51,12 +51,17 @@ public class Join implements AttributeContainer, Serializable {
public void addProperty(Property property) {
properties.add( property );
declaredProperties.add( property );
property.setPersistentClass( getPersistentClass() );
property.setPersistentClass( persistentClass );
}
public void addMappedsuperclassProperty( Property property ) {
@Override
public boolean contains(Property property) {
return properties.contains( property );
}
public void addMappedSuperclassProperty(Property property ) {
properties.add( property );
property.setPersistentClass( getPersistentClass() );
property.setPersistentClass( persistentClass );
}
public List<Property> getDeclaredProperties() {

View File

@ -23,19 +23,19 @@ import org.hibernate.boot.model.CustomSql;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.ClassLoaderAccess;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.FilterConfiguration;
import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.internal.util.collections.JoinedList;
import org.hibernate.internal.util.collections.SingletonIterator;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.jpa.event.spi.CallbackDefinition;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.Alias;
import org.hibernate.sql.Template;
import org.hibernate.type.Type;
import org.hibernate.type.spi.TypeConfiguration;
@ -44,6 +44,7 @@ import static java.util.Collections.unmodifiableList;
import static java.util.Comparator.comparing;
import static org.hibernate.internal.util.StringHelper.qualify;
import static org.hibernate.internal.util.StringHelper.root;
import static org.hibernate.sql.Template.collectColumnNames;
/**
* A mapping model object that represents an {@linkplain jakarta.persistence.Entity entity class}.
@ -301,10 +302,15 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
}
@Override
public void addProperty(Property p) {
properties.add( p );
declaredProperties.add( p );
p.setPersistentClass( this );
public void addProperty(Property property) {
properties.add( property );
declaredProperties.add( property );
property.setPersistentClass( this );
}
@Override
public boolean contains(Property property) {
return properties.contains( property );
}
public abstract Table getTable();
@ -1224,36 +1230,55 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
// End of @MappedSuperclass support
public void prepareForMappingModel() {
public void prepareForMappingModel(RuntimeModelCreationContext context) {
final Dialect dialect = context.getDialect();
final TypeConfiguration typeConfiguration = context.getTypeConfiguration();
final SqmFunctionRegistry functionRegistry = context.getFunctionRegistry();
// assign check constraints to the right table
for ( CheckConstraint checkConstraint : checkConstraints ) {
container( collectColumnNames( checkConstraint.getConstraint(), dialect, typeConfiguration, functionRegistry ) )
.getTable().addCheck( checkConstraint );
}
// now, move @Formulas to the correct AttributeContainers
//TODO: skip this step for hbm.xml
for ( Property property : new ArrayList<>( properties ) ) {
for ( Selectable selectable : property.getSelectables() ) {
if ( selectable.isFormula() && properties.contains( property ) ) {
final Formula formula = (Formula) selectable;
final AttributeContainer container =
container( collectColumnNames( formula.getTemplate( dialect, typeConfiguration, functionRegistry ) ) );
if ( !container.contains( property ) ) {
properties.remove( property );
container.addProperty( property );
break; //TODO: embeddables
}
}
}
}
properties.sort( comparing( Property::getName ) );
}
public void mappingModelReady(MappingMetamodel mappingMetamodel) {
for ( CheckConstraint checkConstraint : checkConstraints ) {
final TypeConfiguration typeConfiguration = mappingMetamodel.getTypeConfiguration();
final SessionFactoryImplementor sessionFactory = typeConfiguration.getSessionFactory();
final List<String> constrainedColumnNames =
Template.collectColumnNames( checkConstraint.getConstraint(), typeConfiguration, sessionFactory );
final Table primary = getTable();
long matches = matchesInTable( constrainedColumnNames, primary );
if ( matches == constrainedColumnNames.size() ) {
// perfect, all columns matched in the primary table
primary.addCheck( checkConstraint );
}
else {
// go searching for a secondary table which better matches
Table table = primary;
long max = matches;
for ( Join join : getJoins() ) {
final Table secondary = join.getTable();
long secondaryMatches = matchesInTable( constrainedColumnNames, secondary );
if ( secondaryMatches > max ) {
table = secondary;
max = secondaryMatches;
}
private AttributeContainer container(List<String> constrainedColumnNames) {
long matches = matchesInTable( constrainedColumnNames, getTable() );
if ( matches == constrainedColumnNames.size() ) {
// perfect, all columns matched in the primary table
return this;
}
else {
// go searching for a secondary table which better matches
AttributeContainer result = this;
long max = matches;
for ( Join join : getJoins() ) {
long secondaryMatches = matchesInTable( constrainedColumnNames, join.getTable() );
if ( secondaryMatches > max ) {
result = join;
max = secondaryMatches;
}
table.addCheck( checkConstraint );
}
return result;
}
}

View File

@ -108,15 +108,15 @@ public class Subclass extends PersistentClass {
}
@Override
public void addProperty(Property p) {
super.addProperty(p);
getSuperclass().addSubclassProperty(p);
public void addProperty(Property property) {
super.addProperty( property );
getSuperclass().addSubclassProperty( property );
}
@Override
public void addMappedSuperclassProperty(Property p) {
super.addMappedSuperclassProperty( p );
getSuperclass().addSubclassProperty(p);
public void addMappedSuperclassProperty(Property property) {
super.addMappedSuperclassProperty( property );
getSuperclass().addSubclassProperty( property );
}
@Override

View File

@ -7,8 +7,8 @@
package org.hibernate.metamodel;
/**
* At the end of the day, any "value mapping" (id, version, attribute, collection element, etc) can be one
* of a few classifications. This defines an enumeration of those classifications
* At the end of the day, any "value mapping" (id, version, attribute, collection element, etc.)
* can be one of a few classifications. This defines an enumeration of those classifications.
*
* @author Steve Ebersole
*/
@ -18,9 +18,10 @@ public enum ValueClassification {
*/
BASIC,
/**
* ANY is a Hibernate specific concept. It is essentially a "reverse discrimination". Here, the association itself
* defines a discriminator to the associated entity - sort of the reverse of discriminator-inheritance. Here the
* various associated types can be unrelated in terms of mapped inheritance.
* ANY is a Hibernate-specific concept. It is essentially a "reverse discrimination".
* Here, the association itself defines a discriminator to the associated entity,
* sort of the reverse of discriminator-inheritance. Here the various associated types
* can be unrelated in terms of mapped inheritance.
*/
ANY,
/**

View File

@ -6,12 +6,8 @@
*/
package org.hibernate.metamodel.internal;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.metamodel.spi.RuntimeMetamodelsImplementor;
@ -46,22 +42,11 @@ public class RuntimeMetamodelsImpl implements RuntimeMetamodelsImplementor {
return mappingMetamodel.getEmbeddableValuedModelPart( role );
}
/**
* Chicken-and-egg because things try to use the SessionFactory (specifically the MappingMetamodel)
* before it is ready. So we do this fugly code...
*/
public void finishInitialization(
MetadataImplementor bootMetamodel,
BootstrapContext bootstrapContext,
SessionFactoryImpl sessionFactory) {
final MappingMetamodelImpl mappingMetamodel = bootstrapContext.getTypeConfiguration().scope( sessionFactory );
public void setMappingMetamodel(MappingMetamodelImplementor mappingMetamodel) {
this.mappingMetamodel = mappingMetamodel;
mappingMetamodel.finishInitialization(
bootMetamodel,
bootstrapContext,
sessionFactory
);
}
this.jpaMetamodel = mappingMetamodel.getJpaMetamodel();
public void setJpaMetamodel(JpaMetamodelImplementor jpaMetamodel) {
this.jpaMetamodel = jpaMetamodel;
}
}

View File

@ -32,18 +32,15 @@ public class MappingModelCreationProcess {
*/
public static void process(
Map<String,EntityPersister> entityPersisterMap,
SqmFunctionRegistry functionRegistry,
RuntimeModelCreationContext creationContext) {
final MappingModelCreationProcess process = new MappingModelCreationProcess(
entityPersisterMap,
functionRegistry,
creationContext
);
process.execute();
}
private final Map<String,EntityPersister> entityPersisterMap;
private final SqmFunctionRegistry functionRegistry;
private final RuntimeModelCreationContext creationContext;
@ -53,10 +50,8 @@ public class MappingModelCreationProcess {
private MappingModelCreationProcess(
Map<String, EntityPersister> entityPersisterMap,
SqmFunctionRegistry functionRegistry,
RuntimeModelCreationContext creationContext) {
this.entityPersisterMap = entityPersisterMap;
this.functionRegistry = functionRegistry;
this.creationContext = creationContext;
}
@ -69,7 +64,7 @@ public class MappingModelCreationProcess {
}
public SqmFunctionRegistry getSqmFunctionRegistry() {
return functionRegistry;
return creationContext.getFunctionRegistry();
}
/**

View File

@ -25,13 +25,11 @@ import org.hibernate.MappingException;
import org.hibernate.UnknownEntityTypeException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.BootstrapContext;
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.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.RootGraph;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.EntityManagerMessageLogger;
@ -43,8 +41,6 @@ import org.hibernate.mapping.Component;
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting;
import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
@ -68,6 +64,7 @@ import org.hibernate.query.BindableType;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.type.BasicType;
@ -104,8 +101,6 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
private static final String[] EMPTY_IMPLEMENTORS = ArrayHelper.EMPTY_STRING_ARRAY;
private final SessionFactoryImplementor sessionFactory;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JpaMetamodel
@ -160,79 +155,50 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
// private final Map<Class<?>, EmbeddableDomainType<?>> jpaEmbeddableTypeMap = new ConcurrentHashMap<>();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private final ServiceRegistry serviceRegistry;
private final TypeConfiguration typeConfiguration;
private final Map<String, String[]> implementorsCache = new ConcurrentHashMap<>();
private final Map<TupleType<?>, MappingModelExpressible<?>> tupleTypeCache = new ConcurrentHashMap<>();
public MappingMetamodelImpl(SessionFactoryImplementor sessionFactory, TypeConfiguration typeConfiguration) {
this.sessionFactory = sessionFactory;
public MappingMetamodelImpl(
TypeConfiguration typeConfiguration,
ServiceRegistry serviceRegistry,
JpaCompliance jpaCompliance) {
this.serviceRegistry = serviceRegistry;
this.typeConfiguration = typeConfiguration;
this.jpaMetamodel = new JpaMetamodelImpl( typeConfiguration, sessionFactory.getSessionFactoryOptions().getJpaCompliance() );
this.jpaMetamodel = new JpaMetamodelImpl( typeConfiguration, jpaCompliance );
}
public JpaMetamodelImplementor getJpaMetamodel() {
return jpaMetamodel;
}
public void finishInitialization(
MetadataImplementor bootModel,
BootstrapContext bootstrapContext,
SessionFactoryImplementor sessionFactory) {
final RuntimeModelCreationContext runtimeModelCreationContext = new RuntimeModelCreationContext() {
@Override
public BootstrapContext getBootstrapContext() {
return bootstrapContext;
}
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@Override
public MetadataImplementor getBootModel() {
return bootModel;
}
@Override
public MappingMetamodel getDomainModel() {
return MappingMetamodelImpl.this;
}
};
final PersisterFactory persisterFactory = sessionFactory.getServiceRegistry().getService( PersisterFactory.class );
final JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting = determineJpaStaticMetaModelPopulationSetting( sessionFactory.getProperties() );
final JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting = determineJpaMetaModelPopulationSetting( sessionFactory.getProperties() );
public void finishInitialization(RuntimeModelCreationContext context) {
final MetadataImplementor bootModel = context.getBootModel();
bootModel.visitRegisteredComponents( Component::prepareForMappingModel );
bootModel.getMappedSuperclassMappingsCopy().forEach( MappedSuperclass::prepareForMappingModel );
bootModel.getEntityBindings().forEach( PersistentClass::prepareForMappingModel );
bootModel.getEntityBindings().forEach( persistentClass -> persistentClass.prepareForMappingModel( context ) );
final PersisterFactory persisterFactory = serviceRegistry.getService( PersisterFactory.class );
final CacheImplementor cache = context.getCache();
processBootEntities(
bootModel.getEntityBindings(),
sessionFactory.getCache(),
cache,
persisterFactory,
runtimeModelCreationContext
context
);
processBootCollections(
bootModel.getCollectionBindings(),
sessionFactory.getCache(),
cache,
persisterFactory,
runtimeModelCreationContext
context
);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// after *all* persisters and named queries are registered
MappingModelCreationProcess.process(
entityPersisterMap,
sessionFactory.getQueryEngine().getSqmFunctionRegistry(),
runtimeModelCreationContext
);
MappingModelCreationProcess.process( entityPersisterMap, context );
for ( EntityPersister persister : entityPersisterMap.values() ) {
persister.postInstantiate();
@ -243,18 +209,16 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
registerEmbeddableMappingType( bootModel );
( (JpaMetamodelImpl) this.jpaMetamodel ).processJpa(
final Map<String, Object> settings = context.getSettings();
( (JpaMetamodelImpl) jpaMetamodel ).processJpa(
bootModel,
this,
entityProxyInterfaceMap,
jpaStaticMetaModelPopulationSetting,
jpaMetaModelPopulationSetting,
determineJpaStaticMetaModelPopulationSetting( settings ),
determineJpaMetaModelPopulationSetting( settings ),
bootModel.getNamedEntityGraphs().values(),
runtimeModelCreationContext
context
);
bootModel.getEntityBindings().forEach( persistentClass -> persistentClass.mappingModelReady( this ) );
}
private void registerEmbeddableMappingType(MetadataImplementor bootModel) {
@ -452,11 +416,6 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
return entityPersisterMap.containsKey( entityJavaType.getName() );
}
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@Override
public EntityPersister getEntityDescriptor(Class<?> entityJavaType) {
EntityPersister entityPersister = entityPersisterMap.get( entityJavaType.getName() );
@ -566,9 +525,7 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
}
try {
final Class<?> clazz = getSessionFactory().getServiceRegistry()
.getService( ClassLoaderService.class )
.classForName( className );
final Class<?> clazz = serviceRegistry.getService( ClassLoaderService.class ).classForName( className );
implementors = doGetImplementors( clazz );
if ( implementors.length > 0 ) {
implementorsCache.putIfAbsent( className, implementors );

View File

@ -29,10 +29,6 @@ import org.hibernate.persister.entity.EntityPersister;
*/
@Deprecated(since = "6.0")
public interface MetamodelImplementor extends MappingMetamodel, Metamodel {
@Override
SessionFactoryImplementor getSessionFactory();
/**
* @deprecated Use {@link MappingMetamodelImplementor#getEntityNameResolvers} instead
*/

View File

@ -8,13 +8,18 @@ package org.hibernate.metamodel.spi;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.Map;
/**
* @author Steve Ebersole
*/
@ -25,16 +30,12 @@ public interface RuntimeModelCreationContext extends PersisterCreationContext {
MetadataImplementor getBootModel();
MappingMetamodel getDomainModel();
MappingMetamodelImplementor getDomainModel();
default TypeConfiguration getTypeConfiguration() {
return getBootstrapContext().getTypeConfiguration();
}
default ManagedBeanRegistry getManagedBeanRegistry() {
return getSessionFactory().getServiceRegistry().getService( ManagedBeanRegistry.class );
}
default JavaTypeRegistry getJavaTypeRegistry() {
return getTypeConfiguration().getJavaTypeRegistry();
}
@ -43,4 +44,16 @@ public interface RuntimeModelCreationContext extends PersisterCreationContext {
default MetadataImplementor getMetadata() {
return getBootModel();
}
SqmFunctionRegistry getFunctionRegistry();
Map<String, Object> getSettings();
Dialect getDialect();
CacheImplementor getCache();
SessionFactoryOptions getSessionFactoryOptions();
JdbcServices getJdbcServices();
}

View File

@ -487,12 +487,14 @@ public abstract class AbstractEntityPersister
final NaturalIdDataAccess naturalIdRegionAccessStrategy,
final RuntimeModelCreationContext creationContext) throws HibernateException {
//set it here, but don't call it, since it's still uninitialized!
factory = creationContext.getSessionFactory();
sqlAliasStem = SqlAliasStemHelper.INSTANCE.generateStemFromEntityName( persistentClass.getEntityName() );
navigableRole = new NavigableRole( persistentClass.getEntityName() );
final SessionFactoryOptions sessionFactoryOptions = creationContext.getSessionFactory().getSessionFactoryOptions();
final SessionFactoryOptions sessionFactoryOptions = creationContext.getSessionFactoryOptions();
if ( sessionFactoryOptions.isSecondLevelCacheEnabled() ) {
this.cacheAccessStrategy = cacheAccessStrategy;
@ -1069,8 +1071,7 @@ public abstract class AbstractEntityPersister
}
private boolean isCacheComplianceEnabled(RuntimeModelCreationContext creationContext) {
return creationContext.getSessionFactory()
.getSessionFactoryOptions()
return creationContext.getSessionFactoryOptions()
.getJpaCompliance()
.isJpaCacheComplianceEnabled();
}
@ -4752,8 +4753,7 @@ public abstract class AbstractEntityPersister
else {
sqmMultiTableMutationStrategy.prepare(
creationProcess,
creationContext.getSessionFactory().getJdbcServices()
.getBootstrapJdbcConnectionAccess()
creationContext.getJdbcServices().getBootstrapJdbcConnectionAccess()
);
return true;
}
@ -4784,8 +4784,7 @@ public abstract class AbstractEntityPersister
else {
sqmMultiTableInsertStrategy.prepare(
creationProcess,
creationContext.getSessionFactory().getJdbcServices()
.getBootstrapJdbcConnectionAccess()
creationContext.getJdbcServices().getBootstrapJdbcConnectionAccess()
);
return true;
}

View File

@ -10,7 +10,6 @@ import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -34,10 +33,6 @@ public interface PersisterCreationContext {
MetadataImplementor getMetadata();
default ManagedBeanRegistry getManagedBeanRegistry() {
return getSessionFactory().getServiceRegistry().getService( ManagedBeanRegistry.class );
}
default JavaTypeRegistry getJavaTypeRegistry() {
return getTypeConfiguration().getJavaTypeRegistry();
}

View File

@ -362,15 +362,14 @@ public final class Template {
}
public static List<String> collectColumnNames(
String checkConstraint,
String sql,
Dialect dialect,
TypeConfiguration typeConfiguration,
SessionFactoryImplementor sessionFactory) {
final String template = renderWhereStringTemplate(
checkConstraint,
sessionFactory.getJdbcServices().getDialect(),
typeConfiguration,
sessionFactory.getQueryEngine().getSqmFunctionRegistry()
);
SqmFunctionRegistry functionRegistry) {
return collectColumnNames( renderWhereStringTemplate( sql, dialect, typeConfiguration, functionRegistry ) );
}
public static List<String> collectColumnNames(String template) {
final List<String> names = new ArrayList<>();
int begin = 0;
int match;

View File

@ -49,7 +49,6 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.metamodel.model.domain.internal.ArrayTupleType;
import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl;
import org.hibernate.query.sqm.BinaryArithmeticOperator;
import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.internal.QueryHelper;
@ -156,25 +155,39 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
// Scoping
/**
* Obtain the MetadataBuildingContext currently scoping the
* TypeConfiguration.
* Obtain the {@link MetadataBuildingContext} currently scoping this
* {@code TypeConfiguration}.
*
* @apiNote This will throw an exception if the SessionFactory is not yet
* bound here. See {@link Scope} for more details regarding the stages
* a TypeConfiguration goes through
*
* @return The MetadataBuildingContext
* @return The {@link MetadataBuildingContext}
*/
public MetadataBuildingContext getMetadataBuildingContext() {
return scope.getMetadataBuildingContext();
}
/**
* Scope this {@code TypeConfiguration} to the given {@link MetadataBuildingContext}.
*
* @implNote The given factory is not yet fully-initialized!
*
* @param metadataBuildingContext a {@link MetadataBuildingContext}
*/
public void scope(MetadataBuildingContext metadataBuildingContext) {
log.debugf( "Scoping TypeConfiguration [%s] to MetadataBuildingContext [%s]", this, metadataBuildingContext );
scope.setMetadataBuildingContext( metadataBuildingContext );
}
public MappingMetamodelImpl scope(SessionFactoryImplementor sessionFactory) {
/**
* Scope this {@code TypeConfiguration} to the given {@link SessionFactory}.
*
* @implNote The given factory is not yet fully-initialized!
*
* @param sessionFactory a {@link SessionFactory} that is in a very fragile state
*/
public void scope(SessionFactoryImplementor sessionFactory) {
log.debugf( "Scoping TypeConfiguration [%s] to SessionFactoryImplementor [%s]", this, sessionFactory );
if ( scope.getMetadataBuildingContext() == null ) {
@ -183,33 +196,31 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
scope.setSessionFactory( sessionFactory );
sessionFactory.addObserver( this );
return new MappingMetamodelImpl( sessionFactory, this );
}
/**
* Obtain the SessionFactory currently scoping the TypeConfiguration.
* Obtain the {@link SessionFactory} currently scoping the {@code TypeConfiguration}.
*
* @apiNote This will throw an exception if the SessionFactory is not yet
* bound here. See {@link Scope} for more details regarding the stages
* a TypeConfiguration goes through (this is "runtime stage")
* @apiNote Throws an exception if the {@code TypeConfiguration} is not yet scoped to
* a factory. See {@link Scope} for more details regarding the stages a
* {@code TypeConfiguration} passes through (this is a "runtime stage").
*
* @return The SessionFactory
* @return The {@link SessionFactory} to which this {@code TypeConfiguration} is scoped
*
* @throws IllegalStateException if the TypeConfiguration is currently not
* associated with a SessionFactory (in "runtime stage").
* @throws HibernateException if the {@code TypeConfiguration} is not currently scoped
* to a {@link SessionFactory} (in a "runtime stage").
*/
public SessionFactoryImplementor getSessionFactory() {
return scope.getSessionFactory();
}
/**
* Obtain the ServiceRegistry scoped to the TypeConfiguration.
* Obtain the {@link ServiceRegistry} scoped to the {@code TypeConfiguration}.
*
* @apiNote Depending on what the {@link Scope} is currently scoped to will determine where the
* {@link ServiceRegistry} is obtained from.
* @apiNote The current {@link Scope} will determine from where the {@link ServiceRegistry}
* is obtained.
*
* @return The ServiceRegistry
* @return The {@link ServiceRegistry} for the current scope
*/
public ServiceRegistry getServiceRegistry() {
return scope.getServiceRegistry();
@ -323,30 +334,32 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
}
/**
* Encapsulation of lifecycle concerns for a TypeConfiguration:<ol>
* Encapsulation of lifecycle concerns of a {@link TypeConfiguration}:
* <ol>
* <li>
* "Boot" is where the {@link TypeConfiguration} is first
* built as the boot-model ({@link org.hibernate.boot.model}) of
* the user's domain model is converted into the runtime-model
* ({@link org.hibernate.metamodel.model}). During this phase,
* {@link #getMetadataBuildingContext()} will be accessible but
* {@link #getSessionFactory} will throw an exception.
* "Boot" is where the {@link TypeConfiguration} is first built as
* {@linkplain org.hibernate.boot.model the boot model} of the domain
* model is converted into {@linkplain org.hibernate.metamodel.model
* the runtime model}. During this phase,
* {@link #getMetadataBuildingContext()} is accessible but
* {@link #getSessionFactory} throws an exception.
* </li>
* <li>
* "Runtime" is where the runtime-model is accessible. During this
* phase {@link #getSessionFactory()} is accessible while
* {@link #getMetadataBuildingContext()} will now throw an exception
* "Runtime" is where the runtime model is accessible. During this
* phase, {@link #getSessionFactory()} is accessible but
* {@link #getMetadataBuildingContext()} throws an exception.
* </li>
* <li>
* "Sunset" is after the SessionFactory has been closed. At this point, both
* {@link #getSessionFactory()} and {@link #getMetadataBuildingContext()}
* will now throw an exception
* "Sunset" happens after the {@link SessionFactory} has been closed.
* Both {@link #getSessionFactory()} and {@link #getMetadataBuildingContext()}
* throw exceptions.
* </li>
* </ol>
* <p>
* {@link #getServiceRegistry()} is available for both "Boot" and "Runtime".
*
* Each stage or phase is consider a scope for the TypeConfiguration.
* On the other hand, the {@linkplain #getServiceRegistry() service registry}
* is available during both "Boot" and "Runtime" phases.
* <p>
* Each stage or phase is considered a scope for the {@link TypeConfiguration}.
*/
private static class Scope implements Serializable {
private final TypeConfiguration typeConfiguration;
@ -456,9 +469,9 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
}
/**
* Used by TypeFactory scoping.
* Used by {@link TypeConfiguration} scoping.
*
* @param factory The SessionFactory that the TypeFactory is being bound to
* @param factory The {@link SessionFactory} to which the {@link TypeConfiguration} is being bound
*/
void setSessionFactory(SessionFactoryImplementor factory) {
if ( this.sessionFactory != null ) {
@ -466,15 +479,15 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
}
else {
this.sessionFactoryUuid = factory.getUuid();
String sfName = factory.getSessionFactoryOptions().getSessionFactoryName();
if ( sfName == null ) {
String factoryName = factory.getSessionFactoryOptions().getSessionFactoryName();
if ( factoryName == null ) {
final CfgXmlAccessService cfgXmlAccessService = factory.getServiceRegistry()
.getService( CfgXmlAccessService.class );
if ( cfgXmlAccessService.getAggregatedConfig() != null ) {
sfName = cfgXmlAccessService.getAggregatedConfig().getSessionFactoryName();
factoryName = cfgXmlAccessService.getAggregatedConfig().getSessionFactoryName();
}
}
this.sessionFactoryName = sfName;
this.sessionFactoryName = factoryName;
}
this.sessionFactory = factory;
}

View File

@ -25,8 +25,8 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* Tests Hibernate specific feature that {@link org.hibernate.annotations.SortNatural @SortNatural} will take effect implicitly
* when no <i>sort</i> or <i>order</i> related annotations exist, including:
* Tests Hibernate-specific feature that {@link org.hibernate.annotations.SortNatural @SortNatural}
* will take effect implicitly when no <i>sort</i> or <i>order</i> related annotations exist, including:
* <ul>
* <li>{@link org.hibernate.annotations.SortNatural @SortNatural}</li>
* <li>{@link org.hibernate.annotations.SortComparator @SortComparator}</li>

View File

@ -35,15 +35,13 @@ public class MetadataBuildingContextTestingImpl implements MetadataBuildingConte
buildingOptions.setBootstrapContext( bootstrapContext = new BootstrapContextImpl( serviceRegistry, buildingOptions ) );
mappingDefaults = new MetadataBuilderImpl.MappingDefaultsImpl( serviceRegistry );
metadataCollector = new InFlightMetadataCollectorImpl( bootstrapContext, buildingOptions );
objectNameNormalizer = new ObjectNameNormalizer() {
@Override
protected MetadataBuildingContext getBuildingContext() {
return MetadataBuildingContextTestingImpl.this;
}
};
this.typeDefinitionRegistry = new TypeDefinitionRegistryStandardImpl();
typeDefinitionRegistry = new TypeDefinitionRegistryStandardImpl();
bootstrapContext.getTypeConfiguration().scope( this );
}

View File

@ -34,14 +34,14 @@ import org.hibernate.jpamodelgen.util.TypeUtils;
public class MetaAttributeGenerationVisitor extends SimpleTypeVisitor6<AnnotationMetaAttribute, Element> {
/**
* FQCN of the Hibernate specific @Target annotation. We do not use the class directly to avoid depending on Hibernate
* Core.
* FQCN of the Hibernate-specific {@code @Target} annotation.
* We do not use the class directly to avoid depending on Hibernate Core.
*/
private static final String ORG_HIBERNATE_ANNOTATIONS_TARGET = "org.hibernate.annotations.Target";
/**
* FQCN of the Hibernate specific @Type annotation. We do not use the class directly to avoid depending on Hibernate
* Core.
* FQCN of the Hibernate-specific {@code @Type} annotation.
* We do not use the class directly to avoid depending on Hibernate Core.
*/
private static final String ORG_HIBERNATE_ANNOTATIONS_TYPE = "org.hibernate.annotations.Type";