1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.context.annotation;
18
19 import java.io.IOException;
20 import java.lang.annotation.ElementType;
21 import java.lang.annotation.Retention;
22 import java.lang.annotation.RetentionPolicy;
23 import java.lang.annotation.Target;
24 import java.util.HashSet;
25
26 import example.scannable.CustomComponent;
27 import example.scannable.CustomStereotype;
28 import example.scannable.DefaultNamedComponent;
29 import example.scannable.FooService;
30 import example.scannable.MessageBean;
31 import example.scannable.ScopedProxyTestBean;
32 import example.scannable_implicitbasepackage.ComponentScanAnnotatedConfigWithImplicitBasePackage;
33 import example.scannable_scoped.CustomScopeAnnotationBean;
34 import example.scannable_scoped.MyScope;
35 import org.junit.Test;
36
37 import org.springframework.aop.support.AopUtils;
38 import org.springframework.beans.factory.annotation.CustomAutowireConfigurer;
39 import org.springframework.beans.factory.config.BeanDefinition;
40 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
41 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
42 import org.springframework.context.annotation.ComponentScan.Filter;
43 import org.springframework.context.annotation.ComponentScanParserTests.KustomAnnotationAutowiredBean;
44 import org.springframework.context.annotation.componentscan.simple.ClassWithNestedComponents;
45 import org.springframework.context.annotation.componentscan.simple.SimpleComponent;
46 import org.springframework.context.support.GenericApplicationContext;
47 import org.springframework.tests.context.SimpleMapScope;
48 import org.springframework.util.SerializationTestUtils;
49
50 import static org.hamcrest.CoreMatchers.*;
51 import static org.junit.Assert.*;
52 import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
53
54
55
56
57
58
59
60
61
62 @SuppressWarnings("resource")
63 public class ComponentScanAnnotationIntegrationTests {
64
65 @Test
66 public void controlScan() {
67 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
68 ctx.scan(example.scannable._package.class.getPackage().getName());
69 ctx.refresh();
70 assertThat("control scan for example.scannable package failed to register FooServiceImpl bean",
71 ctx.containsBean("fooServiceImpl"), is(true));
72 }
73
74 @Test
75 public void viaContextRegistration() {
76 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
77 ctx.register(ComponentScanAnnotatedConfig.class);
78 ctx.refresh();
79 ctx.getBean(ComponentScanAnnotatedConfig.class);
80 ctx.getBean(TestBean.class);
81 assertThat("config class bean not found", ctx.containsBeanDefinition("componentScanAnnotatedConfig"), is(true));
82 assertThat("@ComponentScan annotated @Configuration class registered directly against " +
83 "AnnotationConfigApplicationContext did not trigger component scanning as expected",
84 ctx.containsBean("fooServiceImpl"), is(true));
85 }
86
87 @Test
88 public void viaContextRegistration_WithValueAttribute() {
89 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
90 ctx.register(ComponentScanAnnotatedConfig_WithValueAttribute.class);
91 ctx.refresh();
92 ctx.getBean(ComponentScanAnnotatedConfig_WithValueAttribute.class);
93 ctx.getBean(TestBean.class);
94 assertThat("config class bean not found", ctx.containsBeanDefinition("componentScanAnnotatedConfig_WithValueAttribute"), is(true));
95 assertThat("@ComponentScan annotated @Configuration class registered directly against " +
96 "AnnotationConfigApplicationContext did not trigger component scanning as expected",
97 ctx.containsBean("fooServiceImpl"), is(true));
98 }
99
100 @Test
101 public void viaContextRegistration_FromPackageOfConfigClass() {
102 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
103 ctx.register(ComponentScanAnnotatedConfigWithImplicitBasePackage.class);
104 ctx.refresh();
105 ctx.getBean(ComponentScanAnnotatedConfigWithImplicitBasePackage.class);
106 assertThat("config class bean not found", ctx.containsBeanDefinition("componentScanAnnotatedConfigWithImplicitBasePackage"), is(true));
107 assertThat("@ComponentScan annotated @Configuration class registered directly against " +
108 "AnnotationConfigApplicationContext did not trigger component scanning as expected",
109 ctx.containsBean("scannedComponent"), is(true));
110 }
111
112 @Test
113 public void viaContextRegistration_WithComposedAnnotation() {
114 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
115 ctx.register(ComposedAnnotationConfig.class);
116 ctx.refresh();
117 ctx.getBean(ComposedAnnotationConfig.class);
118 ctx.getBean(SimpleComponent.class);
119 ctx.getBean(ClassWithNestedComponents.NestedComponent.class);
120 ctx.getBean(ClassWithNestedComponents.OtherNestedComponent.class);
121 assertThat("config class bean not found",
122 ctx.containsBeanDefinition("componentScanAnnotationIntegrationTests.ComposedAnnotationConfig"), is(true));
123 assertThat("@ComponentScan annotated @Configuration class registered directly against " +
124 "AnnotationConfigApplicationContext did not trigger component scanning as expected",
125 ctx.containsBean("simpleComponent"), is(true));
126 }
127
128 @Test
129 public void viaBeanRegistration() {
130 DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
131 bf.registerBeanDefinition("componentScanAnnotatedConfig",
132 genericBeanDefinition(ComponentScanAnnotatedConfig.class).getBeanDefinition());
133 bf.registerBeanDefinition("configurationClassPostProcessor",
134 genericBeanDefinition(ConfigurationClassPostProcessor.class).getBeanDefinition());
135 GenericApplicationContext ctx = new GenericApplicationContext(bf);
136 ctx.refresh();
137 ctx.getBean(ComponentScanAnnotatedConfig.class);
138 ctx.getBean(TestBean.class);
139 assertThat("config class bean not found", ctx.containsBeanDefinition("componentScanAnnotatedConfig"), is(true));
140 assertThat("@ComponentScan annotated @Configuration class registered " +
141 "as bean definition did not trigger component scanning as expected",
142 ctx.containsBean("fooServiceImpl"), is(true));
143 }
144
145 @Test
146 public void withCustomBeanNameGenerator() {
147 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
148 ctx.register(ComponentScanWithBeanNameGenenerator.class);
149 ctx.refresh();
150 assertThat(ctx.containsBean("custom_fooServiceImpl"), is(true));
151 assertThat(ctx.containsBean("fooServiceImpl"), is(false));
152 }
153
154 @Test
155 public void withScopeResolver() {
156 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanWithScopeResolver.class);
157
158
159 assertThat(ctx.getBean(CustomScopeAnnotationBean.class), not(sameInstance(ctx.getBean(CustomScopeAnnotationBean.class))));
160 }
161
162 @Test
163 public void withCustomTypeFilter() {
164 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanWithCustomTypeFilter.class);
165 assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("componentScanParserTests.KustomAnnotationAutowiredBean"));
166 KustomAnnotationAutowiredBean testBean = ctx.getBean("componentScanParserTests.KustomAnnotationAutowiredBean", KustomAnnotationAutowiredBean.class);
167 assertThat(testBean.getDependency(), notNullValue());
168 }
169
170 @Test
171 public void withScopedProxy() throws IOException, ClassNotFoundException {
172 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
173 ctx.register(ComponentScanWithScopedProxy.class);
174 ctx.getBeanFactory().registerScope("myScope", new SimpleMapScope());
175 ctx.refresh();
176
177 FooService bean = (FooService) ctx.getBean("scopedProxyTestBean");
178
179 assertThat(AopUtils.isJdkDynamicProxy(bean), is(true));
180
181 assertThat(bean.foo(1), equalTo("bar"));
182 FooService deserialized = (FooService) SerializationTestUtils.serializeAndDeserialize(bean);
183 assertThat(deserialized, notNullValue());
184 assertThat(deserialized.foo(1), equalTo("bar"));
185 }
186
187 @Test
188 public void withScopedProxyThroughRegex() throws IOException, ClassNotFoundException {
189 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
190 ctx.register(ComponentScanWithScopedProxyThroughRegex.class);
191 ctx.getBeanFactory().registerScope("myScope", new SimpleMapScope());
192 ctx.refresh();
193
194 FooService bean = (FooService) ctx.getBean("scopedProxyTestBean");
195
196 assertThat(AopUtils.isJdkDynamicProxy(bean), is(true));
197 }
198
199 @Test
200 public void withScopedProxyThroughAspectJPattern() throws IOException, ClassNotFoundException {
201 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
202 ctx.register(ComponentScanWithScopedProxyThroughAspectJPattern.class);
203 ctx.getBeanFactory().registerScope("myScope", new SimpleMapScope());
204 ctx.refresh();
205
206 FooService bean = (FooService) ctx.getBean("scopedProxyTestBean");
207
208 assertThat(AopUtils.isJdkDynamicProxy(bean), is(true));
209 }
210
211 @Test
212 public void withMultipleAnnotationIncludeFilters1() throws IOException, ClassNotFoundException {
213 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
214 ctx.register(ComponentScanWithMultipleAnnotationIncludeFilters1.class);
215 ctx.refresh();
216 ctx.getBean(DefaultNamedComponent.class);
217 ctx.getBean(MessageBean.class);
218 }
219
220 @Test
221 public void withMultipleAnnotationIncludeFilters2() throws IOException, ClassNotFoundException {
222 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
223 ctx.register(ComponentScanWithMultipleAnnotationIncludeFilters2.class);
224 ctx.refresh();
225 ctx.getBean(DefaultNamedComponent.class);
226 ctx.getBean(MessageBean.class);
227 }
228
229 @Test
230 public void withBasePackagesAndValueAlias() {
231 AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
232 ctx.register(ComponentScanWithBasePackagesAndValueAlias.class);
233 ctx.refresh();
234 assertThat(ctx.containsBean("fooServiceImpl"), is(true));
235 }
236
237
238 @Configuration
239 @ComponentScan
240 @Retention(RetentionPolicy.RUNTIME)
241 @Target(ElementType.TYPE)
242 public static @interface ComposedConfiguration {
243 String[] basePackages() default {};
244 }
245
246 @ComposedConfiguration(basePackages = "org.springframework.context.annotation.componentscan.simple")
247 public static class ComposedAnnotationConfig {
248 }
249
250 }
251
252
253 @Configuration
254 @ComponentScan(basePackageClasses=example.scannable._package.class)
255 class ComponentScanAnnotatedConfig {
256 @Bean
257 public TestBean testBean() {
258 return new TestBean();
259 }
260 }
261
262 @Configuration
263 @ComponentScan("example.scannable")
264 class ComponentScanAnnotatedConfig_WithValueAttribute {
265 @Bean
266 public TestBean testBean() {
267 return new TestBean();
268 }
269 }
270
271 @Configuration
272 @ComponentScan
273 class ComponentScanWithNoPackagesConfig {}
274
275 @Configuration
276 @ComponentScan(basePackages="example.scannable", nameGenerator=MyBeanNameGenerator.class)
277 class ComponentScanWithBeanNameGenenerator {}
278
279 class MyBeanNameGenerator extends AnnotationBeanNameGenerator {
280 @Override
281 public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
282 return "custom_" + super.generateBeanName(definition, registry);
283 }
284 }
285
286 @Configuration
287 @ComponentScan(basePackages="example.scannable_scoped", scopeResolver=MyScopeMetadataResolver.class)
288 class ComponentScanWithScopeResolver {}
289
290 class MyScopeMetadataResolver extends AnnotationScopeMetadataResolver {
291 MyScopeMetadataResolver() {
292 this.scopeAnnotationType = MyScope.class;
293 }
294 }
295
296 @Configuration
297 @ComponentScan(basePackages="org.springframework.context.annotation",
298 useDefaultFilters=false,
299 includeFilters=@Filter(type=FilterType.CUSTOM, value=ComponentScanParserTests.CustomTypeFilter.class),
300
301 excludeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, value=ComponentScanWithCustomTypeFilter.class),
302 lazyInit = true)
303 class ComponentScanWithCustomTypeFilter {
304 @Bean
305 @SuppressWarnings({ "rawtypes", "serial", "unchecked" })
306 public static CustomAutowireConfigurer customAutowireConfigurer() {
307 CustomAutowireConfigurer cac = new CustomAutowireConfigurer();
308 cac.setCustomQualifierTypes(new HashSet() {{ add(ComponentScanParserTests.CustomAnnotation.class); }});
309 return cac;
310 }
311
312 public ComponentScanParserTests.KustomAnnotationAutowiredBean testBean() {
313 return new ComponentScanParserTests.KustomAnnotationAutowiredBean();
314 }
315 }
316
317 @Configuration
318 @ComponentScan(basePackages="example.scannable",
319 scopedProxy=ScopedProxyMode.INTERFACES,
320 useDefaultFilters=false,
321 includeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, value=ScopedProxyTestBean.class))
322 class ComponentScanWithScopedProxy {}
323
324 @Configuration
325 @ComponentScan(basePackages="example.scannable",
326 scopedProxy=ScopedProxyMode.INTERFACES,
327 useDefaultFilters=false,
328 includeFilters=@Filter(type=FilterType.REGEX, pattern ="((?:[a-z.]+))ScopedProxyTestBean"))
329 class ComponentScanWithScopedProxyThroughRegex {}
330
331 @Configuration
332 @ComponentScan(basePackages="example.scannable",
333 scopedProxy=ScopedProxyMode.INTERFACES,
334 useDefaultFilters=false,
335 includeFilters=@Filter(type=FilterType.ASPECTJ, pattern ="*..ScopedProxyTestBean"))
336 class ComponentScanWithScopedProxyThroughAspectJPattern {}
337
338 @Configuration
339 @ComponentScan(basePackages="example.scannable",
340 useDefaultFilters=false,
341 includeFilters={
342 @Filter(CustomStereotype.class),
343 @Filter(CustomComponent.class)
344 }
345 )
346 class ComponentScanWithMultipleAnnotationIncludeFilters1 {}
347
348 @Configuration
349 @ComponentScan(basePackages="example.scannable",
350 useDefaultFilters=false,
351 includeFilters=@Filter({CustomStereotype.class, CustomComponent.class})
352 )
353 class ComponentScanWithMultipleAnnotationIncludeFilters2 {}
354
355 @Configuration
356 @ComponentScan(
357 value="example.scannable",
358 basePackages="example.scannable",
359 basePackageClasses=example.scannable._package.class)
360 class ComponentScanWithBasePackagesAndValueAlias {}