@Import allows for importing regular component classes as well
Issue: SPR-11740
This commit is contained in:
parent
1d33fd039a
commit
a15dc08bea
|
@ -35,8 +35,6 @@ import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostPr
|
|||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;
|
||||
import org.springframework.beans.factory.parsing.Location;
|
||||
import org.springframework.beans.factory.parsing.Problem;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
import org.springframework.beans.factory.parsing.SourceExtractor;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinitionReader;
|
||||
|
@ -160,22 +158,18 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
AnnotationMetadata metadata = configClass.getMetadata();
|
||||
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
|
||||
|
||||
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
|
||||
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
|
||||
configBeanDef.setScope(scopeMetadata.getScopeName());
|
||||
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
|
||||
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
|
||||
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
|
||||
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
|
||||
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
|
||||
configClass.setBeanName(configBeanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Registered bean definition for imported @Configuration class %s", configBeanName));
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.problemReporter.error(
|
||||
new InvalidConfigurationImportProblem(metadata.getClassName(), configClass.getResource(), metadata));
|
||||
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
|
||||
configBeanDef.setScope(scopeMetadata.getScopeName());
|
||||
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
|
||||
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
|
||||
|
||||
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
|
||||
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
|
||||
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
|
||||
configClass.setBeanName(configBeanName);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -422,21 +416,6 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configuration classes must be annotated with {@link Configuration @Configuration} or
|
||||
* declare at least one {@link Bean @Bean} method.
|
||||
*/
|
||||
private static class InvalidConfigurationImportProblem extends Problem {
|
||||
|
||||
public InvalidConfigurationImportProblem(String className, Resource resource, AnnotationMetadata metadata) {
|
||||
super(String.format("%s was @Import'ed but is not annotated with @Configuration " +
|
||||
"nor does it declare any @Bean methods; it does not implement ImportSelector " +
|
||||
"or extend ImportBeanDefinitionRegistrar. Update the class to meet one of these requirements " +
|
||||
"or do not attempt to @Import it.", className), new Location(resource, metadata));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate {@code @Conditional} annotations, tracking results and taking into
|
||||
* account 'imported by'.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
|
@ -26,22 +26,23 @@ import java.lang.annotation.Target;
|
|||
* Indicates one or more {@link Configuration @Configuration} classes to import.
|
||||
*
|
||||
* <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML.
|
||||
* Only supported for classes annotated with {@code @Configuration} or declaring at least
|
||||
* one {@link Bean @Bean} method, as well as {@link ImportSelector} and
|
||||
* {@link ImportBeanDefinitionRegistrar} implementations.
|
||||
* Allows for importing {@code @Configuration} classes, {@link ImportSelector} and
|
||||
* {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component
|
||||
* classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
|
||||
*
|
||||
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes
|
||||
* should be accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
|
||||
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
|
||||
* accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
|
||||
* injection. Either the bean itself can be autowired, or the configuration class instance
|
||||
* declaring the bean can be autowired. The latter approach allows for explicit,
|
||||
* IDE-friendly navigation between {@code @Configuration} class methods.
|
||||
* declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
|
||||
* navigation between {@code @Configuration} class methods.
|
||||
*
|
||||
* <p>May be declared at the class level or as a meta-annotation.
|
||||
*
|
||||
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
|
||||
* imported, use {@link ImportResource @ImportResource}
|
||||
* imported, use the {@link ImportResource @ImportResource} annotation instead.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see Configuration
|
||||
* @see ImportSelector
|
||||
|
@ -53,8 +54,9 @@ import java.lang.annotation.Target;
|
|||
public @interface Import {
|
||||
|
||||
/**
|
||||
* The @{@link Configuration}, {@link ImportSelector} and/or
|
||||
* {@link ImportBeanDefinitionRegistrar} classes to import.
|
||||
* @{@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
|
||||
* or regular component classes to import.
|
||||
*/
|
||||
Class<?>[] value();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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,13 +18,13 @@ package org.springframework.context.annotation.configuration;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.tests.sample.beans.ITestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
@ -36,6 +36,7 @@ import static org.junit.Assert.*;
|
|||
* System tests for {@link Import} annotation support.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ImportTests {
|
||||
|
||||
|
@ -52,6 +53,11 @@ public class ImportTests {
|
|||
private void assertBeanDefinitionCount(int expectedCount, Class<?>... classes) {
|
||||
DefaultListableBeanFactory beanFactory = processConfigurationClasses(classes);
|
||||
assertThat(beanFactory.getBeanDefinitionCount(), equalTo(expectedCount));
|
||||
beanFactory.preInstantiateSingletons();
|
||||
for (Class<?> clazz : classes) {
|
||||
beanFactory.getBean(clazz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,7 +124,6 @@ public class ImportTests {
|
|||
public void testImportAnnotationWithTwoLevelRecursion() {
|
||||
int configClasses = 2;
|
||||
int beansInClasses = 3;
|
||||
|
||||
assertBeanDefinitionCount((configClasses + beansInClasses), AppConfig.class);
|
||||
}
|
||||
|
||||
|
@ -149,10 +154,9 @@ public class ImportTests {
|
|||
|
||||
@Test
|
||||
public void testImportAnnotationWithThreeLevelRecursion() {
|
||||
int configClasses = 3;
|
||||
int configClasses = 4;
|
||||
int beansInClasses = 5;
|
||||
|
||||
assertBeanDefinitionCount((configClasses + beansInClasses), FirstLevel.class);
|
||||
assertBeanDefinitionCount(configClasses + beansInClasses, FirstLevel.class);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -161,9 +165,7 @@ public class ImportTests {
|
|||
public void testImportAnnotationWithMultipleArguments() {
|
||||
int configClasses = 3;
|
||||
int beansInClasses = 3;
|
||||
|
||||
assertBeanDefinitionCount((configClasses + beansInClasses),
|
||||
WithMultipleArgumentsToImportAnnotation.class);
|
||||
assertBeanDefinitionCount((configClasses + beansInClasses), WithMultipleArgumentsToImportAnnotation.class);
|
||||
}
|
||||
|
||||
|
||||
|
@ -179,7 +181,7 @@ public class ImportTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@Import( { Foo1.class, Foo2.class })
|
||||
@Import({Foo1.class, Foo2.class})
|
||||
static class WithMultipleArgumentsThatWillCauseDuplication {
|
||||
}
|
||||
|
||||
|
@ -205,7 +207,6 @@ public class ImportTests {
|
|||
public void testImportAnnotationOnInnerClasses() {
|
||||
int configClasses = 2;
|
||||
int beansInClasses = 2;
|
||||
|
||||
assertBeanDefinitionCount((configClasses + beansInClasses), OuterConfig.InnerConfig.class);
|
||||
}
|
||||
|
||||
|
@ -246,7 +247,7 @@ public class ImportTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@Import(ThirdLevel.class)
|
||||
@Import({ThirdLevel.class, InitBean.class})
|
||||
static class SecondLevel {
|
||||
@Bean
|
||||
public TestBean n() {
|
||||
|
@ -255,7 +256,12 @@ public class ImportTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
@DependsOn("org.springframework.context.annotation.configuration.ImportTests$InitBean")
|
||||
static class ThirdLevel {
|
||||
public ThirdLevel() {
|
||||
assertTrue(InitBean.initialized);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ITestBean thirdLevelA() {
|
||||
return new TestBean();
|
||||
|
@ -272,8 +278,16 @@ public class ImportTests {
|
|||
}
|
||||
}
|
||||
|
||||
static class InitBean {
|
||||
public static boolean initialized = false;
|
||||
|
||||
public InitBean() {
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import( { LeftConfig.class, RightConfig.class })
|
||||
@Import({LeftConfig.class, RightConfig.class})
|
||||
static class WithMultipleArgumentsToImportAnnotation {
|
||||
@Bean
|
||||
public TestBean m() {
|
||||
|
@ -299,9 +313,11 @@ public class ImportTests {
|
|||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void testImportNonConfigurationAnnotationClassCausesError() {
|
||||
processConfigurationClasses(ConfigAnnotated.class);
|
||||
@Test
|
||||
public void testImportNonConfigurationAnnotationClass() {
|
||||
int configClasses = 2;
|
||||
int beansInClasses = 0;
|
||||
assertBeanDefinitionCount((configClasses + beansInClasses), ConfigAnnotated.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
|
@ -19,7 +19,6 @@ package org.springframework.context.annotation.configuration;
|
|||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -35,10 +34,10 @@ import static org.junit.Assert.*;
|
|||
* Unit tests cornering the bug exposed in SPR-6779.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ImportedConfigurationClassEnhancementTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void autowiredConfigClassIsEnhancedWhenImported() {
|
||||
autowiredConfigClassIsEnhanced(ConfigThatDoesImport.class);
|
||||
|
@ -77,30 +76,42 @@ public class ImportedConfigurationClassEnhancementTests {
|
|||
}
|
||||
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
@Test
|
||||
public void importingNonConfigurationClassCausesBeanDefinitionParsingException() {
|
||||
new AnnotationConfigApplicationContext(ConfigThatImportsNonConfigClass.class);
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigThatImportsNonConfigClass.class);
|
||||
ConfigThatImportsNonConfigClass config = ctx.getBean(ConfigThatImportsNonConfigClass.class);
|
||||
assertSame(ctx.getBean(TestBean.class), config.testBean);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
class ConfigToBeAutowired {
|
||||
public @Bean TestBean testBean() {
|
||||
return new TestBean();
|
||||
|
||||
|
||||
@Configuration
|
||||
static class ConfigToBeAutowired {
|
||||
|
||||
public @Bean TestBean testBean() {
|
||||
return new TestBean();
|
||||
}
|
||||
}
|
||||
|
||||
static class Config {
|
||||
|
||||
@Autowired ConfigToBeAutowired autowiredConfig;
|
||||
}
|
||||
|
||||
@Import(ConfigToBeAutowired.class)
|
||||
@Configuration
|
||||
static class ConfigThatDoesImport extends Config {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ConfigThatDoesNotImport extends Config {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(TestBean.class)
|
||||
static class ConfigThatImportsNonConfigClass {
|
||||
|
||||
@Autowired TestBean testBean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Config {
|
||||
@Autowired ConfigToBeAutowired autowiredConfig;
|
||||
}
|
||||
|
||||
@Import(ConfigToBeAutowired.class)
|
||||
@Configuration
|
||||
class ConfigThatDoesImport extends Config { }
|
||||
|
||||
@Configuration
|
||||
class ConfigThatDoesNotImport extends Config { }
|
||||
|
||||
@Configuration
|
||||
@Import(TestBean.class)
|
||||
class ConfigThatImportsNonConfigClass { }
|
Loading…
Reference in New Issue