Add missing Hibernate reflection hints

This commit adds the missing reflection hints for Hibernate 8 support:
`PersistenceUnitInfoDescriptor` and `StatelessSession`.

Fixes gh-37247
Fixes gh-37249
This commit is contained in:
Brian Clozel
2026-09-07 09:34:38 +02:00
parent 6e260bc78e
commit 486db005a1
2 changed files with 28 additions and 25 deletions
@@ -21,6 +21,7 @@ import java.util.Collections;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
@@ -54,6 +55,10 @@ class EntityManagerRuntimeHints implements RuntimeHintsRegistrar {
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";
private static final String PERSISTENCE_UNIT_INFO_DESCRIPTOR_CLASS_NAME =
"org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor";
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
@@ -71,32 +76,21 @@ class EntityManagerRuntimeHints implements RuntimeHintsRegistrar {
Collections.emptyList(), ExecutableMode.INVOKE);
});
}
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, NATIVE_QUERY_IMPL_CLASS_NAME);
registerJdkProxyFor(hints, classLoader, STATELESS_SESSION_CLASS_NAME);
if (ClassUtils.isPresent(PERSISTENCE_UNIT_INFO_DESCRIPTOR_CLASS_NAME, classLoader)) {
hints.reflection().registerType(TypeReference.of(PERSISTENCE_UNIT_INFO_DESCRIPTOR_CLASS_NAME),
MemberCategory.INVOKE_PUBLIC_METHODS);
}
}
private static void registerJdkProxyFor(RuntimeHints hints, @Nullable ClassLoader classLoader, String className) {
try {
Class<?> clazz = ClassUtils.forName(QUERY_SQM_IMPL_CLASS_NAME, classLoader);
hints.proxies().registerJdkProxy(ClassUtils.getAllInterfacesForClass(clazz, classLoader));
}
catch (ClassNotFoundException ignored) {
}
try {
Class<?> clazz = ClassUtils.forName(SQM_QUERY_IMPL_CLASS_NAME, classLoader);
hints.proxies().registerJdkProxy(ClassUtils.getAllInterfacesForClass(clazz, classLoader));
}
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);
Class<?> clazz = ClassUtils.forName(className, classLoader);
hints.proxies().registerJdkProxy(ClassUtils.getAllInterfacesForClass(clazz, classLoader));
}
catch (ClassNotFoundException ignored) {
@@ -19,6 +19,8 @@ package org.springframework.orm.jpa;
import jakarta.persistence.EntityManagerFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -55,6 +57,7 @@ class EntityManagerRuntimeHintsTests {
void entityManagerProxyHasHibernateHints() {
assertThat(RuntimeHintsPredicates.proxies().forInterfaces(Session.class, EntityManagerProxy.class))
.accepts(this.hints);
assertThat(RuntimeHintsPredicates.proxies().forInterfaces(StatelessSession.class)).accepts(this.hints);
}
@Test
@@ -63,4 +66,10 @@ class EntityManagerRuntimeHintsTests {
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(EntityManagerFactory.class, "getMetamodel")).accepts(this.hints);
}
@Test
void persistenceUnitInfoDescriptorHasReflectionHints() {
assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(PersistenceUnitInfoDescriptor.class, "getName"))
.accepts(this.hints);
}
}