Prevent incorrect ImportAware metdata injection
Update ImportRegistry to track all import registrations that occur against an importing class (rather than just keeping the last). In addition, prune imported classes from the registry when a configuration class is removed during the REGISTER_BEAN ConfigurationPhase. This update prevents incorrect metadata from being injected into an ImportAware class which is imported twice by different configurations classes (when one of the configuration classes will be ultimately skipped due to a @Condition). Issue: SPR-12128
This commit is contained in:
parent
8bf141eca9
commit
abc343f407
|
@ -44,6 +44,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
|||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.annotation.ConfigurationClassParser.ImportRegistry;
|
||||
import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
@ -86,6 +87,8 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
|
||||
private final BeanNameGenerator importBeanNameGenerator;
|
||||
|
||||
private final ImportRegistry importRegistry;
|
||||
|
||||
private final ConditionEvaluator conditionEvaluator;
|
||||
|
||||
|
||||
|
@ -95,7 +98,8 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
*/
|
||||
public ConfigurationClassBeanDefinitionReader(BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,
|
||||
ProblemReporter problemReporter, MetadataReaderFactory metadataReaderFactory,
|
||||
ResourceLoader resourceLoader, Environment environment, BeanNameGenerator importBeanNameGenerator) {
|
||||
ResourceLoader resourceLoader, Environment environment, BeanNameGenerator importBeanNameGenerator,
|
||||
ImportRegistry importRegistry) {
|
||||
|
||||
this.registry = registry;
|
||||
this.sourceExtractor = sourceExtractor;
|
||||
|
@ -104,6 +108,7 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
this.resourceLoader = resourceLoader;
|
||||
this.environment = environment;
|
||||
this.importBeanNameGenerator = importBeanNameGenerator;
|
||||
this.importRegistry = importRegistry;
|
||||
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
|
||||
}
|
||||
|
||||
|
@ -128,6 +133,7 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
|
||||
if (trackedConditionEvaluator.shouldSkip(configClass)) {
|
||||
removeBeanDefinition(configClass);
|
||||
importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,8 @@ import org.springframework.core.type.classreading.MetadataReader;
|
|||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -470,10 +472,8 @@ class ConfigurationClassParser {
|
|||
}
|
||||
else {
|
||||
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
|
||||
if (!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
|
||||
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
|
||||
processConfigurationClass(candidate.asConfigClass(configClass));
|
||||
}
|
||||
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
|
||||
processConfigurationClass(candidate.asConfigClass(configClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -591,21 +591,35 @@ class ConfigurationClassParser {
|
|||
interface ImportRegistry {
|
||||
|
||||
AnnotationMetadata getImportingClassFor(String importedClass);
|
||||
|
||||
void removeImportingClassFor(String importedClass);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class ImportStack extends Stack<ConfigurationClass> implements ImportRegistry {
|
||||
|
||||
private final Map<String, AnnotationMetadata> imports = new HashMap<String, AnnotationMetadata>();
|
||||
private final MultiValueMap<String, AnnotationMetadata> imports = new LinkedMultiValueMap<String, AnnotationMetadata>();
|
||||
|
||||
public void registerImport(AnnotationMetadata importingClass, String importedClass) {
|
||||
this.imports.put(importedClass, importingClass);
|
||||
this.imports.add(importedClass, importingClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeImportingClassFor(String importedClass) {
|
||||
for (List<AnnotationMetadata> list : this.imports.values()) {
|
||||
for (Iterator<AnnotationMetadata> iterator = list.iterator(); iterator.hasNext();) {
|
||||
if (iterator.next().getClassName().equals(importedClass)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationMetadata getImportingClassFor(String importedClass) {
|
||||
return this.imports.get(importedClass);
|
||||
List<AnnotationMetadata> list = this.imports.get(importedClass);
|
||||
return (list == null || list.isEmpty() ? null : list.get(list.size() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -314,7 +314,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
|||
if (this.reader == null) {
|
||||
this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor,
|
||||
this.problemReporter, this.metadataReaderFactory, this.resourceLoader, this.environment,
|
||||
this.importBeanNameGenerator);
|
||||
this.importBeanNameGenerator, parser.getImportRegistry());
|
||||
}
|
||||
this.reader.loadBeanDefinitions(configClasses);
|
||||
alreadyParsed.addAll(configClasses);
|
||||
|
|
|
@ -234,7 +234,7 @@ public class ImportAwareTests {
|
|||
}
|
||||
|
||||
|
||||
@Conditional(NeverMatchingCondition.class)
|
||||
@Conditional(OnMissingBeanCondition.class)
|
||||
@EnableSomeConfiguration("foo")
|
||||
@Configuration
|
||||
public static class ConfigurationTwo {
|
||||
|
@ -277,11 +277,12 @@ public class ImportAwareTests {
|
|||
}
|
||||
|
||||
|
||||
private static final class NeverMatchingCondition implements ConfigurationCondition {
|
||||
private static final class OnMissingBeanCondition implements ConfigurationCondition {
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return false;
|
||||
return context.getBeanFactory().getBeanNamesForType(MetadataHolder.class,
|
||||
true, false).length == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue