diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessorTests.java index 9856e9d1cf9c..7be4027371f2 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RegisteredBean; @@ -29,12 +31,15 @@ import org.springframework.beans.testfixture.beans.factory.generator.lifecycle.MultiInitDestroyBean; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; /** * Tests for {@link InitDestroyAnnotationBeanPostProcessor}. * + * @since 6.0 * @author Stephane Nicoll * @author Phillip Webb + * @author Sam Brannen */ class InitDestroyAnnotationBeanPostProcessorTests { @@ -109,6 +114,35 @@ void processAheadOfTimeWhenHasMultipleInitDestroyAnnotationsAddsAllMethodNames() assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("anotherDestroyMethod", "destroyMethod"); } + @Test + void processAheadOfTimeWithMultipleLevelsOfPublicAndPrivateInitAndDestroyMethods() { + RootBeanDefinition beanDefinition = new RootBeanDefinition(CustomAnnotatedPrivateSameNameInitDestroyBean.class); + // We explicitly define "afterPropertiesSet" as a "custom init method" + // to ensure that it will be tracked as such even though it has the same + // name as InitializingBean#afterPropertiesSet(). + beanDefinition.setInitMethodNames("afterPropertiesSet", "customInit"); + // We explicitly define "destroy" as a "custom destroy method" + // to ensure that it will be tracked as such even though it has the same + // name as DisposableBean#destroy(). + beanDefinition.setDestroyMethodNames("destroy", "customDestroy"); + processAheadOfTime(beanDefinition); + RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(); + assertSoftly(softly -> { + softly.assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly( + "afterPropertiesSet", + "customInit", + CustomAnnotatedPrivateInitDestroyBean.class.getName() + ".privateInit", // fully-qualified private method + CustomAnnotatedPrivateSameNameInitDestroyBean.class.getName() + ".privateInit" // fully-qualified private method + ); + softly.assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly( + "destroy", + "customDestroy", + CustomAnnotatedPrivateSameNameInitDestroyBean.class.getName() + ".privateDestroy", // fully-qualified private method + CustomAnnotatedPrivateInitDestroyBean.class.getName() + ".privateDestroy" // fully-qualified private method + ); + }); + } + private void processAheadOfTime(RootBeanDefinition beanDefinition) { RegisteredBean registeredBean = registerBean(beanDefinition); assertThat(createAotBeanPostProcessor().processAheadOfTime(registeredBean)).isNull(); @@ -133,4 +167,49 @@ private InitDestroyAnnotationBeanPostProcessor createAotBeanPostProcessor() { static class NoInitDestroyBean {} + static class CustomInitDestroyBean { + + public void customInit() { + } + + public void customDestroy() { + } + } + + static class CustomInitializingDisposableBean extends CustomInitDestroyBean + implements InitializingBean, DisposableBean { + + @Override + public void afterPropertiesSet() { + } + + @Override + public void destroy() { + } + } + + static class CustomAnnotatedPrivateInitDestroyBean extends CustomInitializingDisposableBean { + + @Init + private void privateInit() { + } + + @Destroy + private void privateDestroy() { + } + } + + static class CustomAnnotatedPrivateSameNameInitDestroyBean extends CustomAnnotatedPrivateInitDestroyBean { + + @Init + @SuppressWarnings("unused") + private void privateInit() { + } + + @Destroy + @SuppressWarnings("unused") + private void privateDestroy() { + } + } + }