From 2284b2b1425efe1b2e3e3e41de75530c4d80b41d Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 2 May 2024 13:00:45 -0500 Subject: [PATCH] HHH-18048 - Split notions of SessionFactory name and SessionFactory JNDI name --- .../java/org/hibernate/SessionFactory.java | 5 + .../hibernate/boot/SessionFactoryBuilder.java | 2 + ...SessionFactoryObserverForRegistration.java | 7 +- .../SessionFactoryOptionsBuilder.java | 4 +- ...stractDelegatingSessionFactoryOptions.java | 2 +- .../boot/spi/SessionFactoryOptions.java | 10 +- .../hibernate/cfg/PersistenceSettings.java | 24 ++++- .../spi/SessionFactoryDelegatingImpl.java | 5 + .../internal/SessionFactoryImpl.java | 35 ++++++- .../internal/SessionFactoryRegistry.java | 47 ++++----- .../test/boot/SessionFactoryNamingTests.java | 95 +++++++++++++++++++ .../SessionFactorySerializationTest.java | 12 +-- .../xml/boot/named-session-factory.xml | 17 ++++ migration-guide.adoc | 27 ++++++ 14 files changed, 242 insertions(+), 50 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/boot/SessionFactoryNamingTests.java create mode 100644 hibernate-core/src/test/resources/xml/boot/named-session-factory.xml diff --git a/hibernate-core/src/main/java/org/hibernate/SessionFactory.java b/hibernate-core/src/main/java/org/hibernate/SessionFactory.java index fe4992b659..6503cbe399 100644 --- a/hibernate-core/src/main/java/org/hibernate/SessionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/SessionFactory.java @@ -137,6 +137,11 @@ import static org.hibernate.internal.TransactionManagement.manageTransaction; * @author Steve Ebersole */ public interface SessionFactory extends EntityManagerFactory, Referenceable, Serializable, java.io.Closeable { + /** + * The JNDI name, used to bind the SessionFactory to JNDI + */ + String getJndiName(); + /** * Obtain a {@linkplain SessionBuilder session builder} for creating * new {@link Session}s with certain customized options. diff --git a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java index bdb908ac9d..478e3e09f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java @@ -84,7 +84,9 @@ public interface SessionFactoryBuilder { * * @return {@code this}, for method chaining * + * @see org.hibernate.cfg.AvailableSettings#SESSION_FACTORY_NAME * @see org.hibernate.cfg.AvailableSettings#SESSION_FACTORY_NAME_IS_JNDI + * @see org.hibernate.cfg.AvailableSettings#SESSION_FACTORY_JNDI_NAME */ SessionFactoryBuilder applyNameAsJndiName(boolean isJndiName); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryObserverForRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryObserverForRegistration.java index 338ad64cd6..1169e1d9dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryObserverForRegistration.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryObserverForRegistration.java @@ -23,19 +23,16 @@ import org.hibernate.internal.SessionFactoryRegistry; * @author Gavin King */ class SessionFactoryObserverForRegistration implements SessionFactoryObserver { - private JndiService jndiService; - private boolean registeredInJndi; @Override public void sessionFactoryCreated(SessionFactory factory) { final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) factory; jndiService = sessionFactory.getServiceRegistry().getService( JndiService.class ); - registeredInJndi = sessionFactory.getSessionFactoryOptions().isSessionFactoryNameAlsoJndiName(); SessionFactoryRegistry.INSTANCE.addSessionFactory( sessionFactory.getUuid(), sessionFactory.getName(), - registeredInJndi, + sessionFactory.getJndiName(), sessionFactory, jndiService ); @@ -47,7 +44,7 @@ class SessionFactoryObserverForRegistration implements SessionFactoryObserver { SessionFactoryRegistry.INSTANCE.removeSessionFactory( sessionFactory.getUuid(), sessionFactory.getName(), - registeredInJndi, + sessionFactory.getJndiName(), jndiService ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 234a4954ae..f3b3038e98 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -171,7 +171,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { // SessionFactory behavior private final boolean jpaBootstrap; private String sessionFactoryName; - private boolean sessionFactoryNameAlsoJndiName; + private Boolean sessionFactoryNameAlsoJndiName; // Session behavior private boolean flushBeforeCompletionEnabled; @@ -931,7 +931,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { } @Override - public boolean isSessionFactoryNameAlsoJndiName() { + public Boolean isSessionFactoryNameAlsoJndiName() { return sessionFactoryNameAlsoJndiName; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java index 777fb0194c..361c508da8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java @@ -101,7 +101,7 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp } @Override - public boolean isSessionFactoryNameAlsoJndiName() { + public Boolean isSessionFactoryNameAlsoJndiName() { return delegate.isSessionFactoryNameAlsoJndiName(); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index d983eb79e7..1fb1920580 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -85,10 +85,10 @@ public interface SessionFactoryOptions extends QueryEngineOptions { } /** - * The name to be used for the SessionFactory. This is used both in: + * The name to be used for the SessionFactory. This is used during in-VM serialization; see + * {@link org.hibernate.internal.SessionFactoryRegistry}. + * May also be used as a JNDI name depending on {@value org.hibernate.cfg.PersistenceSettings#SESSION_FACTORY_JNDI_NAME} + * and {@value org.hibernate.cfg.PersistenceSettings#SESSION_FACTORY_NAME_IS_JNDI}. * * @return The SessionFactory name */ @@ -100,7 +100,7 @@ public interface SessionFactoryOptions extends QueryEngineOptions { * * @return {@code true} if the SessionFactory name is also a JNDI name; {@code false} otherwise. */ - boolean isSessionFactoryNameAlsoJndiName(); + Boolean isSessionFactoryNameAlsoJndiName(); boolean isFlushBeforeCompletionEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/PersistenceSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/PersistenceSettings.java index f6ef51c52d..065630d9fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/PersistenceSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/PersistenceSettings.java @@ -7,6 +7,7 @@ package org.hibernate.cfg; import org.hibernate.Incubating; +import org.hibernate.SessionFactory; import org.hibernate.SessionFactoryObserver; import jakarta.persistence.spi.PersistenceUnitInfo; @@ -61,15 +62,26 @@ public interface PersistenceSettings { * Naming the SessionFactory allows for it to be properly serialized across JVMs as * long as the same name is used on each JVM. *

- * If {@link #SESSION_FACTORY_NAME_IS_JNDI} is set to {@code true}, this is also the - * name under which the SessionFactory is bound into JNDI on startup and from which - * it can be obtained from JNDI. + * If {@link #SESSION_FACTORY_NAME_IS_JNDI} is set to {@code true}, this name will + * also be used as {@link #SESSION_FACTORY_JNDI_NAME}. + * + * @see #SESSION_FACTORY_JNDI_NAME + * @see org.hibernate.internal.SessionFactoryRegistry + * @see org.hibernate.boot.SessionFactoryBuilder#applyName(String) + */ + String SESSION_FACTORY_NAME = "hibernate.session_factory_name"; + + /** + * An optional name used to bind the SessionFactory into JNDI. + *

+ * If {@link #SESSION_FACTORY_NAME_IS_JNDI} is set to {@code true}, + * {@link #SESSION_FACTORY_NAME} will be used as the JNDI name * * @see #SESSION_FACTORY_NAME_IS_JNDI * @see org.hibernate.internal.SessionFactoryRegistry * @see org.hibernate.boot.SessionFactoryBuilder#applyName(String) */ - String SESSION_FACTORY_NAME = "hibernate.session_factory_name"; + String SESSION_FACTORY_JNDI_NAME = "hibernate.session_factory_jndi_name"; /** * Does the value defined by {@link #SESSION_FACTORY_NAME} represent a JNDI namespace @@ -83,6 +95,10 @@ public interface PersistenceSettings { * * @see #SESSION_FACTORY_NAME * @see org.hibernate.boot.SessionFactoryBuilder#applyNameAsJndiName(boolean) + * + * @settingDefault {@code true} if {@link SessionFactory#getName()} comes from + * {@value #SESSION_FACTORY_NAME}; {@code false} if there is no {@link SessionFactory#getName()} + * or if it comes from {@value #PERSISTENCE_UNIT_NAME} */ String SESSION_FACTORY_NAME_IS_JNDI = "hibernate.session_factory_name_is_jndi"; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java index e81a326d5a..3721d004e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java @@ -340,6 +340,11 @@ public class SessionFactoryDelegatingImpl implements SessionFactoryImplementor, return delegate.getName(); } + @Override + public String getJndiName() { + return delegate.getJndiName(); + } + @Override public TypeConfiguration getTypeConfiguration() { return delegate.getTypeConfiguration(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index f4713dca41..343d9238fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -60,7 +60,6 @@ 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.config.spi.StandardConverters; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.profile.FetchProfile; @@ -144,6 +143,8 @@ import static org.hibernate.cfg.AvailableSettings.CREATE_EMPTY_COMPOSITES_ENABLE import static org.hibernate.cfg.AvailableSettings.CURRENT_SESSION_CONTEXT_CLASS; import static org.hibernate.cfg.AvailableSettings.JAKARTA_VALIDATION_FACTORY; import static org.hibernate.cfg.AvailableSettings.JPA_VALIDATION_FACTORY; +import static org.hibernate.cfg.PersistenceSettings.PERSISTENCE_UNIT_NAME; +import static org.hibernate.cfg.PersistenceSettings.SESSION_FACTORY_JNDI_NAME; import static org.hibernate.engine.config.spi.StandardConverters.STRING; import static org.hibernate.internal.FetchProfileHelper.getFetchProfiles; import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; @@ -176,6 +177,7 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SessionFactoryImpl.class ); private final String name; + private final String jndiName; private final String uuid; private transient volatile Status status = Status.OPEN; @@ -238,6 +240,7 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im bootMetamodel.initSessionFactory( this ); name = getSessionFactoryName( options, serviceRegistry ); + jndiName = determineJndiName( name, options, serviceRegistry ); uuid = options.getUuid(); jdbcServices = serviceRegistry.requireService( JdbcServices.class ); @@ -346,7 +349,7 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im LOG.debug( "Instantiated SessionFactory" ); } - private void deprecationCheck(Map settings) { + private static void deprecationCheck(Map settings) { for ( String s:settings.keySet() ) { switch (s) { case "hibernate.hql.bulk_id_strategy.global_temporary.create_tables": @@ -575,6 +578,23 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im return null; } + private String determineJndiName( + String name, + SessionFactoryOptions options, + SessionFactoryServiceRegistry serviceRegistry) { + final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); + assert cfgService != null; + final String explicitJndiName = cfgService.getSetting( SESSION_FACTORY_JNDI_NAME, STRING ); + if ( StringHelper.isNotEmpty( explicitJndiName ) ) { + return explicitJndiName; + } + + final String puName = cfgService.getSetting( PERSISTENCE_UNIT_NAME, STRING ); + // do not use name for JNDI if explicitly asked not to or if name comes from JPA persistence-unit name + final boolean nameIsNotJndiName = options.isSessionFactoryNameAlsoJndiName() == Boolean.FALSE || StringHelper.isNotEmpty( puName ); + return !nameIsNotJndiName ? name : null; + } + private SessionBuilderImpl createDefaultSessionOpenOptionsIfPossible() { final CurrentTenantIdentifierResolver currentTenantIdentifierResolver = getCurrentTenantIdentifierResolver(); if ( currentTenantIdentifierResolver == null ) { @@ -725,6 +745,11 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im return name; } + @Override + public String getJndiName() { + return jndiName; + } + @Override public TypeConfiguration getTypeConfiguration() { return runtimeMetamodels.getMappingMetamodel().getTypeConfiguration(); @@ -1766,7 +1791,7 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im return (SessionFactoryImpl) locateSessionFactoryOnDeserialization( uuid, name ); } - private void maskOutSensitiveInformation(Map props) { + private static void maskOutSensitiveInformation(Map props) { maskOutIfSet( props, AvailableSettings.JPA_JDBC_USER ); maskOutIfSet( props, AvailableSettings.JPA_JDBC_PASSWORD ); maskOutIfSet( props, AvailableSettings.JAKARTA_JDBC_USER ); @@ -1775,13 +1800,13 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im maskOutIfSet( props, AvailableSettings.PASS ); } - private void maskOutIfSet(Map props, String setting) { + private static void maskOutIfSet(Map props, String setting) { if ( props.containsKey( setting ) ) { props.put( setting, "****" ); } } - private void logIfEmptyCompositesEnabled(Map props ) { + private static void logIfEmptyCompositesEnabled(Map props ) { final boolean isEmptyCompositesEnabled = getBoolean( CREATE_EMPTY_COMPOSITES_ENABLED, props ); if ( isEmptyCompositesEnabled ) { LOG.emptyCompositesEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryRegistry.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryRegistry.java index 051ee7e146..972f493d69 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryRegistry.java @@ -57,14 +57,14 @@ public class SessionFactoryRegistry { * * @param uuid The uuid under which to register the SessionFactory * @param name The optional name under which to register the SessionFactory - * @param isNameAlsoJndiName Is name, if provided, also a JNDI name? + * @param jndiName An optional name to use for binding the SessionFactory into JNDI * @param instance The SessionFactory instance * @param jndiService The JNDI service, so we can register a listener if name is a JNDI name */ public void addSessionFactory( String uuid, String name, - boolean isNameAlsoJndiName, + String jndiName, SessionFactoryImplementor instance, JndiService jndiService) { if ( uuid == null ) { @@ -77,25 +77,28 @@ public class SessionFactoryRegistry { nameUuidXref.put( name, uuid ); } - if ( name == null || !isNameAlsoJndiName ) { + if ( jndiName == null ) { LOG.debug( "Not binding SessionFactory to JNDI, no JNDI name configured" ); return; } - LOG.debugf( "Attempting to bind SessionFactory [%s] to JNDI", name ); + bindToJndi( jndiName, instance, jndiService ); + } + private void bindToJndi(String jndiName, SessionFactoryImplementor instance, JndiService jndiService) { try { - jndiService.bind( name, instance ); - LOG.factoryBoundToJndiName( name ); + LOG.debugf( "Attempting to bind SessionFactory [%s] to JNDI", jndiName ); + jndiService.bind( jndiName, instance ); + LOG.factoryBoundToJndiName( jndiName ); try { - jndiService.addListener( name, listener ); + jndiService.addListener( jndiName, listener ); } catch (Exception e) { LOG.couldNotBindJndiListener(); } } catch (JndiNameException e) { - LOG.invalidJndiName( name, e ); + LOG.invalidJndiName( jndiName, e ); } catch (JndiException e) { LOG.unableToBindFactoryToJndi( e ); @@ -107,29 +110,29 @@ public class SessionFactoryRegistry { * * @param uuid The uuid * @param name The optional name - * @param isNameAlsoJndiName Is name, if provided, also a JNDI name? + * @param jndiName An optional name to use for binding the SessionFactory nto JNDI * @param jndiService The JNDI service */ public void removeSessionFactory( String uuid, String name, - boolean isNameAlsoJndiName, + String jndiName, JndiService jndiService) { if ( name != null ) { nameUuidXref.remove( name ); + } - if ( isNameAlsoJndiName ) { - try { - LOG.tracef( "Unbinding SessionFactory from JNDI : %s", name ); - jndiService.unbind( name ); - LOG.factoryUnboundFromJndiName( name ); - } - catch (JndiNameException e) { - LOG.invalidJndiName( name, e ); - } - catch (JndiException e) { - LOG.unableToUnbindFactoryFromJndi( e ); - } + if ( jndiName != null ) { + try { + LOG.tracef( "Unbinding SessionFactory from JNDI : %s", jndiName ); + jndiService.unbind( jndiName ); + LOG.factoryUnboundFromJndiName( jndiName ); + } + catch (JndiNameException e) { + LOG.invalidJndiName( jndiName, e ); + } + catch (JndiException e) { + LOG.unableToUnbindFactoryFromJndi( e ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/SessionFactoryNamingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/SessionFactoryNamingTests.java new file mode 100644 index 0000000000..6a299eae78 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/SessionFactoryNamingTests.java @@ -0,0 +1,95 @@ +/* + * 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.orm.test.boot; + +import org.hibernate.boot.model.process.internal.ScanningCoordinator; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.PersistenceSettings; +import org.hibernate.internal.SessionFactoryRegistry; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.Logger; +import org.hibernate.testing.orm.junit.LoggingInspections; +import org.hibernate.testing.orm.junit.MessageKeyInspection; +import org.hibernate.testing.orm.junit.MessageKeyWatcher; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@MessageKeyInspection( + messageKey = "HHH000277", + logger = @Logger( loggerNameClass = SessionFactoryRegistry.class ) +) +public class SessionFactoryNamingTests { + @Test + @DomainModel + @ServiceRegistry( settings = { + @Setting( name = AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, value = "true" ), + @Setting( name = AvailableSettings.SESSION_FACTORY_JNDI_NAME, value = "jndi-named" ) + } ) + @SessionFactory() + void testExplicitJndiName(SessionFactoryScope scope, MessageKeyWatcher logWatcher) { + scope.getSessionFactory(); + assertThat( logWatcher.wasTriggered() ).isTrue(); + } + + + + + + @Test + @DomainModel + @ServiceRegistry( settings = @Setting( name = AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, value = "true" ) ) + @SessionFactory( sessionFactoryName = "named" ) + void testSessionFactoryName(SessionFactoryScope scope, MessageKeyWatcher logWatcher) { + scope.getSessionFactory(); + assertThat( logWatcher.wasTriggered() ).isTrue(); + } + + @Test + @DomainModel + @ServiceRegistry( settings = @Setting( name = AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, value = "false" ) ) + @SessionFactory( sessionFactoryName = "named" ) + void testNonJndiSessionFactoryName(SessionFactoryScope scope, MessageKeyWatcher logWatcher) { + scope.getSessionFactory(); + assertThat( logWatcher.wasTriggered() ).isFalse(); + } + + @Test + @DomainModel + @ServiceRegistry( settings = { + @Setting( name = AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, value = "true" ), + // mimics the persistence.xml persistence-unit name + @Setting( name = PersistenceSettings.PERSISTENCE_UNIT_NAME, value = "named-pu" ), + } ) + @SessionFactory + void testPuName(SessionFactoryScope scope, MessageKeyWatcher logWatcher) { + scope.getSessionFactory(); + assertThat( logWatcher.wasTriggered() ).isFalse(); + } + + @Test + @DomainModel + @ServiceRegistry( settings = { + @Setting( name = AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, value = "false" ), + // mimics the persistence.xml persistence-unit name + @Setting( name = PersistenceSettings.PERSISTENCE_UNIT_NAME, value = "named-pu" ), + } ) + @SessionFactory + void testNonJndiPuName(SessionFactoryScope scope, MessageKeyWatcher logWatcher) { + scope.getSessionFactory(); + assertThat( logWatcher.wasTriggered() ).isFalse(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/serialization/SessionFactorySerializationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/serialization/SessionFactorySerializationTest.java index e01ff143be..928003bec1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/serialization/SessionFactorySerializationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/serialization/SessionFactorySerializationTest.java @@ -45,12 +45,12 @@ public class SessionFactorySerializationTest extends BaseUnitTestCase { // different VM String uuid = ( (SessionFactoryImplementor) factory ).getUuid(); // deregister under this uuid... - SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, NAME, false, null ); + SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, NAME, null, null ); // and then register under a different uuid... SessionFactoryRegistry.INSTANCE.addSessionFactory( "some-other-uuid", NAME, - false, + null, (SessionFactoryImplementor) factory, null ); @@ -58,7 +58,7 @@ public class SessionFactorySerializationTest extends BaseUnitTestCase { SessionFactory factory2 = (SessionFactory) SerializationHelper.clone( factory ); assertSame( factory, factory2 ); - SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", NAME, false, null ); + SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", NAME, null, null ); } assertFalse( SessionFactoryRegistry.INSTANCE.hasRegistrations() ); @@ -77,12 +77,12 @@ public class SessionFactorySerializationTest extends BaseUnitTestCase { // different VM String uuid = ( (SessionFactoryImplementor) factory ).getUuid(); // deregister under this uuid... - SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, null, false, null ); + SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, null, null, null ); // and then register under a different uuid... SessionFactoryRegistry.INSTANCE.addSessionFactory( "some-other-uuid", null, - false, + null, (SessionFactoryImplementor) factory, null ); @@ -94,7 +94,7 @@ public class SessionFactorySerializationTest extends BaseUnitTestCase { catch (SerializationException expected) { } - SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", null, false, null ); + SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", null, null, null ); } assertFalse( SessionFactoryRegistry.INSTANCE.hasRegistrations() ); diff --git a/hibernate-core/src/test/resources/xml/boot/named-session-factory.xml b/hibernate-core/src/test/resources/xml/boot/named-session-factory.xml new file mode 100644 index 0000000000..873a5d5596 --- /dev/null +++ b/hibernate-core/src/test/resources/xml/boot/named-session-factory.xml @@ -0,0 +1,17 @@ + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + + diff --git a/migration-guide.adoc b/migration-guide.adoc index a9acaff418..2aabcd8643 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -137,6 +137,33 @@ String isDefault(); The default precision for Oracle timestamps was changed to 9 i.e. nanosecond precision. The default precision for SQL Server timestamps was changed to 7 i.e. 100 nanosecond precision. + +[[sf-name]] +== SessionFactory Name (and JNDI) + +Hibernate defines `SessionFactory#getName` (specified via `cfg.xml` or `hibernate.session_factory_name`) which is used to +help with (de)serializing a `SessionFactory`. It is also, unless `hibernate.session_factory_name_is_jndi` is set to `false`, +used in biding the `SessionFactory` into JNDI. + +This `SessionFactory#getName` method pre-dates Jakarta Persistence (and JPA). It now implements `EntityManagerFactory#getName` +inherited from Jakarta Persistence, which states that this name should come from the persistence-unit name. +To align with Jakarta Persistence (the 3.2 TCK tests this), Hibernate now considers the persistence-unit name if no +`hibernate.session_factory_name` is specified. + +However, because `hibernate.session_factory_name` is also a trigger to attempt to bind the SessionFactory into JNDI, +this change to consider persistence-unit name, means that each `SessionFactory` created through Jakarta Persistence now +have a name and Hibernate attempted to bind these to JNDI. + +To work around this we have introduced a new `hibernate.session_factory_jndi_name` setting that can be used to explicitly +specify a name for JNDI binding. The new behavior is as follows (assuming `hibernate.session_factory_name_is_jndi` is not explicitly configured): + +* If `hibernate.session_factory_jndi_name` is specified, the name is used to bind into JNDI +* If `hibernate.session_factory_name` is specified, the name is used to bind into JNDI + +Hibernate can use the persistence-unit name for binding into JNDI as well, but `hibernate.session_factory_name_is_jndi` +must be explicitly set to true. + + [[todo]] == Todos (dev)