From 9e963bce58092990a3274a28111296b82e7f7f3d Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Mon, 15 May 2023 11:12:02 +0200 Subject: [PATCH] Add Hibernate runtime hints This adds hints for the two No JtaPlatform candidates as well as for the naming strategies. Closes gh-35423 --- .../orm/jpa/HibernateJpaConfiguration.java | 30 +++++++++++++++++++ .../HibernateJpaAutoConfigurationTests.java | 30 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java index acb9f3ceba..536988a813 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java @@ -28,20 +28,29 @@ import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.cfg.AvailableSettings; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.TypeHint; +import org.springframework.aot.hint.TypeReference; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration.HibernateRuntimeHints; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jdbc.SchemaManagementProvider; import org.springframework.boot.jdbc.metadata.CompositeDataSourcePoolMetadataProvider; import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadata; import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider; +import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.jndi.JndiLocatorDelegate; import org.springframework.orm.hibernate5.SpringBeanContainer; import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; @@ -57,10 +66,12 @@ import org.springframework.util.ClassUtils; * @author Manuel Doninger * @author Andy Wilkinson * @author Stephane Nicoll + * @author Moritz Halbritter */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(HibernateProperties.class) @ConditionalOnSingleCandidate(DataSource.class) +@ImportRuntimeHints(HibernateRuntimeHints.class) class HibernateJpaConfiguration extends JpaBaseConfiguration { private static final Log logger = LogFactory.getLog(HibernateJpaConfiguration.class); @@ -237,4 +248,23 @@ class HibernateJpaConfiguration extends JpaBaseConfiguration { } + static class HibernateRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + for (String clazz : NO_JTA_PLATFORM_CLASSES) { + hints.reflection() + .registerType(TypeReference.of(clazz), + TypeHint.builtWith(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + } + hints.reflection() + .registerType(SpringImplicitNamingStrategy.class, + TypeHint.builtWith(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + hints.reflection() + .registerType(CamelCaseToUnderscoresNamingStrategy.class, + TypeHint.builtWith(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index 7382ce3c80..398c763532 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -48,6 +48,10 @@ import org.hibernate.internal.SessionFactoryImpl; import org.hibernate.jpa.HibernatePersistenceProvider; import org.junit.jupiter.api.Test; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.TypeReference; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -57,6 +61,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerA import org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfigurationTests.JpaUsingApplicationListenerConfiguration.EventCapturingApplicationListener; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration.HibernateRuntimeHints; import org.springframework.boot.autoconfigure.orm.jpa.mapping.NonAnnotatedEntity; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration; @@ -91,6 +96,7 @@ import static org.mockito.Mockito.mock; * @author Kazuki Shimizu * @author Stephane Nicoll * @author Chris Bono + * @author Moritz Halbritter */ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTests { @@ -477,6 +483,30 @@ class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTes }); } + @Test + void registersHintsForJtaClasses() { + RuntimeHints hints = new RuntimeHints(); + new HibernateRuntimeHints().registerHints(hints, getClass().getClassLoader()); + for (String clazz : Arrays.asList("org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform", + "org.hibernate.service.jta.platform.internal.NoJtaPlatform")) { + assertThat(RuntimeHintsPredicates.reflection() + .onType(TypeReference.of(clazz)) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints); + } + } + + @Test + void registersHintsForNamingClasses() { + RuntimeHints hints = new RuntimeHints(); + new HibernateRuntimeHints().registerHints(hints, getClass().getClassLoader()); + for (Class clazz : Arrays.asList(SpringImplicitNamingStrategy.class, + CamelCaseToUnderscoresNamingStrategy.class)) { + assertThat(RuntimeHintsPredicates.reflection() + .onType(clazz) + .withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints); + } + } + @Configuration(proxyBeanMethods = false) @TestAutoConfigurationPackage(City.class) @DependsOnDatabaseInitialization