Register reflection hints for JPA persistence callbacks
Closes gh-29348
This commit is contained in:
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package org.springframework.orm.jpa.persistenceunit;
|
package org.springframework.orm.jpa.persistenceunit;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Executable;
|
import java.lang.reflect.Executable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.lang.model.element.Modifier;
|
import javax.lang.model.element.Modifier;
|
||||||
@@ -24,11 +26,20 @@ import javax.lang.model.element.Modifier;
|
|||||||
import jakarta.persistence.Converter;
|
import jakarta.persistence.Converter;
|
||||||
import jakarta.persistence.EntityListeners;
|
import jakarta.persistence.EntityListeners;
|
||||||
import jakarta.persistence.IdClass;
|
import jakarta.persistence.IdClass;
|
||||||
|
import jakarta.persistence.PostLoad;
|
||||||
|
import jakarta.persistence.PostPersist;
|
||||||
|
import jakarta.persistence.PostRemove;
|
||||||
|
import jakarta.persistence.PostUpdate;
|
||||||
|
import jakarta.persistence.PrePersist;
|
||||||
|
import jakarta.persistence.PreRemove;
|
||||||
|
import jakarta.persistence.PreUpdate;
|
||||||
|
|
||||||
import org.springframework.aot.generate.GeneratedMethod;
|
import org.springframework.aot.generate.GeneratedMethod;
|
||||||
import org.springframework.aot.generate.GenerationContext;
|
import org.springframework.aot.generate.GenerationContext;
|
||||||
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
|
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
|
||||||
|
import org.springframework.aot.hint.ExecutableMode;
|
||||||
import org.springframework.aot.hint.MemberCategory;
|
import org.springframework.aot.hint.MemberCategory;
|
||||||
|
import org.springframework.aot.hint.ReflectionHints;
|
||||||
import org.springframework.aot.hint.RuntimeHints;
|
import org.springframework.aot.hint.RuntimeHints;
|
||||||
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
|
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
|
||||||
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||||
@@ -41,6 +52,7 @@ import org.springframework.javapoet.CodeBlock;
|
|||||||
import org.springframework.javapoet.ParameterizedTypeName;
|
import org.springframework.javapoet.ParameterizedTypeName;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link BeanRegistrationAotProcessor} implementations for persistence managed
|
* {@link BeanRegistrationAotProcessor} implementations for persistence managed
|
||||||
@@ -55,6 +67,9 @@ import org.springframework.util.ClassUtils;
|
|||||||
*/
|
*/
|
||||||
class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
|
class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
|
||||||
|
|
||||||
|
private static final List<Class<? extends Annotation>> CALLBACK_TYPES = Arrays.asList(PreUpdate.class,
|
||||||
|
PostUpdate.class, PrePersist.class, PostPersist.class, PreRemove.class, PostRemove.class, PostLoad.class);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
||||||
@@ -115,6 +130,7 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr
|
|||||||
contributeEntityListenersHints(hints, managedClass);
|
contributeEntityListenersHints(hints, managedClass);
|
||||||
contributeIdClassHints(hints, managedClass);
|
contributeIdClassHints(hints, managedClass);
|
||||||
contributeConverterHints(hints, managedClass);
|
contributeConverterHints(hints, managedClass);
|
||||||
|
contributeCallbackHints(hints, managedClass);
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException ex) {
|
catch (ClassNotFoundException ex) {
|
||||||
throw new IllegalArgumentException("Failed to instantiate the managed class: " + managedClassName, ex);
|
throw new IllegalArgumentException("Failed to instantiate the managed class: " + managedClassName, ex);
|
||||||
@@ -145,5 +161,11 @@ class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void contributeCallbackHints(RuntimeHints hints, Class<?> managedClass) {
|
||||||
|
ReflectionHints reflection = hints.reflection();
|
||||||
|
ReflectionUtils.doWithMethods(managedClass, method ->
|
||||||
|
reflection.registerMethod(method, ExecutableMode.INVOKE),
|
||||||
|
method -> CALLBACK_TYPES.stream().anyMatch(method::isAnnotationPresent));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import jakarta.persistence.Column;
|
|||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.IdClass;
|
import jakarta.persistence.IdClass;
|
||||||
|
import jakarta.persistence.PreRemove;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@IdClass(EmployeeId.class)
|
@IdClass(EmployeeId.class)
|
||||||
@@ -59,4 +60,8 @@ public class Employee {
|
|||||||
public void setLocation(EmployeeLocation location) {
|
public void setLocation(EmployeeLocation location) {
|
||||||
this.location = location;
|
this.location = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreRemove
|
||||||
|
public void preRemove() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ class PersistenceManagedTypesBeanRegistrationAotProcessorTests {
|
|||||||
.accepts(hints);
|
.accepts(hints);
|
||||||
assertThat(RuntimeHintsPredicates.reflection().onType(Employee.class)
|
assertThat(RuntimeHintsPredicates.reflection().onType(Employee.class)
|
||||||
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
|
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
|
||||||
|
assertThat(RuntimeHintsPredicates.reflection().onMethod(Employee.class, "preRemove"))
|
||||||
|
.accepts(hints);
|
||||||
assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeId.class)
|
assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeId.class)
|
||||||
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
|
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
|
||||||
assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeLocationConverter.class)
|
assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeLocationConverter.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user