1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.context.annotation.configuration;
18
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Set;
23 import javax.inject.Provider;
24
25 import org.junit.Test;
26
27 import org.springframework.beans.factory.BeanClassLoaderAware;
28 import org.springframework.beans.factory.BeanFactory;
29 import org.springframework.beans.factory.FactoryBean;
30 import org.springframework.beans.factory.ListableBeanFactory;
31 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
32 import org.springframework.beans.factory.annotation.Required;
33 import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
34 import org.springframework.beans.factory.annotation.Value;
35 import org.springframework.beans.factory.config.BeanDefinition;
36 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
37 import org.springframework.beans.factory.config.BeanPostProcessor;
38 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
39 import org.springframework.beans.factory.config.ListFactoryBean;
40 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
41 import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
42 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
43 import org.springframework.beans.factory.support.RootBeanDefinition;
44 import org.springframework.context.ApplicationListener;
45 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
46 import org.springframework.context.annotation.AnnotationConfigUtils;
47 import org.springframework.context.annotation.Bean;
48 import org.springframework.context.annotation.Configuration;
49 import org.springframework.context.annotation.ConfigurationClassPostProcessor;
50 import org.springframework.context.annotation.Scope;
51 import org.springframework.context.event.ContextRefreshedEvent;
52 import org.springframework.context.support.GenericApplicationContext;
53 import org.springframework.tests.sample.beans.ITestBean;
54 import org.springframework.tests.sample.beans.TestBean;
55
56 import static org.junit.Assert.*;
57
58
59
60
61
62
63
64
65 public class ConfigurationClassProcessingTests {
66
67
68
69
70
71
72
73
74 private ListableBeanFactory initBeanFactory(Class<?>... configClasses) {
75 DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
76 for (Class<?> configClass : configClasses) {
77 String configBeanName = configClass.getName();
78 factory.registerBeanDefinition(configBeanName, new RootBeanDefinition(configClass));
79 }
80 ConfigurationClassPostProcessor ccpp = new ConfigurationClassPostProcessor();
81 ccpp.postProcessBeanDefinitionRegistry(factory);
82 ccpp.postProcessBeanFactory(factory);
83 RequiredAnnotationBeanPostProcessor rapp = new RequiredAnnotationBeanPostProcessor();
84 rapp.setBeanFactory(factory);
85 factory.addBeanPostProcessor(rapp);
86 factory.freezeConfiguration();
87 return factory;
88 }
89
90
91 @Test
92 public void customBeanNameIsRespected() {
93 GenericApplicationContext ac = new GenericApplicationContext();
94 AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
95 ac.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithBeanWithCustomName.class));
96 ac.refresh();
97 assertSame(ac.getBean("customName"), ConfigWithBeanWithCustomName.testBean);
98
99
100 try {
101 ac.getBean("methodName");
102 fail("bean should not have been registered with 'methodName'");
103 }
104 catch (NoSuchBeanDefinitionException ex) {
105
106 }
107 }
108
109 @Test
110 public void aliasesAreRespected() {
111 BeanFactory factory = initBeanFactory(ConfigWithBeanWithAliases.class);
112 assertSame(factory.getBean("name1"), ConfigWithBeanWithAliases.testBean);
113 String[] aliases = factory.getAliases("name1");
114 for(String alias : aliases)
115 assertSame(factory.getBean(alias), ConfigWithBeanWithAliases.testBean);
116
117
118 try {
119 factory.getBean("methodName");
120 fail("bean should not have been registered with 'methodName'");
121 }
122 catch (NoSuchBeanDefinitionException ex) {
123
124 }
125 }
126
127 @Test
128 public void configWithBeanWithProviderImplementation() {
129 GenericApplicationContext ac = new GenericApplicationContext();
130 AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
131 ac.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithBeanWithProviderImplementation.class));
132 ac.refresh();
133 assertSame(ac.getBean("customName"), ConfigWithBeanWithProviderImplementation.testBean);
134 }
135
136 @Test
137 public void configWithSetWithProviderImplementation() {
138 GenericApplicationContext ac = new GenericApplicationContext();
139 AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
140 ac.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithSetWithProviderImplementation.class));
141 ac.refresh();
142 assertSame(ac.getBean("customName"), ConfigWithSetWithProviderImplementation.set);
143 }
144
145 @Test(expected=BeanDefinitionParsingException.class)
146 public void testFinalBeanMethod() {
147 initBeanFactory(ConfigWithFinalBean.class);
148 }
149
150 @Test
151 public void simplestPossibleConfig() {
152 BeanFactory factory = initBeanFactory(SimplestPossibleConfig.class);
153 String stringBean = factory.getBean("stringBean", String.class);
154 assertEquals(stringBean, "foo");
155 }
156
157 @Test
158 public void configWithObjectReturnType() {
159 BeanFactory factory = initBeanFactory(ConfigWithNonSpecificReturnTypes.class);
160 assertEquals(Object.class, factory.getType("stringBean"));
161 assertFalse(factory.isTypeMatch("stringBean", String.class));
162 String stringBean = factory.getBean("stringBean", String.class);
163 assertEquals(stringBean, "foo");
164 }
165
166 @Test
167 public void configWithFactoryBeanReturnType() {
168 ListableBeanFactory factory = initBeanFactory(ConfigWithNonSpecificReturnTypes.class);
169 assertEquals(List.class, factory.getType("factoryBean"));
170 assertTrue(factory.isTypeMatch("factoryBean", List.class));
171 assertEquals(FactoryBean.class, factory.getType("&factoryBean"));
172 assertTrue(factory.isTypeMatch("&factoryBean", FactoryBean.class));
173 assertFalse(factory.isTypeMatch("&factoryBean", BeanClassLoaderAware.class));
174 assertFalse(factory.isTypeMatch("&factoryBean", ListFactoryBean.class));
175 assertTrue(factory.getBean("factoryBean") instanceof List);
176
177 String[] beanNames = factory.getBeanNamesForType(FactoryBean.class);
178 assertEquals(1, beanNames.length);
179 assertEquals("&factoryBean", beanNames[0]);
180
181 beanNames = factory.getBeanNamesForType(BeanClassLoaderAware.class);
182 assertEquals(1, beanNames.length);
183 assertEquals("&factoryBean", beanNames[0]);
184
185 beanNames = factory.getBeanNamesForType(ListFactoryBean.class);
186 assertEquals(1, beanNames.length);
187 assertEquals("&factoryBean", beanNames[0]);
188
189 beanNames = factory.getBeanNamesForType(List.class);
190 assertEquals("factoryBean", beanNames[0]);
191 }
192
193 @Test
194 public void configurationWithPrototypeScopedBeans() {
195 BeanFactory factory = initBeanFactory(ConfigWithPrototypeBean.class);
196
197 TestBean foo = factory.getBean("foo", TestBean.class);
198 ITestBean bar = factory.getBean("bar", ITestBean.class);
199 ITestBean baz = factory.getBean("baz", ITestBean.class);
200
201 assertSame(foo.getSpouse(), bar);
202 assertNotSame(bar.getSpouse(), baz);
203 }
204
205 @Test
206 public void configurationWithPostProcessor() {
207 AnnotationConfigApplicationContext factory = new AnnotationConfigApplicationContext();
208 factory.register(ConfigWithPostProcessor.class);
209 RootBeanDefinition placeholderConfigurer = new RootBeanDefinition(PropertyPlaceholderConfigurer.class);
210 placeholderConfigurer.getPropertyValues().add("properties", "myProp=myValue");
211 factory.registerBeanDefinition("placeholderConfigurer", placeholderConfigurer);
212 factory.refresh();
213
214 TestBean foo = factory.getBean("foo", TestBean.class);
215 ITestBean bar = factory.getBean("bar", ITestBean.class);
216 ITestBean baz = factory.getBean("baz", ITestBean.class);
217
218 assertEquals("foo-processed-myValue", foo.getName());
219 assertEquals("bar-processed-myValue", bar.getName());
220 assertEquals("baz-processed-myValue", baz.getName());
221
222 SpousyTestBean listener = factory.getBean("listenerTestBean", SpousyTestBean.class);
223 assertTrue(listener.refreshed);
224 }
225
226
227 @Configuration
228 static class ConfigWithBeanWithCustomName {
229
230 static TestBean testBean = new TestBean();
231
232 @Bean(name="customName")
233 public TestBean methodName() {
234 return testBean;
235 }
236 }
237
238
239 @Configuration
240 static class ConfigWithBeanWithAliases {
241
242 static TestBean testBean = new TestBean();
243
244 @Bean(name={"name1", "alias1", "alias2", "alias3"})
245 public TestBean methodName() {
246 return testBean;
247 }
248 }
249
250
251 @Configuration
252 static class ConfigWithBeanWithProviderImplementation implements Provider<TestBean> {
253
254 static TestBean testBean = new TestBean();
255
256 @Bean(name="customName")
257 public TestBean get() {
258 return testBean;
259 }
260 }
261
262
263 @Configuration
264 static class ConfigWithSetWithProviderImplementation implements Provider<Set<String>> {
265
266 static Set<String> set = Collections.singleton("value");
267
268 @Bean(name="customName")
269 public Set<String> get() {
270 return set;
271 }
272 }
273
274
275 @Configuration
276 static class ConfigWithFinalBean {
277
278 public final @Bean TestBean testBean() {
279 return new TestBean();
280 }
281 }
282
283
284 @Configuration
285 static class SimplestPossibleConfig {
286
287 public @Bean String stringBean() {
288 return "foo";
289 }
290 }
291
292
293 @Configuration
294 static class ConfigWithNonSpecificReturnTypes {
295
296 public @Bean Object stringBean() {
297 return "foo";
298 }
299
300 public @Bean FactoryBean<?> factoryBean() {
301 ListFactoryBean fb = new ListFactoryBean();
302 fb.setSourceList(Arrays.asList("element1", "element2"));
303 return fb;
304 }
305 }
306
307
308 @Configuration
309 static class ConfigWithPrototypeBean {
310
311 public @Bean TestBean foo() {
312 TestBean foo = new SpousyTestBean("foo");
313 foo.setSpouse(bar());
314 return foo;
315 }
316
317 public @Bean TestBean bar() {
318 TestBean bar = new SpousyTestBean("bar");
319 bar.setSpouse(baz());
320 return bar;
321 }
322
323 @Bean @Scope("prototype")
324 public TestBean baz() {
325 return new TestBean("baz");
326 }
327 }
328
329
330 @SuppressWarnings("unused")
331 static class ConfigWithPostProcessor extends ConfigWithPrototypeBean {
332
333 @Value("${myProp}")
334 private String myProp;
335
336 @Bean
337 public POBPP beanPostProcessor() {
338 return new POBPP() {
339
340 String nameSuffix = "-processed-" + myProp;
341
342 public void setNameSuffix(String nameSuffix) {
343 this.nameSuffix = nameSuffix;
344 }
345
346 @Override
347 public Object postProcessBeforeInitialization(Object bean, String beanName) {
348 if (bean instanceof ITestBean) {
349 ((ITestBean) bean).setName(((ITestBean) bean).getName() + nameSuffix);
350 }
351 return bean;
352 }
353
354 @Override
355 public Object postProcessAfterInitialization(Object bean, String beanName) {
356 return bean;
357 }
358
359 public int getOrder() {
360 return 0;
361 }
362 };
363 }
364
365
366 public BeanFactoryPostProcessor beanFactoryPostProcessor() {
367 return new BeanFactoryPostProcessor() {
368 @Override
369 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
370 BeanDefinition bd = beanFactory.getBeanDefinition("beanPostProcessor");
371 bd.getPropertyValues().addPropertyValue("nameSuffix", "-processed-" + myProp);
372 }
373 };
374 }
375
376 @Bean
377 public ITestBean listenerTestBean() {
378 return new SpousyTestBean("listener");
379 }
380 }
381
382
383 public interface POBPP extends BeanPostProcessor {
384 }
385
386
387 private static class SpousyTestBean extends TestBean implements ApplicationListener<ContextRefreshedEvent> {
388
389 public boolean refreshed = false;
390
391 public SpousyTestBean(String name) {
392 super(name);
393 }
394
395 @Override
396 @Required
397 public void setSpouse(ITestBean spouse) {
398 super.setSpouse(spouse);
399 }
400
401 @Override
402 public void onApplicationEvent(ContextRefreshedEvent event) {
403 this.refreshed = true;
404 }
405 }
406
407 }