diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java index b6155f6d7bfa..c970b61d90ad 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java @@ -16,7 +16,7 @@ package org.springframework.context.annotation; -import java.util.HashSet; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; @@ -65,8 +65,7 @@ final class ConfigurationClass { private final Map importBeanDefinitionRegistrars = new LinkedHashMap<>(); - final Set skippedBeanMethods = new HashSet<>(); - + final Map skippedBeanMethods = new HashMap<>(); /** * Create a new {@link ConfigurationClass} with the given name. diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 93f22542f6b5..4ba26b6af1aa 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -69,6 +69,7 @@ * @author Phillip Webb * @author Sam Brannen * @author Sebastien Deleuze + * @author Hakan Altindag * @since 3.0 * @see ConfigurationClassParser */ @@ -187,12 +188,26 @@ private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) { MethodMetadata metadata = beanMethod.getMetadata(); String methodName = metadata.getMethodName(); - // Do we need to mark the bean as skipped by its condition? + MethodMetadataWrapper metadataWrapper = new MethodMetadataWrapper(metadata); + if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) { - configClass.skippedBeanMethods.add(methodName); + configClass.skippedBeanMethods.put(methodName, new MethodMetadataWrapper(metadata)); return; } - if (configClass.skippedBeanMethods.contains(methodName)) { + else if (configClass.skippedBeanMethods.containsKey(methodName)){ + MethodMetadataWrapper toBeSkippedBeanMethod = configClass.skippedBeanMethods.get(methodName); + + if (!toBeSkippedBeanMethod.getSuperClassForDeclaredBean().isPresent()) { + configClass.skippedBeanMethods.remove(methodName); + } + + if (toBeSkippedBeanMethod.getClassForDeclaredBean().isPresent() + && metadataWrapper.getSuperClassForDeclaredBean().isPresent() + && toBeSkippedBeanMethod.getClassForDeclaredBean().get() == metadataWrapper.getSuperClassForDeclaredBean().get()) { + configClass.skippedBeanMethods.remove(methodName); + } + } + if (configClass.skippedBeanMethods.containsKey(methodName)) { return; } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/MethodMetadataWrapper.java b/spring-context/src/main/java/org/springframework/context/annotation/MethodMetadataWrapper.java new file mode 100644 index 000000000000..1262517a32ae --- /dev/null +++ b/spring-context/src/main/java/org/springframework/context/annotation/MethodMetadataWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2022 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; + +import java.util.Optional; + +import org.springframework.core.type.MethodMetadata; + +public class MethodMetadataWrapper { + + private final MethodMetadata methodMetadata; + + public MethodMetadataWrapper(MethodMetadata methodMetadata) { + this.methodMetadata = methodMetadata; + } + + public String getBeanName() { + return this.methodMetadata.getMethodName(); + } + + public Optional> getClassForDeclaredBean() { + try { + Class clazz = Class.forName(this.methodMetadata.getDeclaringClassName()); + return Optional.of(clazz); + } + catch (ClassNotFoundException ex) { + return Optional.empty(); + } + } + + public Optional> getSuperClassForDeclaredBean() { + return getClassForDeclaredBean() + .map(Class::getSuperclass) + .filter(superClass -> !"java.lang.Object".equals(superClass.getName())); + } + +} diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java index e5593c5d8731..f577d3ba4816 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassWithConditionTests.java @@ -136,11 +136,17 @@ public void importsNotCreated() throws Exception { } @Test - public void conditionOnOverriddenMethodHonored() { + public void conditionOnOverriddenMethodHonoredWhenHavingInheritance() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithBeanSkipped.class); assertThat(context.getBeansOfType(ExampleBean.class).size()).isEqualTo(0); } + @Test + public void conditionOnOverriddenMethodHonoredWhenHavingMethodOverloading() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithBeanNotSkippedWithMethodOverloading.class); + assertThat(context.getBeansOfType(ExampleBean.class).size()).isEqualTo(1); + } + @Test public void noConditionOnOverriddenMethodHonored() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithBeanReactivated.class); @@ -358,6 +364,27 @@ public ExampleBean baz() { } } + static class ConfigWithBeanNotSkippedWithMethodOverloading { + + @Bean + @Conditional(NeverCondition.class) + public ExampleBean baz() { + return new ExampleBean(); + } + + @Bean + @Conditional(AlwaysCondition.class) + public ExampleBean baz(Object foo) { + return new ExampleBean(); + } + + @Bean + public Object foo() { + return new Object(); + } + + } + static class ConfigWithBeanReactivated extends ConfigWithBeanSkipped { @Override