/* * Copyright 2002-2009 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 static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.Test; import test.beans.ITestBean; import test.beans.TestBean; 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.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.context.annotation.Import; /** * System tests for {@link Import} annotation support. * * @author Chris Beams */ 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)); } @Test public void testProcessImports() { int configClasses = 2; int beansInClasses = 2; assertBeanDefinitionCount((configClasses + beansInClasses), ConfigurationWithImportAnnotation.class); } @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 = 3; 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) static class SecondLevel { @Bean public TestBean n() { return new TestBean(); } } @Configuration static class ThirdLevel { @Bean public ITestBean thirdLevelA() { return new TestBean(); } @Bean public ITestBean thirdLevelB() { return new TestBean(); } @Bean public ITestBean thirdLevelC() { return new TestBean(); } } @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(expected=BeanDefinitionParsingException.class) public void testImportNonConfigurationAnnotationClassCausesError() { processConfigurationClasses(ConfigAnnotated.class); } @Configuration @Import(NonConfigAnnotated.class) static class ConfigAnnotated { } static class NonConfigAnnotated { } }