/* * Copyright 2002-2014 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; import org.junit.Test; import org.springframework.stereotype.Component; import org.springframework.tests.sample.beans.TestBean; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; /** * Tests ensuring that nested static @Configuration classes are automatically detected * and registered without the need for explicit registration or @Import. See SPR-8186. * * @author Chris Beams * @author Juergen Hoeller * @since 3.1 */ public class NestedConfigurationClassTests { @Test public void oneLevelDeep() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(L0Config.L1Config.class); ctx.refresh(); assertFalse(ctx.containsBean("l0Bean")); ctx.getBean(L0Config.L1Config.class); ctx.getBean("l1Bean"); ctx.getBean(L0Config.L1Config.L2Config.class); ctx.getBean("l2Bean"); // ensure that override order is correct assertThat(ctx.getBean("overrideBean", TestBean.class).getName(), is("override-l1")); } @Test public void twoLevelsDeep() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(L0Config.class); ctx.refresh(); assertFalse(ctx.getBeanFactory().containsSingleton("nestedConfigurationClassTests.L0Config")); ctx.getBean(L0Config.class); ctx.getBean("l0Bean"); assertTrue(ctx.getBeanFactory().containsSingleton(L0Config.L1Config.class.getName())); ctx.getBean(L0Config.L1Config.class); ctx.getBean("l1Bean"); assertFalse(ctx.getBeanFactory().containsSingleton(L0Config.L1Config.L2Config.class.getName())); ctx.getBean(L0Config.L1Config.L2Config.class); ctx.getBean("l2Bean"); // ensure that override order is correct assertThat(ctx.getBean("overrideBean", TestBean.class).getName(), is("override-l0")); } @Test public void twoLevelsInLiteMode() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(L0ConfigLight.class); ctx.refresh(); assertFalse(ctx.getBeanFactory().containsSingleton("nestedConfigurationClassTests.L0ConfigLight")); ctx.getBean(L0ConfigLight.class); ctx.getBean("l0Bean"); assertTrue(ctx.getBeanFactory().containsSingleton(L0ConfigLight.L1ConfigLight.class.getName())); ctx.getBean(L0ConfigLight.L1ConfigLight.class); ctx.getBean("l1Bean"); assertFalse(ctx.getBeanFactory().containsSingleton(L0ConfigLight.L1ConfigLight.L2ConfigLight.class.getName())); ctx.getBean(L0ConfigLight.L1ConfigLight.L2ConfigLight.class); ctx.getBean("l2Bean"); // ensure that override order is correct assertThat(ctx.getBean("overrideBean", TestBean.class).getName(), is("override-l0")); } @Test public void twoLevelsDeepWithInheritance() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(S1Config.class); ctx.refresh(); S1Config config = ctx.getBean(S1Config.class); assertTrue(config != ctx.getBean(S1Config.class)); TestBean tb = ctx.getBean("l0Bean", TestBean.class); assertTrue(tb == ctx.getBean("l0Bean", TestBean.class)); ctx.getBean(L0Config.L1Config.class); ctx.getBean("l1Bean"); ctx.getBean(L0Config.L1Config.L2Config.class); ctx.getBean("l2Bean"); // ensure that override order is correct and that it is a singleton TestBean ob = ctx.getBean("overrideBean", TestBean.class); assertThat(ob.getName(), is("override-s1")); assertTrue(ob == ctx.getBean("overrideBean", TestBean.class)); TestBean pb1 = ctx.getBean("prototypeBean", TestBean.class); TestBean pb2 = ctx.getBean("prototypeBean", TestBean.class); assertTrue(pb1 != pb2); assertTrue(pb1.getFriends().iterator().next() != pb2.getFriends().iterator().next()); } @Test public void twoLevelsDeepWithInheritanceThroughImport() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(S1Importer.class); ctx.refresh(); S1Config config = ctx.getBean(S1Config.class); assertTrue(config != ctx.getBean(S1Config.class)); TestBean tb = ctx.getBean("l0Bean", TestBean.class); assertTrue(tb == ctx.getBean("l0Bean", TestBean.class)); ctx.getBean(L0Config.L1Config.class); ctx.getBean("l1Bean"); ctx.getBean(L0Config.L1Config.L2Config.class); ctx.getBean("l2Bean"); // ensure that override order is correct and that it is a singleton TestBean ob = ctx.getBean("overrideBean", TestBean.class); assertThat(ob.getName(), is("override-s1")); assertTrue(ob == ctx.getBean("overrideBean", TestBean.class)); TestBean pb1 = ctx.getBean("prototypeBean", TestBean.class); TestBean pb2 = ctx.getBean("prototypeBean", TestBean.class); assertTrue(pb1 != pb2); assertTrue(pb1.getFriends().iterator().next() != pb2.getFriends().iterator().next()); } @Test public void twoLevelsDeepWithInheritanceAndScopedProxy() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(S1ImporterWithProxy.class); ctx.refresh(); S1ConfigWithProxy config = ctx.getBean(S1ConfigWithProxy.class); assertTrue(config == ctx.getBean(S1ConfigWithProxy.class)); TestBean tb = ctx.getBean("l0Bean", TestBean.class); assertTrue(tb == ctx.getBean("l0Bean", TestBean.class)); ctx.getBean(L0Config.L1Config.class); ctx.getBean("l1Bean"); ctx.getBean(L0Config.L1Config.L2Config.class); ctx.getBean("l2Bean"); // ensure that override order is correct and that it is a singleton TestBean ob = ctx.getBean("overrideBean", TestBean.class); assertThat(ob.getName(), is("override-s1")); assertTrue(ob == ctx.getBean("overrideBean", TestBean.class)); TestBean pb1 = ctx.getBean("prototypeBean", TestBean.class); TestBean pb2 = ctx.getBean("prototypeBean", TestBean.class); assertTrue(pb1 != pb2); assertTrue(pb1.getFriends().iterator().next() != pb2.getFriends().iterator().next()); } @Test public void twoLevelsWithNoBeanMethods() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(L0ConfigEmpty.class); ctx.refresh(); assertFalse(ctx.getBeanFactory().containsSingleton("l0ConfigEmpty")); Object l0i1 = ctx.getBean(L0ConfigEmpty.class); Object l0i2 = ctx.getBean(L0ConfigEmpty.class); assertTrue(l0i1 == l0i2); Object l1i1 = ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.class); Object l1i2 = ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.class); assertTrue(l1i1 != l1i2); Object l2i1 = ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.L2ConfigEmpty.class); Object l2i2 = ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.L2ConfigEmpty.class); assertTrue(l2i1 == l2i2); assertNotEquals(l2i1.toString(), l2i2.toString()); } @Configuration @Lazy static class L0Config { @Bean @Lazy public TestBean l0Bean() { return new TestBean("l0"); } @Bean @Lazy public TestBean overrideBean() { return new TestBean("override-l0"); } @Configuration static class L1Config { @Bean public TestBean l1Bean() { return new TestBean("l1"); } @Bean public TestBean overrideBean() { return new TestBean("override-l1"); } @Configuration @Lazy protected static class L2Config { @Bean @Lazy public TestBean l2Bean() { return new TestBean("l2"); } @Bean @Lazy public TestBean overrideBean() { return new TestBean("override-l2"); } } } } @Component @Lazy static class L0ConfigLight { @Bean @Lazy public TestBean l0Bean() { return new TestBean("l0"); } @Bean @Lazy public TestBean overrideBean() { return new TestBean("override-l0"); } @Component static class L1ConfigLight { @Bean public TestBean l1Bean() { return new TestBean("l1"); } @Bean public TestBean overrideBean() { return new TestBean("override-l1"); } @Component @Lazy protected static class L2ConfigLight { @Bean @Lazy public TestBean l2Bean() { return new TestBean("l2"); } @Bean @Lazy public TestBean overrideBean() { return new TestBean("override-l2"); } } } } @Configuration @Scope("prototype") static class S1Config extends L0Config { @Override @Bean public TestBean overrideBean() { return new TestBean("override-s1"); } @Bean @Scope("prototype") public TestBean prototypeBean() { TestBean tb = new TestBean("override-s1"); tb.getFriends().add(this); return tb; } } @Configuration @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) static class S1ConfigWithProxy extends L0Config { @Override @Bean public TestBean overrideBean() { return new TestBean("override-s1"); } @Bean @Scope("prototype") public TestBean prototypeBean() { TestBean tb = new TestBean("override-s1"); tb.getFriends().add(this); return tb; } } @Import(S1Config.class) static class S1Importer { } @Import(S1ConfigWithProxy.class) static class S1ImporterWithProxy { } @Component @Lazy static class L0ConfigEmpty { @Component @Scope("prototype") static class L1ConfigEmpty { @Component @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) protected static class L2ConfigEmpty { } } } }