Skip to content

Commit e0129a3

Browse files
committed
Register reflection hints for JPA persistence callbacks
Closes gh-29348
1 parent d4fac82 commit e0129a3

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,30 @@
1616

1717
package org.springframework.orm.jpa.persistenceunit;
1818

19+
import java.lang.annotation.Annotation;
1920
import java.lang.reflect.Executable;
21+
import java.util.Arrays;
2022
import java.util.List;
2123

2224
import javax.lang.model.element.Modifier;
2325

2426
import jakarta.persistence.Converter;
2527
import jakarta.persistence.EntityListeners;
2628
import jakarta.persistence.IdClass;
29+
import jakarta.persistence.PostLoad;
30+
import jakarta.persistence.PostPersist;
31+
import jakarta.persistence.PostRemove;
32+
import jakarta.persistence.PostUpdate;
33+
import jakarta.persistence.PrePersist;
34+
import jakarta.persistence.PreRemove;
35+
import jakarta.persistence.PreUpdate;
2736

2837
import org.springframework.aot.generate.GeneratedMethod;
2938
import org.springframework.aot.generate.GenerationContext;
3039
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
40+
import org.springframework.aot.hint.ExecutableMode;
3141
import org.springframework.aot.hint.MemberCategory;
42+
import org.springframework.aot.hint.ReflectionHints;
3243
import org.springframework.aot.hint.RuntimeHints;
3344
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
3445
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
@@ -41,6 +52,7 @@
4152
import org.springframework.javapoet.ParameterizedTypeName;
4253
import org.springframework.lang.Nullable;
4354
import org.springframework.util.ClassUtils;
55+
import org.springframework.util.ReflectionUtils;
4456

4557
/**
4658
* {@link BeanRegistrationAotProcessor} implementations for persistence managed
@@ -55,6 +67,9 @@
5567
*/
5668
class PersistenceManagedTypesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
5769

70+
private static final List<Class<? extends Annotation>> CALLBACK_TYPES = Arrays.asList(PreUpdate.class,
71+
PostUpdate.class, PrePersist.class, PostPersist.class, PreRemove.class, PostRemove.class, PostLoad.class);
72+
5873
@Nullable
5974
@Override
6075
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
@@ -115,6 +130,7 @@ private void contributeHints(RuntimeHints hints, List<String> managedClassNames)
115130
contributeEntityListenersHints(hints, managedClass);
116131
contributeIdClassHints(hints, managedClass);
117132
contributeConverterHints(hints, managedClass);
133+
contributeCallbackHints(hints, managedClass);
118134
}
119135
catch (ClassNotFoundException ex) {
120136
throw new IllegalArgumentException("Failed to instantiate the managed class: " + managedClassName, ex);
@@ -145,5 +161,11 @@ private void contributeConverterHints(RuntimeHints hints, Class<?> managedClass)
145161
}
146162
}
147163

164+
private void contributeCallbackHints(RuntimeHints hints, Class<?> managedClass) {
165+
ReflectionHints reflection = hints.reflection();
166+
ReflectionUtils.doWithMethods(managedClass, method ->
167+
reflection.registerMethod(method, ExecutableMode.INVOKE),
168+
method -> CALLBACK_TYPES.stream().anyMatch(method::isAnnotationPresent));
169+
}
148170
}
149171
}

spring-orm/src/test/java/org/springframework/orm/jpa/domain/Employee.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import jakarta.persistence.Entity;
2121
import jakarta.persistence.Id;
2222
import jakarta.persistence.IdClass;
23+
import jakarta.persistence.PreRemove;
2324

2425
@Entity
2526
@IdClass(EmployeeId.class)
@@ -59,4 +60,8 @@ public EmployeeLocation getLocation() {
5960
public void setLocation(EmployeeLocation location) {
6061
this.location = location;
6162
}
63+
64+
@PreRemove
65+
public void preRemove() {
66+
}
6267
}

spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ void contributeHints() {
9191
.accepts(hints);
9292
assertThat(RuntimeHintsPredicates.reflection().onType(Employee.class)
9393
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
94+
assertThat(RuntimeHintsPredicates.reflection().onMethod(Employee.class, "preRemove"))
95+
.accepts(hints);
9496
assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeId.class)
9597
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
9698
assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeLocationConverter.class)

0 commit comments

Comments
 (0)