/* * 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. * You may obtain a copy of the License at * * http://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.configuration; import org.junit.Test; 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; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; /** * System tests for {@link Import} annotation support. * * @author Chris Beams * @author Juergen Hoeller */ public class ImportTests { private DefaultListableBeanFactory processConfigurationClasses(Class<?>... classes) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); for (Class<?> clazz : classes) { beanFactory.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz)); } ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor(); pp.postProcessBeanFactory(beanFactory); return beanFactory; } 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 public void testProcessImportsWithAsm() { int configClasses = 2; int beansInClasses = 2; DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigurationWithImportAnnotation.class.getName())); ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor(); pp.postProcessBeanFactory(beanFactory); assertThat(beanFactory.getBeanDefinitionCount(), equalTo(configClasses + beansInClasses)); } @Test public void testProcessImportsWithDoubleImports() { int configClasses = 3; int beansInClasses = 3; assertBeanDefinitionCount((configClasses + beansInClasses), ConfigurationWithImportAnnotation.class, OtherConfigurationWithImportAnnotation.class); } @Test public void testProcessImportsWithExplicitOverridingBefore() { int configClasses = 2; int beansInClasses = 2; assertBeanDefinitionCount((configClasses + beansInClasses), OtherConfiguration.class, ConfigurationWithImportAnnotation.class); } @Test public void testProcessImportsWithExplicitOverridingAfter() { int configClasses = 2; int beansInClasses = 2; assertBeanDefinitionCount((configClasses + beansInClasses), ConfigurationWithImportAnnotation.class, OtherConfiguration.class); } @Configuration @Import(OtherConfiguration.class) static class ConfigurationWithImportAnnotation { @Bean public ITestBean one() { return new TestBean(); } } @Configuration @Import(OtherConfiguration.class) static class OtherConfigurationWithImportAnnotation { @Bean public ITestBean two() { return new TestBean(); } } @Configuration static class OtherConfiguration { @Bean public ITestBean three() { return new TestBean(); } } // ------------------------------------------------------------------------ @Test public void testImportAnnotationWithTwoLevelRecursion() { int configClasses = 2; int beansInClasses = 3; assertBeanDefinitionCount((configClasses + beansInClasses), AppConfig.class); } @Configuration @Import(DataSourceConfig.class) static class AppConfig { @Bean public ITestBean transferService() { return new TestBean(accountRepository()); } @Bean public ITestBean accountRepository() { return new TestBean(); } } @Configuration static class DataSourceConfig { @Bean public ITestBean dataSourceA() { return new TestBean(); } } // ------------------------------------------------------------------------ @Test public void testImportAnnotationWithThreeLevelRecursion() { int configClasses = 4; int beansInClasses = 5; assertBeanDefinitionCount(configClasses + beansInClasses, FirstLevel.class); } // ------------------------------------------------------------------------ @Test public void testImportAnnotationWithMultipleArguments() { int configClasses = 3; int beansInClasses = 3; assertBeanDefinitionCount((configClasses + beansInClasses), WithMultipleArgumentsToImportAnnotation.class); } @Test public void testImportAnnotationWithMultipleArgumentsResultingInOverriddenBeanDefinition() { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); beanFactory.registerBeanDefinition("config", new RootBeanDefinition( WithMultipleArgumentsThatWillCauseDuplication.class)); ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor(); pp.postProcessBeanFactory(beanFactory); assertThat(beanFactory.getBeanDefinitionCount(), equalTo(4)); assertThat(beanFactory.getBean("foo", ITestBean.class).getName(), equalTo("foo2")); } @Configuration @Import({Foo1.class, Foo2.class}) static class WithMultipleArgumentsThatWillCauseDuplication { } @Configuration static class Foo1 { @Bean public ITestBean foo() { return new TestBean("foo1"); } } @Configuration static class Foo2 { @Bean public ITestBean foo() { return new TestBean("foo2"); } } // ------------------------------------------------------------------------ @Test public void testImportAnnotationOnInnerClasses() { int configClasses = 2; int beansInClasses = 2; assertBeanDefinitionCount((configClasses + beansInClasses), OuterConfig.InnerConfig.class); } @Configuration static class OuterConfig { @Bean String whatev() { return "whatev"; } @Configuration @Import(ExternalConfig.class) static class InnerConfig { @Bean public ITestBean innerBean() { return new TestBean(); } } } @Configuration static class ExternalConfig { @Bean public ITestBean extBean() { return new TestBean(); } } // ------------------------------------------------------------------------ @Configuration @Import(SecondLevel.class) static class FirstLevel { @Bean public TestBean m() { return new TestBean(); } } @Configuration @Import({ThirdLevel.class, InitBean.class}) static class SecondLevel { @Bean public TestBean n() { return new TestBean(); } } @Configuration @DependsOn("org.springframework.context.annotation.configuration.ImportTests$InitBean") static class ThirdLevel { public ThirdLevel() { assertTrue(InitBean.initialized); } @Bean public ITestBean thirdLevelA() { return new TestBean(); } @Bean public ITestBean thirdLevelB() { return new TestBean(); } @Bean public ITestBean thirdLevelC() { return new TestBean(); } } static class InitBean { public static boolean initialized = false; public InitBean() { initialized = true; } } @Configuration @Import({LeftConfig.class, RightConfig.class}) static class WithMultipleArgumentsToImportAnnotation { @Bean public TestBean m() { return new TestBean(); } } @Configuration static class LeftConfig { @Bean public ITestBean left() { return new TestBean(); } } @Configuration static class RightConfig { @Bean public ITestBean right() { return new TestBean(); } } // ------------------------------------------------------------------------ @Test public void testImportNonConfigurationAnnotationClass() { int configClasses = 2; int beansInClasses = 0; assertBeanDefinitionCount((configClasses + beansInClasses), ConfigAnnotated.class); } @Configuration @Import(NonConfigAnnotated.class) static class ConfigAnnotated { } static class NonConfigAnnotated { } // ------------------------------------------------------------------------ /** * Test that values supplied to @Configuration(value="...") are propagated as the * bean name for the configuration class even in the case of inclusion via @Import * or in the case of automatic registration via nesting */ @Test public void reproSpr9023() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(B.class); ctx.refresh(); System.out.println(ctx.getBeanFactory()); assertThat(ctx.getBeanNamesForType(B.class)[0], is("config-b")); assertThat(ctx.getBeanNamesForType(A.class)[0], is("config-a")); } @Configuration("config-a") static class A { } @Configuration("config-b") @Import(A.class) static class B { } @Test public void testProcessImports() { int configClasses = 2; int beansInClasses = 2; assertBeanDefinitionCount((configClasses + beansInClasses), ConfigurationWithImportAnnotation.class); } }