Skip to content

Commit

Permalink
Register reflection hints for JPA persistence callbacks
Browse files Browse the repository at this point in the history
Closes gh-29348
  • Loading branch information
sdeleuze committed Oct 18, 2022
1 parent d4fac82 commit e0129a3
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,30 @@

package org.springframework.orm.jpa.persistenceunit;

import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.util.Arrays;
import java.util.List;

import javax.lang.model.element.Modifier;

import jakarta.persistence.Converter;
import jakarta.persistence.EntityListeners;
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.GenerationContext;
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
Expand All @@ -41,6 +52,7 @@
import org.springframework.javapoet.ParameterizedTypeName;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

/**
* {@link BeanRegistrationAotProcessor} implementations for persistence managed
Expand All @@ -55,6 +67,9 @@
*/
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
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Expand Down Expand Up @@ -115,6 +130,7 @@ private void contributeHints(RuntimeHints hints, List<String> managedClassNames)
contributeEntityListenersHints(hints, managedClass);
contributeIdClassHints(hints, managedClass);
contributeConverterHints(hints, managedClass);
contributeCallbackHints(hints, managedClass);
}
catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Failed to instantiate the managed class: " + managedClassName, ex);
Expand Down Expand Up @@ -145,5 +161,11 @@ private void contributeConverterHints(RuntimeHints hints, Class<?> managedClass)
}
}

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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.PreRemove;

@Entity
@IdClass(EmployeeId.class)
Expand Down Expand Up @@ -59,4 +60,8 @@ public EmployeeLocation getLocation() {
public void setLocation(EmployeeLocation location) {
this.location = location;
}

@PreRemove
public void preRemove() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ void contributeHints() {
.accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onType(Employee.class)
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onMethod(Employee.class, "preRemove"))
.accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeId.class)
.withMemberCategories(MemberCategory.DECLARED_FIELDS)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection().onType(EmployeeLocationConverter.class)
Expand Down

0 comments on commit e0129a3

Please sign in to comment.