From c75c0ae2d520fa8524ba3792dd84f2bdb72c8bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 12 Dec 2023 14:43:58 +0100 Subject: [PATCH] Make sure interface method has hints for init/destroy invocation This commit matches the behavior of the core container when it invokes a custom init or destroy method. If the custom method is an interface implementation, the core container attempts to invoke the method that's defined on the interface. This commit makes sure to also register a hint for the interface method. Closes gh-31819 --- ...BeanDefinitionPropertiesCodeGenerator.java | 4 ++ ...efinitionPropertiesCodeGeneratorTests.java | 44 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java index a21e0173653..2f474de6a54 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java @@ -166,6 +166,10 @@ class BeanDefinitionPropertiesCodeGenerator { Method method = ReflectionUtils.findMethod(methodDeclaringClass, methodName); if (method != null) { this.hints.reflection().registerMethod(method, ExecutableMode.INVOKE); + Method interfaceMethod = ClassUtils.getInterfaceMethodIfPossible(method, beanUserClass); + if (!interfaceMethod.equals(method)) { + this.hints.reflection().registerMethod(interfaceMethod, ExecutableMode.INVOKE); + } } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java index 2c2667b3c20..1e473202a76 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java @@ -457,6 +457,15 @@ class BeanDefinitionPropertiesCodeGeneratorTests { assertHasMethodInvokeHints(InitDestroyBean.class, "init"); } + @Test + void singleInitMethodFromInterface() { + beanDefinition.setTargetType(InitializableTestBean.class); + beanDefinition.setInitMethodName("initialize"); + compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly("initialize")); + assertHasMethodInvokeHints(InitializableTestBean.class, "initialize"); + assertHasMethodInvokeHints(Initializable.class, "initialize"); + } + @Test void privateInitMethod() { beanDefinition.setTargetType(InitDestroyBean.class); @@ -489,6 +498,16 @@ class BeanDefinitionPropertiesCodeGeneratorTests { assertReflectionOnPublisher(); } + @Test + void singleDestroyMethodFromInterface() { + beanDefinition.setTargetType(DisposableTestBean.class); + beanDefinition.setDestroyMethodName("dispose"); + compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("dispose")); + assertHasMethodInvokeHints(DisposableTestBean.class, "dispose"); + assertHasMethodInvokeHints(Disposable.class, "dispose"); + assertReflectionOnPublisher(); + } + @Test void privateDestroyMethod() { beanDefinition.setTargetType(InitDestroyBean.class); @@ -572,6 +591,31 @@ class BeanDefinitionPropertiesCodeGeneratorTests { } + interface Initializable { + + void initialize(); + } + + static class InitializableTestBean implements Initializable { + + @Override + public void initialize() { + } + } + + interface Disposable { + + void dispose(); + } + + static class DisposableTestBean implements Disposable { + + @Override + public void dispose() { + } + + } + static class PropertyValuesBean { private Class test;