diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java index b30f468e52c..3bd7b74a43f 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java @@ -1075,25 +1075,25 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe * if not recovered yet, and at debug level if already recovered. * Can be overridden in subclasses. * @param ex the exception to handle - * @param alreadyRecovered whether a previously executing listener - * already recovered from the present listener setup failure - * (this usually indicates a follow-up failure than can be ignored - * other than for debug log purposes) + * @param alreadyHandled whether a previously executing listener already + * recovered from the present listener setup failure or the problem has + * been handled otherwise already (this usually indicates a follow-up + * failure than can be ignored other than for debug log purposes) * @see #recoverAfterListenerSetupFailure() */ - protected void handleListenerSetupFailure(Throwable ex, boolean alreadyRecovered) { + protected void handleListenerSetupFailure(Throwable ex, boolean alreadyHandled) { if (ex instanceof JMSException jmsException) { invokeExceptionListener(jmsException); } if (ex instanceof SharedConnectionNotInitializedException) { - if (!alreadyRecovered) { + if (!alreadyHandled) { logger.debug("JMS message listener invoker needs to establish shared Connection"); } } else { // Recovery during active operation... - if (alreadyRecovered) { - logger.debug("Setup of JMS message listener invoker failed - already recovered by other invoker", ex); + if (alreadyHandled) { + logger.debug("Setup of JMS message listener invoker failed", ex); } else { StringBuilder msg = new StringBuilder(); @@ -1317,6 +1317,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe lifecycleLock.unlock(); } boolean messageReceived = false; + boolean exhausted = false; try { // For core consumers without maxMessagesPerTask, no idle limit applies since they // will always get rescheduled immediately anyway. Whereas for surplus consumers @@ -1340,31 +1341,45 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe } catch (Throwable ex) { clearResources(); + boolean alreadyHandled = false; if (this.invokerBackOff != null) { // We failed more than once in a row, probably due to a specific failure // from the JMS receive call even after a successful connection recovery: // locally wait before a further recovery attempt to avoid a burst retry. - applyBackOffTime(this.invokerBackOff); + alreadyHandled = true; + if (logger.isWarnEnabled()) { + logger.warn("Recurring setup failure in " + id() + " - retrying using " + + this.invokerBackOff + ". Cause: " + (ex instanceof JMSException jmsException ? + JmsUtils.buildExceptionMessage(jmsException) : ex.getMessage())); + } + exhausted = !applyBackOffTime(this.invokerBackOff); + if (exhausted) { + // Too many recurring setup failures at the invoker level. + if (logger.isWarnEnabled()) { + logger.warn("Exhausted back-off in " + id() + " after recurring setup failure: " + + this.invokerBackOff); + } + } } else { this.invokerBackOff = DefaultMessageListenerContainer.this.backOff.start(); } - boolean alreadyRecovered = false; - recoveryLock.lock(); - try { - if (this.lastRecoveryMarker == currentRecoveryMarker) { - handleListenerSetupFailure(ex, false); - recoverAfterListenerSetupFailure(); - currentRecoveryMarker = new Object(); + boolean recovered = false; + if (!exhausted) { + recoveryLock.lock(); + try { + if (this.lastRecoveryMarker == DefaultMessageListenerContainer.this.currentRecoveryMarker) { + handleListenerSetupFailure(ex, alreadyHandled); + recoverAfterListenerSetupFailure(); + DefaultMessageListenerContainer.this.currentRecoveryMarker = new Object(); + recovered = true; + } } - else { - alreadyRecovered = true; + finally { + recoveryLock.unlock(); } } - finally { - recoveryLock.unlock(); - } - if (alreadyRecovered) { + if (!recovered) { handleListenerSetupFailure(ex, true); } } @@ -1385,7 +1400,8 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe } lifecycleLock.lock(); try { - if (!shouldRescheduleInvoker(this.idleTaskExecutionCount) || !rescheduleTaskIfNecessary(this)) { + if (exhausted || !shouldRescheduleInvoker(this.idleTaskExecutionCount) || + !rescheduleTaskIfNecessary(this)) { // We're shutting down completely. scheduledInvokers.remove(this); if (logger.isDebugEnabled()) { @@ -1394,16 +1410,15 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe lifecycleCondition.signalAll(); clearResources(); } - else if (isRunning()) { + if (isRunning()) { int nonPausedConsumers = getScheduledConsumerCount() - getPausedTaskCount(); if (nonPausedConsumers < 1) { - logger.error("All scheduled consumers have been paused, probably due to tasks having been rejected. " + - "Check your thread pool configuration! Manual recovery necessary through a start() call."); + logger.error("All scheduled consumers have been paused due to tasks having been exhausted/rejected. " + + "Check your back-off and executor setup! Manual recovery necessary through a start() call."); } else if (nonPausedConsumers < getConcurrentConsumers()) { - logger.warn("Number of scheduled consumers has dropped below concurrentConsumers limit, probably " + - "due to tasks having been rejected. Check your thread pool configuration! Automatic recovery " + - "to be triggered by remaining consumers."); + logger.warn("Number of scheduled consumers has dropped below concurrentConsumers limit due to tasks " + + "having been exhausted/rejected. Automatic recovery to be triggered by remaining consumers."); } } } @@ -1461,7 +1476,10 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe try { initResourcesIfNecessary(); boolean messageReceived = receiveAndExecute(this, this.session, this.consumer); - this.invokerBackOff = null; // successful receive attempt without exception + if (this.invokerBackOff != null) { + logger.debug("Successful receive attempt after JMS message listener invoker recovery"); + this.invokerBackOff = null; + } return messageReceived; } finally { @@ -1552,6 +1570,10 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe this.session = null; } + private String id() { + return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()); + } + @Override public boolean isLongLived() { return (maxMessagesPerTask < 0); diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java index 289374b6043..60452110de5 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/AbstractEntityManagerFactoryBean.java @@ -513,6 +513,7 @@ public abstract class AbstractEntityManagerFactoryBean implements * Delegate an incoming invocation from the proxy, dispatching to EntityManagerFactoryInfo * or the native EntityManagerFactory accordingly. */ + @SuppressWarnings("NullAway") // for query.unwrap(null) Object invokeProxyMethod(Method method, Object @Nullable [] args) throws Throwable { if (method.getDeclaringClass().isAssignableFrom(EntityManagerFactoryInfo.class)) { return method.invoke(this, args); @@ -521,9 +522,8 @@ public abstract class AbstractEntityManagerFactoryBean implements args[0] == SynchronizationType.SYNCHRONIZED) { // JPA 2.1's createEntityManager(SynchronizationType, Map) // Redirect to plain createEntityManager and add synchronization semantics through Spring proxy - EntityManager rawEntityManager = (args.length > 1 ? - getNativeEntityManagerFactory().createEntityManager((Map) args[1]) : - getNativeEntityManagerFactory().createEntityManager()); + EntityManager rawEntityManager = EntityManagerFactoryUtils.createEntityManager( + getNativeEntityManagerFactory(), (args.length > 1 ? (Map) args[1] : null)); postProcessEntityManager(rawEntityManager); return ExtendedEntityManagerCreator.createApplicationManagedEntityManager(rawEntityManager, this, true); } @@ -536,6 +536,7 @@ public abstract class AbstractEntityManagerFactoryBean implements // Assumably a Spring-generated proxy from SharedEntityManagerCreator: // since we're passing it back to the native EntityManagerFactory, // let's unwrap it to the original Query object from the provider. + // Note that null is not an officially supported argument in JPA. try { args[i] = query.unwrap(null); } @@ -609,9 +610,8 @@ public abstract class AbstractEntityManagerFactoryBean implements @Override public EntityManager createNativeEntityManager(@Nullable Map properties) { - EntityManager rawEntityManager = (!CollectionUtils.isEmpty(properties) ? - getNativeEntityManagerFactory().createEntityManager(properties) : - getNativeEntityManagerFactory().createEntityManager()); + EntityManager rawEntityManager = EntityManagerFactoryUtils.createEntityManager( + getNativeEntityManagerFactory(), properties); postProcessEntityManager(rawEntityManager); return rawEntityManager; } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryAccessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryAccessor.java index 81c3c4972ae..c10bcd3db7e 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryAccessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryAccessor.java @@ -162,7 +162,7 @@ public abstract class EntityManagerFactoryAccessor implements BeanFactoryAware { protected EntityManager createEntityManager() throws IllegalStateException { EntityManagerFactory emf = obtainEntityManagerFactory(); Map properties = getJpaPropertyMap(); - return (!CollectionUtils.isEmpty(properties) ? emf.createEntityManager(properties) : emf.createEntityManager()); + return EntityManagerFactoryUtils.createEntityManager(emf, properties); } /** diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java index 20d2bef2d0a..6b382a88aa4 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java @@ -79,10 +79,10 @@ public abstract class EntityManagerFactoryUtils { public static final int ENTITY_MANAGER_SYNCHRONIZATION_ORDER = DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100; - private static final @Nullable Method CREATE_ENTITY_AGENT_METHOD = - ClassUtils.getMethodIfAvailable(EntityManagerFactory.class, "createEntityAgent"); + private static final boolean CREATE_ENTITY_MANAGER_WITHOUT_ARGUMENTS_AVAILABLE = + ClassUtils.hasMethod(EntityManagerFactory.class, "createEntityManager"); - private static final @Nullable Method CREATE_ENTITY_AGENT_WITH_PROPERTIES_METHOD = + private static final @Nullable Method CREATE_ENTITY_AGENT_METHOD = ClassUtils.getMethodIfAvailable(EntityManagerFactory.class, "createEntityAgent", Map.class); private static final Log logger = LogFactory.getLog(EntityManagerFactoryUtils.class); @@ -268,7 +268,7 @@ public abstract class EntityManagerFactoryUtils { } } if (em == null) { - em = (!CollectionUtils.isEmpty(properties) ? emf.createEntityManager(properties) : emf.createEntityManager()); + em = createEntityManager(emf, properties); } try { @@ -358,6 +358,23 @@ public abstract class EntityManagerFactoryUtils { return entityAgent; } + /** + * Create a new JPA EntityManager via reflectively detected JPA 3.2/4.0 API. + * @param emf the EntityManagerFactory to create the EntityManager with + * @param properties the properties to be passed into the {@code createEntityManager} + * call (may be {@code null}) + * @since 7.0.8 + */ + public static EntityManager createEntityManager(EntityManagerFactory emf, @Nullable Map properties) { + if (CollectionUtils.isEmpty(properties)) { + properties = null; + } + if (properties == null && CREATE_ENTITY_MANAGER_WITHOUT_ARGUMENTS_AVAILABLE) { + return emf.createEntityManager(); // on JPA 3.2 + } + return emf.createEntityManager(properties); // on JPA 4.0 even for empty properties + } + /** * Create a new JPA EntityAgent via reflectively detected JPA 4.0 API. * @param emf the EntityManagerFactory to create the EntityAgent with @@ -366,12 +383,13 @@ public abstract class EntityManagerFactoryUtils { * @since 7.0.4 */ static Object createEntityAgent(EntityManagerFactory emf, @Nullable Map properties) { - if (CREATE_ENTITY_AGENT_METHOD == null || CREATE_ENTITY_AGENT_WITH_PROPERTIES_METHOD == null) { + if (CREATE_ENTITY_AGENT_METHOD == null) { throw new IllegalStateException("JPA 4.0 createEntityAgent API not available"); } - Object entityAgent = (!CollectionUtils.isEmpty(properties) ? - ReflectionUtils.invokeMethod(CREATE_ENTITY_AGENT_WITH_PROPERTIES_METHOD, emf, properties) : - ReflectionUtils.invokeMethod(CREATE_ENTITY_AGENT_METHOD, emf)); + if (CollectionUtils.isEmpty(properties)) { + properties = null; + } + Object entityAgent = ReflectionUtils.invokeMethod(CREATE_ENTITY_AGENT_METHOD, emf, properties); if (entityAgent == null) { throw new IllegalStateException("JPA 4.0 createEntityAgent API returned null"); } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerRuntimeHints.java b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerRuntimeHints.java index b7517b38ad0..5ab9fee6ad6 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerRuntimeHints.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/EntityManagerRuntimeHints.java @@ -31,6 +31,7 @@ import org.springframework.util.ClassUtils; * {@link AbstractEntityManagerFactoryBean} and {@link SharedEntityManagerCreator} are registered. * * @author Sebastien Deleuze + * @author Juergen Hoeller * @since 6.0 */ class EntityManagerRuntimeHints implements RuntimeHintsRegistrar { @@ -45,6 +46,12 @@ class EntityManagerRuntimeHints implements RuntimeHintsRegistrar { // As of Hibernate 7.1 private static final String SQM_QUERY_IMPL_CLASS_NAME = "org.hibernate.query.sqm.internal.SqmQueryImpl"; + // As of Hibernate 8.0 + private static final String SELECTION_QUERY_IMPL_CLASS_NAME = "org.hibernate.query.internal.SelectionQueryImpl"; + + // As of Hibernate 8.0 + private static final String MUTATION_QUERY_IMPL_CLASS_NAME = "org.hibernate.query.internal.MutationQueryImpl"; + private static final String NATIVE_QUERY_IMPL_CLASS_NAME = "org.hibernate.query.sql.internal.NativeQueryImpl"; @@ -76,6 +83,18 @@ class EntityManagerRuntimeHints implements RuntimeHintsRegistrar { } catch (ClassNotFoundException ignored) { } + try { + Class clazz = ClassUtils.forName(SELECTION_QUERY_IMPL_CLASS_NAME, classLoader); + hints.proxies().registerJdkProxy(ClassUtils.getAllInterfacesForClass(clazz, classLoader)); + } + catch (ClassNotFoundException ignored) { + } + try { + Class clazz = ClassUtils.forName(MUTATION_QUERY_IMPL_CLASS_NAME, classLoader); + hints.proxies().registerJdkProxy(ClassUtils.getAllInterfacesForClass(clazz, classLoader)); + } + catch (ClassNotFoundException ignored) { + } try { Class clazz = ClassUtils.forName(NATIVE_QUERY_IMPL_CLASS_NAME, classLoader); hints.proxies().registerJdkProxy(ClassUtils.getAllInterfacesForClass(clazz, classLoader)); diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java index 72f377b41fb..ecf0f022adc 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/ExtendedEntityManagerCreator.java @@ -42,7 +42,6 @@ import org.springframework.transaction.support.ResourceHolderSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import org.springframework.util.CollectionUtils; import org.springframework.util.ConcurrentReferenceHashMap; /** @@ -174,8 +173,7 @@ public abstract class ExtendedEntityManagerCreator { return createProxy(rawEntityManager, emfInfo, true, synchronizedWithTransaction); } else { - EntityManager rawEntityManager = (!CollectionUtils.isEmpty(properties) ? - emf.createEntityManager(properties) : emf.createEntityManager()); + EntityManager rawEntityManager = EntityManagerFactoryUtils.createEntityManager(emf, properties); return createProxy(rawEntityManager, null, null, null, null, true, synchronizedWithTransaction); } } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java index 676a66929ed..d629cc0245b 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java @@ -475,8 +475,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager em = emfInfo.createNativeEntityManager(properties); } else { - em = (!CollectionUtils.isEmpty(properties) ? - emf.createEntityManager(properties) : emf.createEntityManager()); + em = EntityManagerFactoryUtils.createEntityManager(emf, properties); } if (this.entityManagerInitializer != null) { this.entityManagerInitializer.accept(em); diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java b/spring-orm/src/main/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java index 087cad8f122..a392b3ddb2e 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/LocalEntityManagerFactoryBean.java @@ -143,9 +143,7 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB */ public PersistenceConfiguration getPersistenceConfiguration() { if (this.configuration == null) { - String name = getPersistenceUnitName(); - Assert.state(name != null, "No persistenceUnitName set"); - this.configuration = new PersistenceConfiguration(name); + this.configuration = new PersistenceConfiguration(obtainPersistenceUnitName()); } return this.configuration; } @@ -167,6 +165,12 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB super.setPersistenceUnitName(persistenceUnitName); } + private String obtainPersistenceUnitName() { + String name = getPersistenceUnitName(); + Assert.state(name != null, "No persistenceUnitName set"); + return name; + } + /** * Set whether to use Spring-based scanning for entity classes in the classpath * instead of using JPA's standard scanning of jar files with {@code persistence.xml} @@ -265,7 +269,7 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB // Create EntityManagerFactory directly through PersistenceProvider. EntityManagerFactory emf = (this.configuration != null ? provider.createEntityManagerFactory(this.configuration) : - provider.createEntityManagerFactory(getPersistenceUnitName(), getJpaPropertyMap())); + provider.createEntityManagerFactory(obtainPersistenceUnitName(), getJpaPropertyMap())); if (emf == null) { throw new PersistenceException( "PersistenceProvider [" + provider + "] could not find persistence unit for name '" + @@ -277,7 +281,7 @@ public class LocalEntityManagerFactoryBean extends AbstractEntityManagerFactoryB // Let JPA perform its standard PersistenceProvider autodetection. return (this.configuration != null ? Persistence.createEntityManagerFactory(this.configuration) : - Persistence.createEntityManagerFactory(getPersistenceUnitName(), getJpaPropertyMap())); + Persistence.createEntityManagerFactory(obtainPersistenceUnitName(), getJpaPropertyMap())); } } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java b/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java index 6166ca0fd5c..82f1fef899d 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java @@ -40,7 +40,6 @@ import org.jspecify.annotations.Nullable; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import org.springframework.util.CollectionUtils; import org.springframework.util.ConcurrentReferenceHashMap; /** @@ -396,9 +395,7 @@ public abstract class SharedEntityManagerCreator { boolean newTarget = false; if (target == null) { logger.debug("Creating new EntityManager for shared EntityManager invocation"); - target = (!CollectionUtils.isEmpty(this.properties) ? - this.targetFactory.createEntityManager(this.properties) : - this.targetFactory.createEntityManager()); + target = EntityManagerFactoryUtils.createEntityManager(this.targetFactory, this.properties); newTarget = true; } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScanner.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScanner.java index 9d663f7390f..96b2e0c7cc5 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScanner.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesScanner.java @@ -146,7 +146,11 @@ public final class PersistenceManagedTypesScanner { try { MetadataReader reader = factory.getMetadataReader(resource); String className = reader.getClassMetadata().getClassName(); - if (matchesEntityTypeFilter(reader, factory) && this.managedClassNameFilter.matches(className)) { + if (className.endsWith(ClassUtils.PACKAGE_INFO_SUFFIX)) { + scanResult.managedPackages.add(className.substring(0, + className.length() - ClassUtils.PACKAGE_INFO_SUFFIX.length())); + } + else if (matchesEntityTypeFilter(reader, factory) && this.managedClassNameFilter.matches(className)) { scanResult.managedClassNames.add(className); if (scanResult.persistenceUnitRootUrl == null) { URL url = resource.getURL(); @@ -155,10 +159,6 @@ public final class PersistenceManagedTypesScanner { } } } - if (className.endsWith(ClassUtils.PACKAGE_INFO_SUFFIX)) { - scanResult.managedPackages.add(className.substring(0, - className.length() - ClassUtils.PACKAGE_INFO_SUFFIX.length())); - } } catch (FileNotFoundException ex) { // Ignore non-readable resource diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java b/spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java index f6d0ebcbff2..426c6289419 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.java @@ -240,7 +240,7 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter { * @see jakarta.persistence.EntityManagerFactory#createEntityManager() */ protected EntityManager createEntityManager(EntityManagerFactory emf) { - return emf.createEntityManager(); + return EntityManagerFactoryUtils.createEntityManager(emf, null); } private boolean applyEntityManagerBindingInterceptor(WebAsyncManager asyncManager, String key) { diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/EntityManagerRuntimeHintsTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/EntityManagerRuntimeHintsTests.java index 1ecb134a82c..917722e8d01 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/EntityManagerRuntimeHintsTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/EntityManagerRuntimeHintsTests.java @@ -19,11 +19,6 @@ package org.springframework.orm.jpa; import jakarta.persistence.EntityManagerFactory; import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.hibernate.query.CommonQueryContract; -import org.hibernate.query.SelectionQuery; -import org.hibernate.query.hql.spi.SqmQueryImplementor; -import org.hibernate.query.spi.DomainQueryExecutionContext; -import org.hibernate.query.sqm.spi.InterpretationsKeySource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -47,8 +42,7 @@ class EntityManagerRuntimeHintsTests { @BeforeEach void setup() { AotServices.factories().load(RuntimeHintsRegistrar.class) - .forEach(registrar -> registrar.registerHints(this.hints, - ClassUtils.getDefaultClassLoader())); + .forEach(registrar -> registrar.registerHints(this.hints, ClassUtils.getDefaultClassLoader())); } @Test @@ -69,13 +63,4 @@ class EntityManagerRuntimeHintsTests { assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(EntityManagerFactory.class, "getMetamodel")).accepts(this.hints); } - @Test - void sqmQueryHints() { - assertThat(RuntimeHintsPredicates.proxies().forInterfaces( - SqmQueryImplementor.class, - InterpretationsKeySource.class, - DomainQueryExecutionContext.class, - SelectionQuery.class, - CommonQueryContract.class)).accepts(this.hints); - } } diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewTests.java index f60ba2e6838..beb23049d24 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/support/OpenEntityManagerInViewTests.java @@ -76,19 +76,20 @@ class OpenEntityManagerInViewTests { @BeforeEach - void setUp() { + void setup() { given(factory.createEntityManager()).willReturn(manager); this.request.setAsyncSupported(true); } @AfterEach - void tearDown() { + void cleanup() { assertThat(TransactionSynchronizationManager.getResourceMap()).isEmpty(); assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isFalse(); assertThat(TransactionSynchronizationManager.isCurrentTransactionReadOnly()).isFalse(); assertThat(TransactionSynchronizationManager.isActualTransactionActive()).isFalse(); } + @Test void openEntityManagerInViewInterceptor() { OpenEntityManagerInViewInterceptor interceptor = new OpenEntityManagerInViewInterceptor(); diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/support/PersistenceContextTransactionTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/support/PersistenceContextTransactionTests.java index fb0a572287c..617280c5109 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/support/PersistenceContextTransactionTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/support/PersistenceContextTransactionTests.java @@ -74,7 +74,7 @@ class PersistenceContextTransactionTests { } @AfterEach - void clear() { + void cleanup() { assertThat(TransactionSynchronizationManager.getResourceMap()).isEmpty(); assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isFalse(); assertThat(TransactionSynchronizationManager.isCurrentTransactionReadOnly()).isFalse();