Ensure package-private init/destroy methods are always invoked
Prior to this commit, if an init/destroy method was package-private and declared in a superclass in a package different from the package in which the registered bean resided, a local init/destroy method with the same name would effectively "shadow" the method from the different package, resulting in only the local init/destroy method being invoked. This commit addresses this issue by tracking package-private init methods from different packages using their fully-qualified method names, analogous to the existing support for private init/destroy methods. Closes gh-30718
This commit is contained in:
@@ -28,6 +28,8 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.lifecyclemethods.InitDestroyBean;
|
||||
import org.springframework.context.annotation.lifecyclemethods.PackagePrivateInitDestroyBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -53,11 +55,11 @@ class InitDestroyMethodLifecycleTests {
|
||||
@Test
|
||||
void initDestroyMethods() {
|
||||
Class<?> beanClass = InitDestroyBean.class;
|
||||
DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "afterPropertiesSet", "destroy");
|
||||
DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "initMethod", "destroyMethod");
|
||||
InitDestroyBean bean = beanFactory.getBean(InitDestroyBean.class);
|
||||
assertThat(bean.initMethods).as("init-methods").containsExactly("afterPropertiesSet");
|
||||
assertThat(bean.initMethods).as("init-methods").containsExactly("initMethod");
|
||||
beanFactory.destroySingletons();
|
||||
assertThat(bean.destroyMethods).as("destroy-methods").containsExactly("destroy");
|
||||
assertThat(bean.destroyMethods).as("destroy-methods").containsExactly("destroyMethod");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -132,6 +134,26 @@ class InitDestroyMethodLifecycleTests {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void jakartaAnnotationsCustomPackagePrivateInitDestroyMethodsWithTheSameMethodNames() {
|
||||
Class<?> beanClass = SubPackagePrivateInitDestroyBean.class;
|
||||
DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "initMethod", "destroyMethod");
|
||||
SubPackagePrivateInitDestroyBean bean = beanFactory.getBean(SubPackagePrivateInitDestroyBean.class);
|
||||
|
||||
assertThat(bean.initMethods).as("init-methods").containsExactly(
|
||||
"PackagePrivateInitDestroyBean.postConstruct",
|
||||
"SubPackagePrivateInitDestroyBean.postConstruct",
|
||||
"initMethod"
|
||||
);
|
||||
|
||||
beanFactory.destroySingletons();
|
||||
assertThat(bean.destroyMethods).as("destroy-methods").containsExactly(
|
||||
"SubPackagePrivateInitDestroyBean.preDestroy",
|
||||
"PackagePrivateInitDestroyBean.preDestroy",
|
||||
"destroyMethod"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void allLifecycleMechanismsAtOnce() {
|
||||
Class<?> beanClass = AllInOneBean.class;
|
||||
@@ -165,21 +187,6 @@ class InitDestroyMethodLifecycleTests {
|
||||
}
|
||||
|
||||
|
||||
static class InitDestroyBean {
|
||||
|
||||
final List<String> initMethods = new ArrayList<>();
|
||||
final List<String> destroyMethods = new ArrayList<>();
|
||||
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.initMethods.add("afterPropertiesSet");
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
this.destroyMethods.add("destroy");
|
||||
}
|
||||
}
|
||||
|
||||
static class InitializingDisposableWithShadowedMethodsBean extends InitDestroyBean implements
|
||||
InitializingBean, DisposableBean {
|
||||
|
||||
@@ -296,4 +303,18 @@ class InitDestroyMethodLifecycleTests {
|
||||
}
|
||||
}
|
||||
|
||||
static class SubPackagePrivateInitDestroyBean extends PackagePrivateInitDestroyBean {
|
||||
|
||||
@PostConstruct
|
||||
void postConstruct() {
|
||||
this.initMethods.add("SubPackagePrivateInitDestroyBean.postConstruct");
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
void preDestroy() {
|
||||
this.destroyMethods.add("SubPackagePrivateInitDestroyBean.preDestroy");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.context.annotation.lifecyclemethods;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class InitDestroyBean {
|
||||
|
||||
public final List<String> initMethods = new ArrayList<>();
|
||||
public final List<String> destroyMethods = new ArrayList<>();
|
||||
|
||||
|
||||
public void initMethod() {
|
||||
this.initMethods.add("initMethod");
|
||||
}
|
||||
|
||||
public void destroyMethod() {
|
||||
this.destroyMethods.add("destroyMethod");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.context.annotation.lifecyclemethods;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
|
||||
public class PackagePrivateInitDestroyBean extends InitDestroyBean {
|
||||
|
||||
@PostConstruct
|
||||
void postConstruct() {
|
||||
this.initMethods.add("PackagePrivateInitDestroyBean.postConstruct");
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
void preDestroy() {
|
||||
this.destroyMethods.add("PackagePrivateInitDestroyBean.preDestroy");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user