diff --git a/hibernate-core/src/main/java/org/hibernate/SessionFactory.java b/hibernate-core/src/main/java/org/hibernate/SessionFactory.java index fe4992b65922..6503cbe39965 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 @@ * @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 7fc513c5d1cc..1af2449e7149 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/SessionFactoryBuilder.java @@ -82,7 +82,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 338ad64cd6c8..1169e1d9dcc9 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 @@ * @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 @@ public void sessionFactoryClosed(SessionFactory factory) { 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 807f1b1d2244..79f9d5a3450d 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 @@ -170,7 +170,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; @@ -916,7 +916,7 @@ public String getSessionFactoryName() { } @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 46e9611a9e48..0a07bf026e2f 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 String getSessionFactoryName() { } @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 d4947226629d..c6068236825f 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 @@ default boolean isAllowRefreshDetachedEntity() { } /** - * 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 @@ default boolean isAllowRefreshDetachedEntity() { * * @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 d93ffc5ab6c2..d19b8cf86d11 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,16 +62,27 @@ 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_NAME_IS_JNDI + * @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_JNDI_NAME = "hibernate.session_factory_jndi_name"; + /** * Does the value defined by {@link #SESSION_FACTORY_NAME} represent a JNDI namespace * into which the {@link org.hibernate.SessionFactory} should be bound and made accessible? @@ -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 e81a326d5a1c..3721d004e148 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 String getName() { 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 d38e5bd7d9ca..550c55827f2a 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.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; @@ -143,6 +142,8 @@ 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; @@ -175,6 +176,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; @@ -237,6 +239,7 @@ public SessionFactoryImpl( bootMetamodel.initSessionFactory( this ); name = getSessionFactoryName( options, serviceRegistry ); + jndiName = determineJndiName( name, options, serviceRegistry ); uuid = options.getUuid(); jdbcServices = serviceRegistry.requireService( JdbcServices.class ); @@ -345,7 +348,7 @@ public SessionFactoryImpl( 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": @@ -574,6 +577,23 @@ private static String getSessionFactoryName(SessionFactoryOptions options, Sessi 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 ) { @@ -724,6 +744,11 @@ public String getName() { return name; } + @Override + public String getJndiName() { + return jndiName; + } + @Override public TypeConfiguration getTypeConfiguration() { return runtimeMetamodels.getMappingMetamodel().getTypeConfiguration(); @@ -1765,7 +1790,7 @@ static SessionFactoryImpl deserialize(ObjectInputStream ois) throws IOException 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 ); @@ -1774,13 +1799,13 @@ private void maskOutSensitiveInformation(Map props) { 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 051ee7e146ae..972f493d693c 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 @@ private 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 void addSessionFactory( 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 void addSessionFactory( * * @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 000000000000..6a299eae78c2 --- /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 e01ff143bea2..928003bec194 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 void testNamedSessionFactorySerialization() throws Exception { // 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 void testNamedSessionFactorySerialization() throws Exception { 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 void testUnNamedSessionFactorySerialization() throws Exception { // 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 void testUnNamedSessionFactorySerialization() throws Exception { 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 000000000000..873a5d5596a0 --- /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 a9acaff41881..2aabcd864375 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)