View Javadoc
1   /*
2    * Copyright 2002-2015 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.beans.factory.support;
18  
19  import java.lang.reflect.InvocationHandler;
20  import java.lang.reflect.Method;
21  import java.lang.reflect.Proxy;
22  import java.net.MalformedURLException;
23  import java.net.URI;
24  import java.net.URL;
25  import java.util.AbstractCollection;
26  import java.util.ArrayList;
27  import java.util.HashMap;
28  import java.util.HashSet;
29  import java.util.LinkedList;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  
34  import org.junit.Test;
35  import org.mockito.Mockito;
36  
37  import org.springframework.beans.PropertyEditorRegistrar;
38  import org.springframework.beans.PropertyEditorRegistry;
39  import org.springframework.beans.factory.BeanCreationException;
40  import org.springframework.beans.factory.config.TypedStringValue;
41  import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
42  import org.springframework.beans.propertyeditors.CustomNumberEditor;
43  import org.springframework.core.io.ClassPathResource;
44  import org.springframework.core.io.UrlResource;
45  import org.springframework.tests.Assume;
46  import org.springframework.tests.TestGroup;
47  import org.springframework.tests.sample.beans.GenericBean;
48  import org.springframework.tests.sample.beans.GenericIntegerBean;
49  import org.springframework.tests.sample.beans.GenericSetOfIntegerBean;
50  import org.springframework.tests.sample.beans.TestBean;
51  
52  import static org.junit.Assert.*;
53  
54  /**
55   * @author Juergen Hoeller
56   * @author Chris Beams
57   * @author Sam Brannen
58   * @since 20.01.2006
59   */
60  public class BeanFactoryGenericsTests {
61  
62  	@Test
63  	public void testGenericSetProperty() {
64  		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
65  		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
66  
67  		Set<String> input = new HashSet<String>();
68  		input.add("4");
69  		input.add("5");
70  		rbd.getPropertyValues().add("integerSet", input);
71  
72  		bf.registerBeanDefinition("genericBean", rbd);
73  		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
74  
75  		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
76  		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
77  	}
78  
79  	@Test
80  	public void testGenericListProperty() throws MalformedURLException {
81  		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
82  		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
83  
84  		List<String> input = new ArrayList<String>();
85  		input.add("http://localhost:8080");
86  		input.add("http://localhost:9090");
87  		rbd.getPropertyValues().add("resourceList", input);
88  
89  		bf.registerBeanDefinition("genericBean", rbd);
90  		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
91  
92  		assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0));
93  		assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1));
94  	}
95  
96  	@Test
97  	public void testGenericListPropertyWithAutowiring() throws MalformedURLException {
98  		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
99  		bf.registerSingleton("resource1", new UrlResource("http://localhost:8080"));
100 		bf.registerSingleton("resource2", new UrlResource("http://localhost:9090"));
101 
102 		RootBeanDefinition rbd = new RootBeanDefinition(GenericIntegerBean.class);
103 		rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
104 		bf.registerBeanDefinition("genericBean", rbd);
105 		GenericIntegerBean gb = (GenericIntegerBean) bf.getBean("genericBean");
106 
107 		assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0));
108 		assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1));
109 	}
110 
111 	@Test
112 	public void testGenericListPropertyWithInvalidElementType() {
113 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
114 		RootBeanDefinition rbd = new RootBeanDefinition(GenericIntegerBean.class);
115 
116 		List<Integer> input = new ArrayList<Integer>();
117 		input.add(1);
118 		rbd.getPropertyValues().add("testBeanList", input);
119 
120 		bf.registerBeanDefinition("genericBean", rbd);
121 		try {
122 			bf.getBean("genericBean");
123 			fail("Should have thrown BeanCreationException");
124 		}
125 		catch (BeanCreationException ex) {
126 			assertTrue(ex.getMessage().contains("genericBean") && ex.getMessage().contains("testBeanList[0]"));
127 			assertTrue(ex.getMessage().contains(TestBean.class.getName()) && ex.getMessage().contains("Integer"));
128 		}
129 	}
130 
131 	@Test
132 	public void testGenericListPropertyWithOptionalAutowiring() throws MalformedURLException {
133 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
134 
135 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
136 		rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
137 		bf.registerBeanDefinition("genericBean", rbd);
138 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
139 
140 		assertNull(gb.getResourceList());
141 	}
142 
143 	@Test
144 	public void testGenericMapProperty() {
145 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
146 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
147 
148 		Map<String, String> input = new HashMap<String, String>();
149 		input.put("4", "5");
150 		input.put("6", "7");
151 		rbd.getPropertyValues().add("shortMap", input);
152 
153 		bf.registerBeanDefinition("genericBean", rbd);
154 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
155 
156 		assertEquals(new Integer(5), gb.getShortMap().get(new Short("4")));
157 		assertEquals(new Integer(7), gb.getShortMap().get(new Short("6")));
158 	}
159 
160 	@Test
161 	public void testGenericListOfArraysProperty() throws MalformedURLException {
162 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
163 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
164 				new ClassPathResource("genericBeanTests.xml", getClass()));
165 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("listOfArrays");
166 
167 		assertEquals(1, gb.getListOfArrays().size());
168 		String[] array = gb.getListOfArrays().get(0);
169 		assertEquals(2, array.length);
170 		assertEquals("value1", array[0]);
171 		assertEquals("value2", array[1]);
172 	}
173 
174 
175 	@Test
176 	public void testGenericSetConstructor() {
177 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
178 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
179 
180 		Set<String> input = new HashSet<String>();
181 		input.add("4");
182 		input.add("5");
183 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
184 
185 		bf.registerBeanDefinition("genericBean", rbd);
186 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
187 
188 		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
189 		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
190 	}
191 
192 	@Test
193 	public void testGenericSetConstructorWithAutowiring() {
194 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
195 		bf.registerSingleton("integer1", new Integer(4));
196 		bf.registerSingleton("integer2", new Integer(5));
197 
198 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
199 		rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
200 		bf.registerBeanDefinition("genericBean", rbd);
201 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
202 
203 		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
204 		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
205 	}
206 
207 	@Test
208 	public void testGenericSetConstructorWithOptionalAutowiring() {
209 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
210 
211 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
212 		rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
213 		bf.registerBeanDefinition("genericBean", rbd);
214 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
215 
216 		assertNull(gb.getIntegerSet());
217 	}
218 
219 	@Test
220 	public void testGenericSetListConstructor() throws MalformedURLException {
221 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
222 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
223 
224 		Set<String> input = new HashSet<String>();
225 		input.add("4");
226 		input.add("5");
227 		List<String> input2 = new ArrayList<String>();
228 		input2.add("http://localhost:8080");
229 		input2.add("http://localhost:9090");
230 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
231 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2);
232 
233 		bf.registerBeanDefinition("genericBean", rbd);
234 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
235 
236 		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
237 		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
238 		assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0));
239 		assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1));
240 	}
241 
242 	@Test
243 	public void testGenericSetListConstructorWithAutowiring() throws MalformedURLException {
244 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
245 		bf.registerSingleton("integer1", new Integer(4));
246 		bf.registerSingleton("integer2", new Integer(5));
247 		bf.registerSingleton("resource1", new UrlResource("http://localhost:8080"));
248 		bf.registerSingleton("resource2", new UrlResource("http://localhost:9090"));
249 
250 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
251 		rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
252 		bf.registerBeanDefinition("genericBean", rbd);
253 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
254 
255 		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
256 		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
257 		assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0));
258 		assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1));
259 	}
260 
261 	@Test
262 	public void testGenericSetListConstructorWithOptionalAutowiring() throws MalformedURLException {
263 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
264 		bf.registerSingleton("resource1", new UrlResource("http://localhost:8080"));
265 		bf.registerSingleton("resource2", new UrlResource("http://localhost:9090"));
266 
267 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
268 		rbd.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
269 		bf.registerBeanDefinition("genericBean", rbd);
270 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
271 
272 		assertNull(gb.getIntegerSet());
273 		assertNull(gb.getResourceList());
274 	}
275 
276 	@Test
277 	public void testGenericSetMapConstructor() throws MalformedURLException {
278 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
279 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
280 
281 		Set<String> input = new HashSet<String>();
282 		input.add("4");
283 		input.add("5");
284 		Map<String, String> input2 = new HashMap<String, String>();
285 		input2.put("4", "5");
286 		input2.put("6", "7");
287 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
288 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2);
289 
290 		bf.registerBeanDefinition("genericBean", rbd);
291 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
292 
293 		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
294 		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
295 		assertEquals(new Integer(5), gb.getShortMap().get(new Short("4")));
296 		assertEquals(new Integer(7), gb.getShortMap().get(new Short("6")));
297 	}
298 
299 	@Test
300 	public void testGenericMapResourceConstructor() throws MalformedURLException {
301 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
302 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
303 
304 		Map<String, String> input = new HashMap<String, String>();
305 		input.put("4", "5");
306 		input.put("6", "7");
307 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
308 		rbd.getConstructorArgumentValues().addGenericArgumentValue("http://localhost:8080");
309 
310 		bf.registerBeanDefinition("genericBean", rbd);
311 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
312 
313 		assertEquals(new Integer(5), gb.getShortMap().get(new Short("4")));
314 		assertEquals(new Integer(7), gb.getShortMap().get(new Short("6")));
315 		assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0));
316 	}
317 
318 	@Test
319 	public void testGenericMapMapConstructor() throws MalformedURLException {
320 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
321 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
322 
323 		Map<String, String> input = new HashMap<String, String>();
324 		input.put("1", "0");
325 		input.put("2", "3");
326 		Map<String, String> input2 = new HashMap<String, String>();
327 		input2.put("4", "5");
328 		input2.put("6", "7");
329 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
330 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2);
331 
332 		bf.registerBeanDefinition("genericBean", rbd);
333 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
334 
335 		assertNotSame(gb.getPlainMap(), gb.getShortMap());
336 		assertEquals(2, gb.getPlainMap().size());
337 		assertEquals("0", gb.getPlainMap().get("1"));
338 		assertEquals("3", gb.getPlainMap().get("2"));
339 		assertEquals(2, gb.getShortMap().size());
340 		assertEquals(new Integer(5), gb.getShortMap().get(new Short("4")));
341 		assertEquals(new Integer(7), gb.getShortMap().get(new Short("6")));
342 	}
343 
344 	@Test
345 	public void testGenericMapMapConstructorWithSameRefAndConversion() throws MalformedURLException {
346 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
347 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
348 
349 		Map<String, String> input = new HashMap<String, String>();
350 		input.put("1", "0");
351 		input.put("2", "3");
352 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
353 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
354 
355 		bf.registerBeanDefinition("genericBean", rbd);
356 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
357 
358 		assertNotSame(gb.getPlainMap(), gb.getShortMap());
359 		assertEquals(2, gb.getPlainMap().size());
360 		assertEquals("0", gb.getPlainMap().get("1"));
361 		assertEquals("3", gb.getPlainMap().get("2"));
362 		assertEquals(2, gb.getShortMap().size());
363 		assertEquals(new Integer(0), gb.getShortMap().get(new Short("1")));
364 		assertEquals(new Integer(3), gb.getShortMap().get(new Short("2")));
365 	}
366 
367 	@Test
368 	public void testGenericMapMapConstructorWithSameRefAndNoConversion() throws MalformedURLException {
369 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
370 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
371 
372 		Map<Short, Integer> input = new HashMap<Short, Integer>();
373 		input.put(new Short((short) 1), new Integer(0));
374 		input.put(new Short((short) 2), new Integer(3));
375 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
376 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
377 
378 		bf.registerBeanDefinition("genericBean", rbd);
379 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
380 
381 		assertSame(gb.getPlainMap(), gb.getShortMap());
382 		assertEquals(2, gb.getShortMap().size());
383 		assertEquals(new Integer(0), gb.getShortMap().get(new Short("1")));
384 		assertEquals(new Integer(3), gb.getShortMap().get(new Short("2")));
385 	}
386 
387 	@Test
388 	public void testGenericMapWithKeyTypeConstructor() throws MalformedURLException {
389 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
390 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
391 
392 		Map<String, String> input = new HashMap<String, String>();
393 		input.put("4", "5");
394 		input.put("6", "7");
395 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
396 
397 		bf.registerBeanDefinition("genericBean", rbd);
398 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
399 
400 		assertEquals("5", gb.getLongMap().get(new Long("4")));
401 		assertEquals("7", gb.getLongMap().get(new Long("6")));
402 	}
403 
404 	@Test
405 	public void testGenericMapWithCollectionValueConstructor() throws MalformedURLException {
406 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
407 		bf.addPropertyEditorRegistrar(new PropertyEditorRegistrar() {
408 			@Override
409 			public void registerCustomEditors(PropertyEditorRegistry registry) {
410 				registry.registerCustomEditor(Number.class, new CustomNumberEditor(Integer.class, false));
411 			}
412 		});
413 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
414 
415 		Map<String, AbstractCollection<?>> input = new HashMap<String, AbstractCollection<?>>();
416 		HashSet<Integer> value1 = new HashSet<Integer>();
417 		value1.add(new Integer(1));
418 		input.put("1", value1);
419 		ArrayList<Boolean> value2 = new ArrayList<Boolean>();
420 		value2.add(Boolean.TRUE);
421 		input.put("2", value2);
422 		rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE);
423 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
424 
425 		bf.registerBeanDefinition("genericBean", rbd);
426 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
427 
428 		assertTrue(gb.getCollectionMap().get(new Integer(1)) instanceof HashSet);
429 		assertTrue(gb.getCollectionMap().get(new Integer(2)) instanceof ArrayList);
430 	}
431 
432 
433 	@Test
434 	public void testGenericSetFactoryMethod() {
435 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
436 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
437 		rbd.setFactoryMethodName("createInstance");
438 
439 		Set<String> input = new HashSet<String>();
440 		input.add("4");
441 		input.add("5");
442 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
443 
444 		bf.registerBeanDefinition("genericBean", rbd);
445 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
446 
447 		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
448 		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
449 	}
450 
451 	@Test
452 	public void testGenericSetListFactoryMethod() throws MalformedURLException {
453 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
454 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
455 		rbd.setFactoryMethodName("createInstance");
456 
457 		Set<String> input = new HashSet<String>();
458 		input.add("4");
459 		input.add("5");
460 		List<String> input2 = new ArrayList<String>();
461 		input2.add("http://localhost:8080");
462 		input2.add("http://localhost:9090");
463 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
464 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2);
465 
466 		bf.registerBeanDefinition("genericBean", rbd);
467 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
468 
469 		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
470 		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
471 		assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0));
472 		assertEquals(new UrlResource("http://localhost:9090"), gb.getResourceList().get(1));
473 	}
474 
475 	@Test
476 	public void testGenericSetMapFactoryMethod() throws MalformedURLException {
477 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
478 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
479 		rbd.setFactoryMethodName("createInstance");
480 
481 		Set<String> input = new HashSet<String>();
482 		input.add("4");
483 		input.add("5");
484 		Map<String, String> input2 = new HashMap<String, String>();
485 		input2.put("4", "5");
486 		input2.put("6", "7");
487 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
488 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2);
489 
490 		bf.registerBeanDefinition("genericBean", rbd);
491 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
492 
493 		assertTrue(gb.getIntegerSet().contains(new Integer(4)));
494 		assertTrue(gb.getIntegerSet().contains(new Integer(5)));
495 		assertEquals(new Integer(5), gb.getShortMap().get(new Short("4")));
496 		assertEquals(new Integer(7), gb.getShortMap().get(new Short("6")));
497 	}
498 
499 	@Test
500 	public void testGenericMapResourceFactoryMethod() throws MalformedURLException {
501 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
502 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
503 		rbd.setFactoryMethodName("createInstance");
504 
505 		Map<String, String> input = new HashMap<String, String>();
506 		input.put("4", "5");
507 		input.put("6", "7");
508 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
509 		rbd.getConstructorArgumentValues().addGenericArgumentValue("http://localhost:8080");
510 
511 		bf.registerBeanDefinition("genericBean", rbd);
512 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
513 
514 		assertEquals(new Integer(5), gb.getShortMap().get(new Short("4")));
515 		assertEquals(new Integer(7), gb.getShortMap().get(new Short("6")));
516 		assertEquals(new UrlResource("http://localhost:8080"), gb.getResourceList().get(0));
517 	}
518 
519 	@Test
520 	public void testGenericMapMapFactoryMethod() throws MalformedURLException {
521 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
522 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
523 		rbd.setFactoryMethodName("createInstance");
524 
525 		Map<String, String> input = new HashMap<String, String>();
526 		input.put("1", "0");
527 		input.put("2", "3");
528 		Map<String, String> input2 = new HashMap<String, String>();
529 		input2.put("4", "5");
530 		input2.put("6", "7");
531 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
532 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2);
533 
534 		bf.registerBeanDefinition("genericBean", rbd);
535 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
536 
537 		assertEquals("0", gb.getPlainMap().get("1"));
538 		assertEquals("3", gb.getPlainMap().get("2"));
539 		assertEquals(new Integer(5), gb.getShortMap().get(new Short("4")));
540 		assertEquals(new Integer(7), gb.getShortMap().get(new Short("6")));
541 	}
542 
543 	@Test
544 	public void testGenericMapWithKeyTypeFactoryMethod() throws MalformedURLException {
545 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
546 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
547 		rbd.setFactoryMethodName("createInstance");
548 
549 		Map<String, String> input = new HashMap<String, String>();
550 		input.put("4", "5");
551 		input.put("6", "7");
552 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
553 
554 		bf.registerBeanDefinition("genericBean", rbd);
555 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
556 
557 		assertEquals("5", gb.getLongMap().get(new Long("4")));
558 		assertEquals("7", gb.getLongMap().get(new Long("6")));
559 	}
560 
561 	@Test
562 	public void testGenericMapWithCollectionValueFactoryMethod() throws MalformedURLException {
563 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
564 		bf.addPropertyEditorRegistrar(new PropertyEditorRegistrar() {
565 			@Override
566 			public void registerCustomEditors(PropertyEditorRegistry registry) {
567 				registry.registerCustomEditor(Number.class, new CustomNumberEditor(Integer.class, false));
568 			}
569 		});
570 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class);
571 		rbd.setFactoryMethodName("createInstance");
572 
573 		Map<String, AbstractCollection<?>> input = new HashMap<String, AbstractCollection<?>>();
574 		HashSet<Integer> value1 = new HashSet<Integer>();
575 		value1.add(new Integer(1));
576 		input.put("1", value1);
577 		ArrayList<Boolean> value2 = new ArrayList<Boolean>();
578 		value2.add(Boolean.TRUE);
579 		input.put("2", value2);
580 		rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE);
581 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input);
582 
583 		bf.registerBeanDefinition("genericBean", rbd);
584 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean");
585 
586 		assertTrue(gb.getCollectionMap().get(new Integer(1)) instanceof HashSet);
587 		assertTrue(gb.getCollectionMap().get(new Integer(2)) instanceof ArrayList);
588 	}
589 
590 	@Test
591 	public void testGenericListBean() throws Exception {
592 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
593 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
594 				new ClassPathResource("genericBeanTests.xml", getClass()));
595 		List<?> list = (List<?>) bf.getBean("list");
596 		assertEquals(1, list.size());
597 		assertEquals(new URL("http://localhost:8080"), list.get(0));
598 	}
599 
600 	@Test
601 	public void testGenericSetBean() throws Exception {
602 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
603 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
604 				new ClassPathResource("genericBeanTests.xml", getClass()));
605 		Set<?> set = (Set<?>) bf.getBean("set");
606 		assertEquals(1, set.size());
607 		assertEquals(new URL("http://localhost:8080"), set.iterator().next());
608 	}
609 
610 	@Test
611 	public void testGenericMapBean() throws Exception {
612 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
613 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
614 				new ClassPathResource("genericBeanTests.xml", getClass()));
615 		Map<?, ?> map = (Map<?, ?>) bf.getBean("map");
616 		assertEquals(1, map.size());
617 		assertEquals(new Integer(10), map.keySet().iterator().next());
618 		assertEquals(new URL("http://localhost:8080"), map.values().iterator().next());
619 	}
620 
621 	@Test
622 	public void testGenericallyTypedIntegerBean() throws Exception {
623 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
624 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
625 				new ClassPathResource("genericBeanTests.xml", getClass()));
626 		GenericIntegerBean gb = (GenericIntegerBean) bf.getBean("integerBean");
627 		assertEquals(new Integer(10), gb.getGenericProperty());
628 		assertEquals(new Integer(20), gb.getGenericListProperty().get(0));
629 		assertEquals(new Integer(30), gb.getGenericListProperty().get(1));
630 	}
631 
632 	@Test
633 	public void testGenericallyTypedSetOfIntegerBean() throws Exception {
634 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
635 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
636 				new ClassPathResource("genericBeanTests.xml", getClass()));
637 		GenericSetOfIntegerBean gb = (GenericSetOfIntegerBean) bf.getBean("setOfIntegerBean");
638 		assertEquals(new Integer(10), gb.getGenericProperty().iterator().next());
639 		assertEquals(new Integer(20), gb.getGenericListProperty().get(0).iterator().next());
640 		assertEquals(new Integer(30), gb.getGenericListProperty().get(1).iterator().next());
641 	}
642 
643 	@Test
644 	public void testSetBean() throws Exception {
645 		Assume.group(TestGroup.LONG_RUNNING);
646 
647 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
648 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
649 				new ClassPathResource("genericBeanTests.xml", getClass()));
650 		UrlSet us = (UrlSet) bf.getBean("setBean");
651 		assertEquals(1, us.size());
652 		assertEquals(new URL("http://www.springframework.org"), us.iterator().next());
653 	}
654 
655 	/**
656 	 * Tests support for parameterized static {@code factory-method} declarations such as
657 	 * Mockito's {@code mock()} method which has the following signature.
658 	 * <pre>
659 	 * {@code
660 	 * public static <T> T mock(Class<T> classToMock)
661 	 * }
662 	 * </pre>
663 	 * <p>See SPR-9493
664 	 */
665 	@Test
666 	public void parameterizedStaticFactoryMethod() {
667 		RootBeanDefinition rbd = new RootBeanDefinition(Mockito.class);
668 		rbd.setFactoryMethodName("mock");
669 		rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
670 
671 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
672 		bf.registerBeanDefinition("mock", rbd);
673 
674 		Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
675 		assertEquals(1, beans.size());
676 	}
677 
678 	/**
679 	 * Tests support for parameterized instance {@code factory-method} declarations such
680 	 * as EasyMock's {@code IMocksControl.createMock()} method which has the following
681 	 * signature.
682 	 * <pre>
683 	 * {@code
684 	 * public <T> T createMock(Class<T> toMock)
685 	 * }
686 	 * </pre>
687 	 * <p>See SPR-10411
688 	 */
689 	@Test
690 	public void parameterizedInstanceFactoryMethod() {
691 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
692 
693 		RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
694 		bf.registerBeanDefinition("mocksControl", rbd);
695 
696 		rbd = new RootBeanDefinition();
697 		rbd.setFactoryBeanName("mocksControl");
698 		rbd.setFactoryMethodName("createMock");
699 		rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
700 		bf.registerBeanDefinition("mock", rbd);
701 
702 		Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
703 		assertEquals(1, beans.size());
704 	}
705 
706 	@Test
707 	public void parameterizedInstanceFactoryMethodWithNonResolvedClassName() {
708 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
709 
710 		RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
711 		bf.registerBeanDefinition("mocksControl", rbd);
712 
713 		rbd = new RootBeanDefinition();
714 		rbd.setFactoryBeanName("mocksControl");
715 		rbd.setFactoryMethodName("createMock");
716 		rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class.getName());
717 		bf.registerBeanDefinition("mock", rbd);
718 
719 		Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
720 		assertEquals(1, beans.size());
721 	}
722 
723 	@Test
724 	public void parameterizedInstanceFactoryMethodWithWrappedClassName() {
725 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
726 
727 		RootBeanDefinition rbd = new RootBeanDefinition();
728 		rbd.setBeanClassName(Mockito.class.getName());
729 		rbd.setFactoryMethodName("mock");
730 		// TypedStringValue used to be equivalent to an XML-defined argument String
731 		rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Runnable.class.getName()));
732 		bf.registerBeanDefinition("mock", rbd);
733 
734 		Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
735 		assertEquals(1, beans.size());
736 	}
737 
738 	@Test
739 	public void parameterizedInstanceFactoryMethodWithInvalidClassName() {
740 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
741 
742 		RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
743 		bf.registerBeanDefinition("mocksControl", rbd);
744 
745 		rbd = new RootBeanDefinition();
746 		rbd.setFactoryBeanName("mocksControl");
747 		rbd.setFactoryMethodName("createMock");
748 		rbd.getConstructorArgumentValues().addGenericArgumentValue("x");
749 		bf.registerBeanDefinition("mock", rbd);
750 
751 		Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
752 		assertEquals(0, beans.size());
753 	}
754 
755 	@Test
756 	public void parameterizedInstanceFactoryMethodWithIndexedArgument() {
757 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
758 
759 		RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
760 		bf.registerBeanDefinition("mocksControl", rbd);
761 
762 		rbd = new RootBeanDefinition();
763 		rbd.setFactoryBeanName("mocksControl");
764 		rbd.setFactoryMethodName("createMock");
765 		rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, Runnable.class);
766 		bf.registerBeanDefinition("mock", rbd);
767 
768 		Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
769 		assertEquals(1, beans.size());
770 	}
771 
772 	@Test
773 	public void testGenericMatchingWithBeanNameDifferentiation() {
774 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
775 		bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
776 
777 		bf.registerBeanDefinition("doubleStore", new RootBeanDefinition(NumberStore.class));
778 		bf.registerBeanDefinition("floatStore", new RootBeanDefinition(NumberStore.class));
779 		bf.registerBeanDefinition("numberBean",
780 				new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
781 
782 		NumberBean nb = bf.getBean(NumberBean.class);
783 		assertSame(bf.getBean("doubleStore"), nb.getDoubleStore());
784 		assertSame(bf.getBean("floatStore"), nb.getFloatStore());
785 	}
786 
787 	@Test
788 	public void testGenericMatchingWithFullTypeDifferentiation() {
789 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
790 		bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
791 
792 		bf.registerBeanDefinition("store1", new RootBeanDefinition(DoubleStore.class));
793 		bf.registerBeanDefinition("store2", new RootBeanDefinition(FloatStore.class));
794 		bf.registerBeanDefinition("numberBean",
795 				new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
796 
797 		NumberBean nb = bf.getBean(NumberBean.class);
798 		assertSame(bf.getBean("store1"), nb.getDoubleStore());
799 		assertSame(bf.getBean("store2"), nb.getFloatStore());
800 	}
801 
802 
803 	@SuppressWarnings("serial")
804 	public static class NamedUrlList extends LinkedList<URL> {
805 	}
806 
807 
808 	@SuppressWarnings("serial")
809 	public static class NamedUrlSet extends HashSet<URL> {
810 	}
811 
812 
813 	@SuppressWarnings("serial")
814 	public static class NamedUrlMap extends HashMap<Integer, URL> {
815 	}
816 
817 
818 	public static class CollectionDependentBean {
819 
820 		public CollectionDependentBean(NamedUrlList list, NamedUrlSet set, NamedUrlMap map) {
821 			assertEquals(1, list.size());
822 			assertEquals(1, set.size());
823 			assertEquals(1, map.size());
824 		}
825 	}
826 
827 
828 	@SuppressWarnings("serial")
829 	public static class UrlSet extends HashSet<URL> {
830 
831 		public UrlSet() {
832 			super();
833 		}
834 
835 		public UrlSet(Set<? extends URL> urls) {
836 			super();
837 		}
838 
839 		public void setUrlNames(Set<URI> urlNames) throws MalformedURLException {
840 			for (URI urlName : urlNames) {
841 				add(urlName.toURL());
842 			}
843 		}
844 	}
845 
846 
847 	/**
848 	 * Pseudo-implementation of EasyMock's {@code MocksControl} class.
849 	 */
850 	public static class MocksControl {
851 
852 		@SuppressWarnings("unchecked")
853 		public <T> T createMock(Class<T> toMock) {
854 			return (T) Proxy.newProxyInstance(BeanFactoryGenericsTests.class.getClassLoader(), new Class<?>[] {toMock},
855 					new InvocationHandler() {
856 						@Override
857 						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
858 							throw new UnsupportedOperationException("mocked!");
859 						}
860 					});
861 		}
862 	}
863 
864 
865 	public static class NumberStore<T extends Number> {
866 	}
867 
868 
869 	public static class DoubleStore extends NumberStore<Double> {
870 	}
871 
872 
873 	public static class FloatStore extends NumberStore<Float> {
874 	}
875 
876 
877 	public static class NumberBean {
878 
879 		private final NumberStore<Double> doubleStore;
880 
881 		private final NumberStore<Float> floatStore;
882 
883 		public NumberBean(NumberStore<Double> doubleStore, NumberStore<Float> floatStore) {
884 			this.doubleStore = doubleStore;
885 			this.floatStore = floatStore;
886 		}
887 
888 		public NumberStore<Double> getDoubleStore() {
889 			return this.doubleStore;
890 		}
891 
892 		public NumberStore<Float> getFloatStore() {
893 			return this.floatStore;
894 		}
895 	}
896 
897 }