Add reflection hint on Publisher for bean destroy support
Prior to this commit, `DisposableBeanAdapter` supported reactive bean destroy methods by detected if `Publisher` is available on the classpath. The AOT engine did not contribute a reflection hint for this call. This commit ensures that this reflection hint is registered in all cases, even if there are no destroy methods detected on beans. Fixes gh-31278
This commit is contained in:
parent
d46c26d903
commit
a97ff39088
|
@ -35,6 +35,7 @@ import java.util.function.Predicate;
|
||||||
import org.springframework.aot.generate.GeneratedMethods;
|
import org.springframework.aot.generate.GeneratedMethods;
|
||||||
import org.springframework.aot.hint.ExecutableMode;
|
import org.springframework.aot.hint.ExecutableMode;
|
||||||
import org.springframework.aot.hint.RuntimeHints;
|
import org.springframework.aot.hint.RuntimeHints;
|
||||||
|
import org.springframework.aot.hint.TypeReference;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.beans.PropertyValue;
|
import org.springframework.beans.PropertyValue;
|
||||||
|
@ -128,6 +129,8 @@ class BeanDefinitionPropertiesCodeGenerator {
|
||||||
|
|
||||||
private void addInitDestroyMethods(Builder code, AbstractBeanDefinition beanDefinition,
|
private void addInitDestroyMethods(Builder code, AbstractBeanDefinition beanDefinition,
|
||||||
@Nullable String[] methodNames, String format) {
|
@Nullable String[] methodNames, String format) {
|
||||||
|
// For Publisher-based destroy methods
|
||||||
|
this.hints.reflection().registerType(TypeReference.of("org.reactivestreams.Publisher"));
|
||||||
if (!ObjectUtils.isEmpty(methodNames)) {
|
if (!ObjectUtils.isEmpty(methodNames)) {
|
||||||
Class<?> beanType = ClassUtils.getUserClass(beanDefinition.getResolvableType().toClass());
|
Class<?> beanType = ClassUtils.getUserClass(beanDefinition.getResolvableType().toClass());
|
||||||
Arrays.stream(methodNames).forEach(methodName -> addInitDestroyHint(beanType, methodName));
|
Arrays.stream(methodNames).forEach(methodName -> addInitDestroyHint(beanType, methodName));
|
||||||
|
|
|
@ -31,6 +31,7 @@ import javax.lang.model.element.Modifier;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.reactivestreams.Publisher;
|
||||||
|
|
||||||
import org.springframework.aot.generate.GeneratedClass;
|
import org.springframework.aot.generate.GeneratedClass;
|
||||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||||
|
@ -413,6 +414,7 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||||
@Test
|
@Test
|
||||||
void noDestroyMethod() {
|
void noDestroyMethod() {
|
||||||
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).isNull());
|
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).isNull());
|
||||||
|
assertReflectionOnPublisher();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -420,6 +422,7 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||||
beanDefinition.setDestroyMethodName("destroy");
|
beanDefinition.setDestroyMethodName("destroy");
|
||||||
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy"));
|
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy"));
|
||||||
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy");
|
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy");
|
||||||
|
assertReflectionOnPublisher();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -427,6 +430,7 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||||
beanDefinition.setDestroyMethodName(privateDestroyMethod);
|
beanDefinition.setDestroyMethodName(privateDestroyMethod);
|
||||||
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly(privateDestroyMethod));
|
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly(privateDestroyMethod));
|
||||||
assertHasMethodInvokeHints(InitDestroyBean.class, "privateDestroy");
|
assertHasMethodInvokeHints(InitDestroyBean.class, "privateDestroy");
|
||||||
|
assertReflectionOnPublisher();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -434,6 +438,11 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||||
beanDefinition.setDestroyMethodNames("destroy", privateDestroyMethod);
|
beanDefinition.setDestroyMethodNames("destroy", privateDestroyMethod);
|
||||||
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy", privateDestroyMethod));
|
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy", privateDestroyMethod));
|
||||||
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy", "privateDestroy");
|
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy", "privateDestroy");
|
||||||
|
assertReflectionOnPublisher();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertReflectionOnPublisher() {
|
||||||
|
assertThat(RuntimeHintsPredicates.reflection().onType(Publisher.class)).accepts(generationContext.getRuntimeHints());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue