mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 08:24:13 +00:00
Add missing proxy hints for Hibernate 8's MutationOrSelectionQuery
Prior to this commit, Hibernate 8 types extending `MutationOrSelectionQuery` would fail proxying at runtime in native images because reflection hints were not registered at build time. While the `MutationOrSelectionQueryImpl` case can be solved with an additional proxy hint, `NativeMutationOrSelectionQueryImpl` is impossible to solve that way due to multi interface mismatch. This was found in gh-36878 and handled with a fallback proxy. In this case, native image will throw a `MissingReflectionRegistrationError` - but obviously we cannot depend on this type in JVM applications. `MissingReflectionRegistrationError` extends `LinkageError`, which we will use along IllegalArgumentException` to detect that the proxying operation failed and that we should use the fallback. This commit also register a proxy hint for the said fallback. Fixes gh-37251
This commit is contained in:
@@ -18,6 +18,7 @@ package org.springframework.orm.jpa;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import jakarta.persistence.Query;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.ExecutableMode;
|
||||
@@ -53,6 +54,10 @@ class EntityManagerRuntimeHints implements RuntimeHintsRegistrar {
|
||||
// As of Hibernate 8.0
|
||||
private static final String MUTATION_QUERY_IMPL_CLASS_NAME = "org.hibernate.query.internal.MutationQueryImpl";
|
||||
|
||||
// As of Hibernate 8.0
|
||||
private static final String MUTATION_OR_SELECTION_QUERY_IMPL_CLASS_NAME =
|
||||
"org.hibernate.query.internal.MutationOrSelectionQueryImpl";
|
||||
|
||||
private static final String NATIVE_QUERY_IMPL_CLASS_NAME = "org.hibernate.query.sql.internal.NativeQueryImpl";
|
||||
|
||||
private static final String STATELESS_SESSION_CLASS_NAME = "org.hibernate.StatelessSession";
|
||||
@@ -75,11 +80,15 @@ class EntityManagerRuntimeHints implements RuntimeHintsRegistrar {
|
||||
builder.onReachableType(SharedEntityManagerCreator.class).withMethod("getMetamodel",
|
||||
Collections.emptyList(), ExecutableMode.INVOKE);
|
||||
});
|
||||
// Fallback proxy for Hibernate 8.0 query implementation types like NativeMutationOrSelectionQueryImpl,
|
||||
// matching the single-interface fallback in SharedEntityManagerCreator. See gh-36878
|
||||
hints.proxies().registerJdkProxy(TypeReference.of(Query.class));
|
||||
}
|
||||
registerJdkProxyFor(hints, classLoader, QUERY_SQM_IMPL_CLASS_NAME);
|
||||
registerJdkProxyFor(hints, classLoader, SQM_QUERY_IMPL_CLASS_NAME);
|
||||
registerJdkProxyFor(hints, classLoader, SELECTION_QUERY_IMPL_CLASS_NAME);
|
||||
registerJdkProxyFor(hints, classLoader, MUTATION_QUERY_IMPL_CLASS_NAME);
|
||||
registerJdkProxyFor(hints, classLoader, MUTATION_OR_SELECTION_QUERY_IMPL_CLASS_NAME);
|
||||
registerJdkProxyFor(hints, classLoader, NATIVE_QUERY_IMPL_CLASS_NAME);
|
||||
registerJdkProxyFor(hints, classLoader, STATELESS_SESSION_CLASS_NAME);
|
||||
if (ClassUtils.isPresent(PERSISTENCE_UNIT_INFO_DESCRIPTOR_CLASS_NAME, classLoader)) {
|
||||
|
||||
+2
-1
@@ -245,8 +245,9 @@ public abstract class SharedEntityManagerCreator {
|
||||
try {
|
||||
result = Proxy.newProxyInstance(this.proxyClassLoader, ifcs, ih);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
catch (IllegalArgumentException | LinkageError ex) {
|
||||
// Hibernate 8.0 NativeMutationOrSelectionQueryImpl multi-interface mismatch?
|
||||
// IllegalArgumentException on the JVM, LinkageError in native image
|
||||
// Fall back to single declared interface from method signature.
|
||||
Class<?>[] singleIfc = new Class<?>[] {method.getReturnType()};
|
||||
cachedQueryInterfaces.put(query.getClass(), singleIfc);
|
||||
|
||||
+6
@@ -17,6 +17,7 @@
|
||||
package org.springframework.orm.jpa;
|
||||
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import jakarta.persistence.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.StatelessSession;
|
||||
@@ -60,6 +61,11 @@ class EntityManagerRuntimeHintsTests {
|
||||
assertThat(RuntimeHintsPredicates.proxies().forInterfaces(StatelessSession.class)).accepts(this.hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void entityManagerFactoryHasFallbackQueryProxyHints() {
|
||||
assertThat(RuntimeHintsPredicates.proxies().forInterfaces(Query.class)).accepts(this.hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void entityManagerFactoryHasReflectionHints() {
|
||||
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(EntityManagerFactory.class, "getCriteriaBuilder")).accepts(this.hints);
|
||||
|
||||
Reference in New Issue
Block a user