Skip to content

Commit c75c0ae

Browse files
committed
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
1 parent c0683cd commit c75c0ae

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ private void addInitDestroyHint(Class<?> beanUserClass, String methodName) {
166166
Method method = ReflectionUtils.findMethod(methodDeclaringClass, methodName);
167167
if (method != null) {
168168
this.hints.reflection().registerMethod(method, ExecutableMode.INVOKE);
169+
Method interfaceMethod = ClassUtils.getInterfaceMethodIfPossible(method, beanUserClass);
170+
if (!interfaceMethod.equals(method)) {
171+
this.hints.reflection().registerMethod(interfaceMethod, ExecutableMode.INVOKE);
172+
}
169173
}
170174
}
171175

spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,15 @@ void singleInitMethod() {
457457
assertHasMethodInvokeHints(InitDestroyBean.class, "init");
458458
}
459459

460+
@Test
461+
void singleInitMethodFromInterface() {
462+
beanDefinition.setTargetType(InitializableTestBean.class);
463+
beanDefinition.setInitMethodName("initialize");
464+
compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly("initialize"));
465+
assertHasMethodInvokeHints(InitializableTestBean.class, "initialize");
466+
assertHasMethodInvokeHints(Initializable.class, "initialize");
467+
}
468+
460469
@Test
461470
void privateInitMethod() {
462471
beanDefinition.setTargetType(InitDestroyBean.class);
@@ -489,6 +498,16 @@ void singleDestroyMethod() {
489498
assertReflectionOnPublisher();
490499
}
491500

501+
@Test
502+
void singleDestroyMethodFromInterface() {
503+
beanDefinition.setTargetType(DisposableTestBean.class);
504+
beanDefinition.setDestroyMethodName("dispose");
505+
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("dispose"));
506+
assertHasMethodInvokeHints(DisposableTestBean.class, "dispose");
507+
assertHasMethodInvokeHints(Disposable.class, "dispose");
508+
assertReflectionOnPublisher();
509+
}
510+
492511
@Test
493512
void privateDestroyMethod() {
494513
beanDefinition.setTargetType(InitDestroyBean.class);
@@ -572,6 +591,31 @@ private void privateDestroy() {
572591

573592
}
574593

594+
interface Initializable {
595+
596+
void initialize();
597+
}
598+
599+
static class InitializableTestBean implements Initializable {
600+
601+
@Override
602+
public void initialize() {
603+
}
604+
}
605+
606+
interface Disposable {
607+
608+
void dispose();
609+
}
610+
611+
static class DisposableTestBean implements Disposable {
612+
613+
@Override
614+
public void dispose() {
615+
}
616+
617+
}
618+
575619
static class PropertyValuesBean {
576620

577621
private Class<?> test;

0 commit comments

Comments
 (0)