From 9d6bda2b442aa5063fb5b9074a91f807bad8c6e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Tue, 7 Nov 2023 11:04:31 +0100 Subject: [PATCH] Register Hibernate `@EmbeddableInstantiator` reflection hints This commit updates PersistenceManagedTypesBeanRegistrationAotProcessor to register reflection hints for `@EmbeddableInstantiator` annotations available as of Hibernate 6.0 when needed. Related tests will be added in https://github.com/spring-projects/spring-aot-smoke-tests. Closes gh-31534 --- ...agedTypesBeanRegistrationAotProcessor.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java index 2a6d68a2b6..b334d327ba 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java @@ -23,6 +23,7 @@ import javax.lang.model.element.Modifier; import jakarta.persistence.Convert; import jakarta.persistence.Converter; +import jakarta.persistence.Embedded; import jakarta.persistence.EntityListeners; import jakarta.persistence.IdClass; import jakarta.persistence.PostLoad; @@ -64,11 +65,26 @@ import org.springframework.util.ReflectionUtils; * @author Sebastien Deleuze * @since 6.0 */ +@SuppressWarnings("unchecked") class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { private static final List> CALLBACK_TYPES = List.of(PreUpdate.class, PostUpdate.class, PrePersist.class, PostPersist.class, PreRemove.class, PostRemove.class, PostLoad.class); + @Nullable + private static Class embeddableInstantiatorClass; + + static { + try { + embeddableInstantiatorClass = (Class) ClassUtils.forName("org.hibernate.annotations.EmbeddableInstantiator", + PersistenceManagedTypesBeanRegistrationAotProcessor.class.getClassLoader()); + } + catch (ClassNotFoundException ex) { + embeddableInstantiatorClass = null; + } + } + + @Nullable @Override public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { @@ -129,6 +145,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr contributeIdClassHints(hints, managedClass); contributeConverterHints(hints, managedClass); contributeCallbackHints(hints, managedClass); + contributeHibernateHints(hints, managedClass); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException("Failed to instantiate the managed class: " + managedClassName, ex); @@ -176,5 +193,23 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr reflection.registerMethod(method, ExecutableMode.INVOKE), method -> CALLBACK_TYPES.stream().anyMatch(method::isAnnotationPresent)); } + + @SuppressWarnings("unchecked") + private void contributeHibernateHints(RuntimeHints hints, Class managedClass) { + if (embeddableInstantiatorClass == null) { + return; + } + ReflectionHints reflection = hints.reflection(); + ReflectionUtils.doWithFields(managedClass, field -> { + Embedded embeddedAnnotation = AnnotationUtils.findAnnotation(field, Embedded.class); + if (embeddedAnnotation != null && field.getAnnotatedType().getType() instanceof Class embeddedClass) { + Annotation embeddableInstantiatorAnnotation = AnnotationUtils.findAnnotation(embeddedClass, embeddableInstantiatorClass); + if (embeddableInstantiatorAnnotation != null) { + Class embeddableInstantiatorClass = (Class) AnnotationUtils.getAnnotationAttributes(embeddableInstantiatorAnnotation).get("value"); + reflection.registerType(embeddableInstantiatorClass, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + } + } + }); + } } }