Skip to content

Commit b572c0d

Browse files
committed
two simplifications to SessionFactoryImpl
1. move BindingContext implementation to RuntimeMetamodelsImplementor 2. move named query registration to NamedObjectRepository better separation of concerns!
1 parent 80ae0e9 commit b572c0d

File tree

5 files changed

+94
-90
lines changed

5 files changed

+94
-90
lines changed

hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java

Lines changed: 33 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import javax.naming.Reference;
2626
import javax.naming.StringRefAddr;
2727

28-
import org.hibernate.AssertionFailure;
2928
import org.hibernate.CustomEntityDirtinessStrategy;
3029
import org.hibernate.EntityNameResolver;
3130
import org.hibernate.FlushMode;
@@ -90,17 +89,11 @@
9089
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
9190
import org.hibernate.metamodel.spi.RuntimeMetamodelsImplementor;
9291
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
93-
import org.hibernate.procedure.spi.ProcedureCallImplementor;
9492
import org.hibernate.proxy.EntityNotFoundDelegate;
9593
import org.hibernate.proxy.LazyInitializer;
96-
import org.hibernate.query.BindingContext;
97-
import org.hibernate.query.hql.spi.SqmQueryImplementor;
9894
import org.hibernate.query.internal.QueryEngineImpl;
99-
import org.hibernate.query.named.NamedObjectRepository;
10095
import org.hibernate.query.spi.QueryEngine;
101-
import org.hibernate.query.spi.QueryImplementor;
10296
import org.hibernate.query.sql.internal.SqlTranslationEngineImpl;
103-
import org.hibernate.query.sql.spi.NativeQueryImplementor;
10497
import org.hibernate.query.sql.spi.SqlTranslationEngine;
10598
import org.hibernate.query.sqm.NodeBuilder;
10699
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
@@ -167,7 +160,7 @@
167160
* @author Steve Ebersole
168161
* @author Chris Cranford
169162
*/
170-
public class SessionFactoryImpl implements SessionFactoryImplementor, BindingContext {
163+
public class SessionFactoryImpl implements SessionFactoryImplementor {
171164
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SessionFactoryImpl.class );
172165

173166
private final String name;
@@ -290,21 +283,26 @@ public SessionFactoryImpl(
290283

291284
primeSecondLevelCacheRegions( bootMetamodel );
292285

293-
// we build this before creating the runtime metamodel
286+
// create the empty runtime metamodels object
287+
final RuntimeMetamodelsImpl runtimeMetamodelsImpl = new RuntimeMetamodelsImpl( typeConfiguration );
288+
runtimeMetamodels = runtimeMetamodelsImpl;
289+
290+
// we build this before creating the runtime metamodels
294291
// because the persisters need the SqmFunctionRegistry
295-
// to translate SQL formulas ... but, if we fix Dialect
292+
// to translate SQL formulas. But, if we fix Dialect
296293
// as I proposed, so that it can contribute functions
297294
// to the SqmFunctionRegistry before the QueryEngine is
298295
// created, then we can split creation of QueryEngine
299296
// and SqmFunctionRegistry, instantiating just the
300-
// registry here, and doing the engine later
301-
queryEngine = new QueryEngineImpl( bootMetamodel, options, this, serviceRegistry, settings, name );
297+
// registry here, and doing the engine later, and we
298+
// can thus untie this nasty little knot. Alternatively,
299+
// perhaps it's not really appropriate that they use the
300+
// SqmFunctionRegistry for that purpose at all?
301+
queryEngine = new QueryEngineImpl( bootMetamodel, options, runtimeMetamodels, serviceRegistry, settings, name );
302302
final Map<String, FetchProfile> fetchProfiles = new HashMap<>();
303303
sqlTranslationEngine = new SqlTranslationEngineImpl( this, typeConfiguration, fetchProfiles );
304304

305-
// create runtime metamodels (mapping and JPA)
306-
final RuntimeMetamodelsImpl runtimeMetamodelsImpl = new RuntimeMetamodelsImpl();
307-
runtimeMetamodels = runtimeMetamodelsImpl;
305+
// now actually create the mapping and JPA metamodels
308306
final MappingMetamodelImpl mappingMetamodelImpl = new MappingMetamodelImpl( typeConfiguration, serviceRegistry );
309307
runtimeMetamodelsImpl.setMappingMetamodel( mappingMetamodelImpl );
310308
mappingMetamodelImpl.finishInitialization(
@@ -478,10 +476,12 @@ private SessionBuilderImpl buildTemporarySessionOpenOptions() {
478476
private void primeSecondLevelCacheRegions(MetadataImplementor mappingMetadata) {
479477
final Map<String, DomainDataRegionConfigImpl.Builder> regionConfigBuilders = new ConcurrentHashMap<>();
480478

481-
// todo : ultimately this code can be made more efficient when we have a better intrinsic understanding of the hierarchy as a whole
479+
// TODO: ultimately this code can be made more efficient when we have
480+
// a better intrinsic understanding of the hierarchy as a whole
482481

483482
for ( PersistentClass bootEntityDescriptor : mappingMetadata.getEntityBindings() ) {
484-
final AccessType accessType = AccessType.fromExternalName( bootEntityDescriptor.getCacheConcurrencyStrategy() );
483+
final AccessType accessType =
484+
AccessType.fromExternalName( bootEntityDescriptor.getCacheConcurrencyStrategy() );
485485

486486
if ( accessType != null ) {
487487
if ( bootEntityDescriptor.isCached() ) {
@@ -530,29 +530,25 @@ private void primeSecondLevelCacheRegions(MetadataImplementor mappingMetadata) {
530530
}
531531

532532
@Override
533-
public SessionImplementor openSession() throws HibernateException {
534-
//The defaultSessionOpenOptions can't be used in some cases; for example when using a TenantIdentifierResolver.
535-
if ( defaultSessionOpenOptions != null ) {
536-
return defaultSessionOpenOptions.openSession();
537-
}
538-
else {
539-
return withOptions().openSession();
540-
}
533+
public SessionImplementor openSession() {
534+
// The defaultSessionOpenOptions can't be used in some cases;
535+
// for example when using a TenantIdentifierResolver.
536+
return defaultSessionOpenOptions != null
537+
? defaultSessionOpenOptions.openSession()
538+
: withOptions().openSession();
541539
}
542540

543541
@Override
544-
public SessionImpl openTemporarySession() throws HibernateException {
545-
//The temporarySessionOpenOptions can't be used in some cases; for example when using a TenantIdentifierResolver.
546-
if ( temporarySessionOpenOptions != null ) {
547-
return temporarySessionOpenOptions.openSession();
548-
}
549-
else {
550-
return buildTemporarySessionOpenOptions().openSession();
551-
}
542+
public SessionImpl openTemporarySession() {
543+
// The temporarySessionOpenOptions can't be used in some cases;
544+
// for example when using a TenantIdentifierResolver.
545+
return temporarySessionOpenOptions != null
546+
? temporarySessionOpenOptions.openSession()
547+
: buildTemporarySessionOpenOptions().openSession();
552548
}
553549

554550
@Override
555-
public Session getCurrentSession() throws HibernateException {
551+
public Session getCurrentSession() {
556552
if ( currentSessionContext == null ) {
557553
throw new HibernateException( "No CurrentSessionContext configured" );
558554
}
@@ -791,7 +787,7 @@ public Reference getReference() {
791787
* collector release the memory.
792788
*/
793789
@Override
794-
public void close() throws HibernateException {
790+
public void close() {
795791
synchronized (this) {
796792
if ( status != Status.OPEN ) {
797793
if ( getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) {
@@ -871,58 +867,7 @@ public PersistenceUnitTransactionType getTransactionType() {
871867
@Override
872868
public void addNamedQuery(String name, Query query) {
873869
validateNotClosed();
874-
875-
// NOTE : we use Query#unwrap here (rather than direct type checking)
876-
// to account for possibly wrapped query implementations
877-
878-
// first, handle StoredProcedureQuery
879-
final NamedObjectRepository namedObjectRepository = getQueryEngine().getNamedObjectRepository();
880-
try {
881-
final ProcedureCallImplementor<?> unwrapped = query.unwrap( ProcedureCallImplementor.class );
882-
if ( unwrapped != null ) {
883-
namedObjectRepository.registerCallableQueryMemento( name, unwrapped.toMemento( name ) );
884-
return;
885-
}
886-
}
887-
catch ( PersistenceException ignore ) {
888-
// this means 'query' is not a ProcedureCallImplementor
889-
}
890-
891-
// then try as a native-SQL or JPQL query
892-
try {
893-
final QueryImplementor<?> queryImplementor = query.unwrap( QueryImplementor.class );
894-
if ( queryImplementor != null ) {
895-
// create and register the proper NamedQueryDefinition...
896-
if ( queryImplementor instanceof NativeQueryImplementor<?> nativeQueryImplementor ) {
897-
namedObjectRepository.registerNativeQueryMemento(
898-
name,
899-
nativeQueryImplementor.toMemento( name )
900-
);
901-
902-
}
903-
else if ( queryImplementor instanceof SqmQueryImplementor<?> sqmQueryImplementor ) {
904-
namedObjectRepository.registerSqmQueryMemento(
905-
name,
906-
sqmQueryImplementor.toMemento( name )
907-
);
908-
}
909-
else {
910-
throw new AssertionFailure("unknown QueryImplementor");
911-
}
912-
return;
913-
}
914-
}
915-
catch ( PersistenceException ignore ) {
916-
// this means 'query' is not a native-SQL or JPQL query
917-
}
918-
919-
// if we get here, we are unsure how to properly unwrap the incoming query to extract the needed information
920-
throw new PersistenceException(
921-
String.format(
922-
"Unsure how to properly unwrap given Query [%s] as basis for named query",
923-
query
924-
)
925-
);
870+
getQueryEngine().getNamedObjectRepository().registerNamedQuery( name, query );
926871
}
927872

928873
@Override
@@ -1001,7 +946,7 @@ public StatisticsImplementor getStatistics() {
1001946
return statistics;
1002947
}
1003948

1004-
public FilterDefinition getFilterDefinition(String filterName) throws HibernateException {
949+
public FilterDefinition getFilterDefinition(String filterName) {
1005950
final FilterDefinition filterDefinition = filters.get( filterName );
1006951
if ( filterDefinition == null ) {
1007952
throw new UnknownFilterException( filterName );

hibernate-core/src/main/java/org/hibernate/metamodel/internal/RuntimeMetamodelsImpl.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,24 @@
99
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
1010
import org.hibernate.metamodel.spi.RuntimeMetamodelsImplementor;
1111
import org.hibernate.type.Type;
12+
import org.hibernate.type.spi.TypeConfiguration;
1213

1314
/**
1415
* @author Steve Ebersole
1516
*/
1617
public class RuntimeMetamodelsImpl implements RuntimeMetamodelsImplementor {
1718

19+
private final TypeConfiguration typeConfiguration;
1820
private JpaMetamodelImplementor jpaMetamodel;
1921
private MappingMetamodelImplementor mappingMetamodel;
2022

21-
public RuntimeMetamodelsImpl() {
23+
public RuntimeMetamodelsImpl(TypeConfiguration typeConfiguration) {
24+
this.typeConfiguration = typeConfiguration;
25+
}
26+
27+
@Override
28+
public TypeConfiguration getTypeConfiguration() {
29+
return typeConfiguration;
2230
}
2331

2432
@Override

hibernate-core/src/main/java/org/hibernate/metamodel/spi/RuntimeMetamodelsImplementor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
import org.hibernate.metamodel.RuntimeMetamodels;
88
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
9+
import org.hibernate.query.BindingContext;
910
import org.hibernate.type.MappingContext;
1011

1112
/**
1213
* SPI extending {@link RuntimeMetamodels} and mixing in {@link MappingContext}.
1314
*
1415
* @author Steve Ebersole
1516
*/
16-
public interface RuntimeMetamodelsImplementor extends RuntimeMetamodels, MappingContext {
17+
public interface RuntimeMetamodelsImplementor extends RuntimeMetamodels, MappingContext, BindingContext {
1718
@Override
1819
MappingMetamodelImplementor getMappingMetamodel();
1920

hibernate-core/src/main/java/org/hibernate/query/internal/NamedObjectRepositoryImpl.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import java.util.Map;
99
import java.util.function.Consumer;
1010

11+
import jakarta.persistence.PersistenceException;
12+
import jakarta.persistence.Query;
13+
import org.hibernate.AssertionFailure;
1114
import org.hibernate.HibernateException;
1215
import org.hibernate.QueryException;
1316
import org.hibernate.boot.Metadata;
@@ -17,6 +20,10 @@
1720
import org.hibernate.boot.spi.MetadataImplementor;
1821
import org.hibernate.engine.spi.SessionFactoryImplementor;
1922
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
23+
import org.hibernate.procedure.spi.ProcedureCallImplementor;
24+
import org.hibernate.query.hql.spi.SqmQueryImplementor;
25+
import org.hibernate.query.spi.QueryImplementor;
26+
import org.hibernate.query.sql.spi.NativeQueryImplementor;
2027
import org.hibernate.query.sqm.EntityTypeException;
2128
import org.hibernate.query.NamedQueryValidationException;
2229
import org.hibernate.query.sqm.PathElementException;
@@ -76,6 +83,46 @@ public <R> Map<String, TypedQueryReference<R>> getNamedQueries(Class<R> resultTy
7683
return namedQueries;
7784
}
7885

86+
@Override
87+
public void registerNamedQuery(String name, Query query) {
88+
// use unwrap() here instead of 'instanceof' because the Query might be wrapped
89+
90+
// first, handle stored procedures
91+
try {
92+
final var unwrapped = query.unwrap( ProcedureCallImplementor.class );
93+
if ( unwrapped != null ) {
94+
registerCallableQueryMemento( name, unwrapped.toMemento( name ) );
95+
return;
96+
}
97+
}
98+
catch ( PersistenceException ignore ) {
99+
// this means 'query' is not a ProcedureCallImplementor
100+
}
101+
102+
// then try as a native SQL or JPQL query
103+
try {
104+
final var queryImplementor = query.unwrap( QueryImplementor.class );
105+
if ( queryImplementor != null ) {
106+
if ( queryImplementor instanceof NativeQueryImplementor<?> nativeQueryImplementor ) {
107+
registerNativeQueryMemento( name, nativeQueryImplementor.toMemento( name ) );
108+
109+
}
110+
else if ( queryImplementor instanceof SqmQueryImplementor<?> sqmQueryImplementor ) {
111+
registerSqmQueryMemento( name, sqmQueryImplementor.toMemento( name ) );
112+
}
113+
else {
114+
throw new AssertionFailure( "unknown QueryImplementor" );
115+
}
116+
return;
117+
}
118+
}
119+
catch ( PersistenceException ignore ) {
120+
// this means 'query' is not a native SQL or JPQL query
121+
}
122+
123+
throw new PersistenceException( "Could not register named query: " + name );
124+
}
125+
79126
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
80127
// Named SQM Memento
81128

hibernate-core/src/main/java/org/hibernate/query/named/NamedObjectRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.Map;
88
import java.util.function.Consumer;
99

10+
import jakarta.persistence.Query;
1011
import org.hibernate.HibernateException;
1112
import org.hibernate.Incubating;
1213
import org.hibernate.boot.Metadata;
@@ -33,6 +34,8 @@ public interface NamedObjectRepository {
3334

3435
<R> Map<String, TypedQueryReference<R>> getNamedQueries(Class<R> resultType);
3536

37+
void registerNamedQuery(String name, Query query);
38+
3639
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3740
// Named SQM Memento
3841

0 commit comments

Comments
 (0)