Polishing
This commit is contained in:
		
							parent
							
								
									d0a088f9dc
								
							
						
					
					
						commit
						a88d5d1c62
					
				|  | @ -16,13 +16,12 @@ | |||
| 
 | ||||
| package org.springframework.beans.factory.support; | ||||
| 
 | ||||
| import java.lang.reflect.InvocationHandler; | ||||
| import java.lang.reflect.Proxy; | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URI; | ||||
| import java.net.URL; | ||||
| import java.util.AbstractCollection; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.HashMap; | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
|  | @ -49,11 +48,10 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator; | |||
| import org.springframework.core.annotation.Order; | ||||
| import org.springframework.core.io.ClassPathResource; | ||||
| import org.springframework.core.io.UrlResource; | ||||
| import org.springframework.core.testfixture.EnabledForTestGroups; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| import static org.assertj.core.api.Assertions.assertThatExceptionOfType; | ||||
| import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING; | ||||
| import static org.assertj.core.api.Assertions.entry; | ||||
| 
 | ||||
| /** | ||||
|  * @author Juergen Hoeller | ||||
|  | @ -64,41 +62,35 @@ import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING; | |||
| class BeanFactoryGenericsTests { | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetProperty() { | ||||
| 	void genericSetProperty() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Set<String> input = new HashSet<>(); | ||||
| 		input.add("4"); | ||||
| 		input.add("5"); | ||||
| 		rbd.getPropertyValues().add("integerSet", input); | ||||
| 		rbd.getPropertyValues().add("integerSet", Set.of("4", "5")); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericListProperty() throws Exception { | ||||
| 	void genericListProperty() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		List<String> input = new ArrayList<>(); | ||||
| 		input.add("http://localhost:8080"); | ||||
| 		input.add("http://localhost:9090"); | ||||
| 		List<String> input = List.of("http://localhost:8080", "http://localhost:9090"); | ||||
| 		rbd.getPropertyValues().add("resourceList", input); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); | ||||
| 		assertThat(gb.getResourceList().get(1)).isEqualTo(new UrlResource("http://localhost:9090")); | ||||
| 		assertThat(gb.getResourceList()) | ||||
| 				.containsExactly(new UrlResource("http://localhost:8080"), new UrlResource("http://localhost:9090")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericListPropertyWithAutowiring() throws Exception { | ||||
| 	void genericListPropertyWithAutowiring() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); | ||||
| 		bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); | ||||
|  | @ -108,22 +100,19 @@ class BeanFactoryGenericsTests { | |||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericIntegerBean gb = (GenericIntegerBean) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); | ||||
| 		assertThat(gb.getResourceList().get(1)).isEqualTo(new UrlResource("http://localhost:9090")); | ||||
| 		assertThat(gb.getResourceList()) | ||||
| 				.containsExactly(new UrlResource("http://localhost:8080"), new UrlResource("http://localhost:9090")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericListPropertyWithInvalidElementType() { | ||||
| 	void genericListPropertyWithInvalidElementType() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericIntegerBean.class); | ||||
| 
 | ||||
| 		List<Integer> input = new ArrayList<>(); | ||||
| 		input.add(1); | ||||
| 		rbd.getPropertyValues().add("testBeanList", input); | ||||
| 		rbd.getPropertyValues().add("testBeanList", List.of(1)); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> | ||||
| 				bf.getBean("genericBean")) | ||||
| 		assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> bf.getBean("genericBean")) | ||||
| 			.withMessageContaining("genericBean") | ||||
| 			.withMessageContaining("testBeanList[0]") | ||||
| 			.withMessageContaining(TestBean.class.getName()) | ||||
|  | @ -131,7 +120,7 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericListPropertyWithOptionalAutowiring() { | ||||
| 	void genericListPropertyWithOptionalAutowiring() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 
 | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
|  | @ -143,13 +132,13 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapProperty() { | ||||
| 	void genericMapProperty() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Map<String, String> input = new HashMap<>(); | ||||
| 		input.put("4", "5"); | ||||
| 		input.put("6", "7"); | ||||
| 		Map<String, String> input = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getPropertyValues().add("shortMap", input); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
|  | @ -160,39 +149,31 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericListOfArraysProperty() { | ||||
| 	void genericListOfArraysProperty() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions( | ||||
| 				new ClassPathResource("genericBeanTests.xml", getClass())); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("listOfArrays"); | ||||
| 
 | ||||
| 		assertThat(gb.getListOfArrays()).hasSize(1); | ||||
| 		String[] array = gb.getListOfArrays().get(0); | ||||
| 		assertThat(array).hasSize(2); | ||||
| 		assertThat(array[0]).isEqualTo("value1"); | ||||
| 		assertThat(array[1]).isEqualTo("value2"); | ||||
| 		assertThat(gb.getListOfArrays()).containsExactly(new String[] {"value1", "value2"}); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetConstructor() { | ||||
| 	void genericSetConstructor() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Set<String> input = new HashSet<>(); | ||||
| 		input.add("4"); | ||||
| 		input.add("5"); | ||||
| 		Set<String> input = Set.of("4", "5"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetConstructorWithAutowiring() { | ||||
| 	void genericSetConstructorWithAutowiring() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.registerSingleton("integer1", 4); | ||||
| 		bf.registerSingleton("integer2", 5); | ||||
|  | @ -202,12 +183,11 @@ class BeanFactoryGenericsTests { | |||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetConstructorWithOptionalAutowiring() { | ||||
| 	void genericSetConstructorWithOptionalAutowiring() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 
 | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
|  | @ -219,30 +199,25 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetListConstructor() throws Exception { | ||||
| 	void genericSetListConstructor() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Set<String> input = new HashSet<>(); | ||||
| 		input.add("4"); | ||||
| 		input.add("5"); | ||||
| 		List<String> input2 = new ArrayList<>(); | ||||
| 		input2.add("http://localhost:8080"); | ||||
| 		input2.add("http://localhost:9090"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		Set<String> input1 = Set.of("4", "5"); | ||||
| 		List<String> input2 = List.of("http://localhost:8080", "http://localhost:9090"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input1); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); | ||||
| 		assertThat(gb.getResourceList().get(1)).isEqualTo(new UrlResource("http://localhost:9090")); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 		assertThat(gb.getResourceList()) | ||||
| 				.containsExactly(new UrlResource("http://localhost:8080"), new UrlResource("http://localhost:9090")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetListConstructorWithAutowiring() throws Exception { | ||||
| 	void genericSetListConstructorWithAutowiring() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.registerSingleton("integer1", 4); | ||||
| 		bf.registerSingleton("integer2", 5); | ||||
|  | @ -254,14 +229,13 @@ class BeanFactoryGenericsTests { | |||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); | ||||
| 		assertThat(gb.getResourceList().get(1)).isEqualTo(new UrlResource("http://localhost:9090")); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 		assertThat(gb.getResourceList()) | ||||
| 				.containsExactly(new UrlResource("http://localhost:8080"), new UrlResource("http://localhost:9090")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetListConstructorWithOptionalAutowiring() throws Exception { | ||||
| 	void genericSetListConstructorWithOptionalAutowiring() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.registerSingleton("resource1", new UrlResource("http://localhost:8080")); | ||||
| 		bf.registerSingleton("resource2", new UrlResource("http://localhost:9090")); | ||||
|  | @ -276,36 +250,33 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetMapConstructor() { | ||||
| 	void genericSetMapConstructor() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Set<String> input = new HashSet<>(); | ||||
| 		input.add("4"); | ||||
| 		input.add("5"); | ||||
| 		Map<String, String> input2 = new HashMap<>(); | ||||
| 		input2.put("4", "5"); | ||||
| 		input2.put("6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		Set<String> input1 = Set.of("4", "5"); | ||||
| 		Map<String, String> input2 = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input1); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 		assertThat(gb.getShortMap().get(Short.valueOf("4"))).isEqualTo(5); | ||||
| 		assertThat(gb.getShortMap().get(Short.valueOf("6"))).isEqualTo(7); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapResourceConstructor() throws Exception { | ||||
| 	void genericMapResourceConstructor() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Map<String, String> input = new HashMap<>(); | ||||
| 		input.put("4", "5"); | ||||
| 		input.put("6", "7"); | ||||
| 		Map<String, String> input = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue("http://localhost:8080"); | ||||
| 
 | ||||
|  | @ -314,21 +285,21 @@ class BeanFactoryGenericsTests { | |||
| 
 | ||||
| 		assertThat(gb.getShortMap().get(Short.valueOf("4"))).isEqualTo(5); | ||||
| 		assertThat(gb.getShortMap().get(Short.valueOf("6"))).isEqualTo(7); | ||||
| 		assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); | ||||
| 		assertThat(gb.getResourceList()).containsExactly(new UrlResource("http://localhost:8080")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapMapConstructor() { | ||||
| 	void genericMapMapConstructor() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Map<String, String> input = new HashMap<>(); | ||||
| 		input.put("1", "0"); | ||||
| 		input.put("2", "3"); | ||||
| 		Map<String, String> input2 = new HashMap<>(); | ||||
| 		input2.put("4", "5"); | ||||
| 		input2.put("6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		Map<String, String> input1 = Map.of( | ||||
| 				"1", "0", | ||||
| 				"2", "3"); | ||||
| 		Map<String, String> input2 = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input1); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
|  | @ -344,13 +315,13 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapMapConstructorWithSameRefAndConversion() { | ||||
| 	void genericMapMapConstructorWithSameRefAndConversion() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Map<String, String> input = new HashMap<>(); | ||||
| 		input.put("1", "0"); | ||||
| 		input.put("2", "3"); | ||||
| 		Map<String, String> input = Map.of( | ||||
| 				"1", "0", | ||||
| 				"2", "3"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 
 | ||||
|  | @ -367,7 +338,7 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapMapConstructorWithSameRefAndNoConversion() { | ||||
| 	void genericMapMapConstructorWithSameRefAndNoConversion() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
|  | @ -387,13 +358,13 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapWithKeyTypeConstructor() { | ||||
| 	void genericMapWithKeyTypeConstructor() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Map<String, String> input = new HashMap<>(); | ||||
| 		input.put("4", "5"); | ||||
| 		input.put("6", "7"); | ||||
| 		Map<String, String> input = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
|  | @ -404,104 +375,88 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapWithCollectionValueConstructor() { | ||||
| 	void genericMapWithCollectionValueConstructor() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.addPropertyEditorRegistrar(registry -> registry.registerCustomEditor(Number.class, new CustomNumberEditor(Integer.class, false))); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 
 | ||||
| 		Map<String, AbstractCollection<?>> input = new HashMap<>(); | ||||
| 		HashSet<Integer> value1 = new HashSet<>(); | ||||
| 		value1.add(1); | ||||
| 		input.put("1", value1); | ||||
| 		ArrayList<Boolean> value2 = new ArrayList<>(); | ||||
| 		value2.add(Boolean.TRUE); | ||||
| 		input.put("2", value2); | ||||
| 		Map<String, Collection<?>> input = Map.of( | ||||
| 				"1", Set.of(1), | ||||
| 				"2", List.of(Boolean.TRUE)); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getCollectionMap().get(1) instanceof HashSet).isTrue(); | ||||
| 		assertThat(gb.getCollectionMap().get(2) instanceof ArrayList).isTrue(); | ||||
| 		assertThat(gb.getCollectionMap().get(1)).isInstanceOf(Set.class); | ||||
| 		assertThat(gb.getCollectionMap().get(2)).isInstanceOf(List.class); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetFactoryMethod() { | ||||
| 	void genericSetFactoryMethod() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 		rbd.setFactoryMethodName("createInstance"); | ||||
| 
 | ||||
| 		Set<String> input = new HashSet<>(); | ||||
| 		input.add("4"); | ||||
| 		input.add("5"); | ||||
| 		Set<String> input = Set.of("4", "5"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetListFactoryMethod() throws Exception { | ||||
| 	void genericSetListFactoryMethod() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 		rbd.setFactoryMethodName("createInstance"); | ||||
| 
 | ||||
| 		Set<String> input = new HashSet<>(); | ||||
| 		input.add("4"); | ||||
| 		input.add("5"); | ||||
| 		List<String> input2 = new ArrayList<>(); | ||||
| 		input2.add("http://localhost:8080"); | ||||
| 		input2.add("http://localhost:9090"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		Set<String> input1 = Set.of("4", "5"); | ||||
| 		List<String> input2 = List.of("http://localhost:8080", "http://localhost:9090"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input1); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); | ||||
| 		assertThat(gb.getResourceList().get(1)).isEqualTo(new UrlResource("http://localhost:9090")); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 		assertThat(gb.getResourceList()) | ||||
| 				.containsExactly(new UrlResource("http://localhost:8080"), new UrlResource("http://localhost:9090")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetMapFactoryMethod() { | ||||
| 	void genericSetMapFactoryMethod() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 		rbd.setFactoryMethodName("createInstance"); | ||||
| 
 | ||||
| 		Set<String> input = new HashSet<>(); | ||||
| 		input.add("4"); | ||||
| 		input.add("5"); | ||||
| 		Map<String, String> input2 = new HashMap<>(); | ||||
| 		input2.put("4", "5"); | ||||
| 		input2.put("6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		Set<String> input1 = Set.of("4", "5"); | ||||
| 		Map<String, String> input2 = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input1); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getIntegerSet().contains(4)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet().contains(5)).isTrue(); | ||||
| 		assertThat(gb.getIntegerSet()).containsExactlyInAnyOrder(4, 5); | ||||
| 		assertThat(gb.getShortMap().get(Short.valueOf("4"))).isEqualTo(5); | ||||
| 		assertThat(gb.getShortMap().get(Short.valueOf("6"))).isEqualTo(7); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapResourceFactoryMethod() throws Exception { | ||||
| 	void genericMapResourceFactoryMethod() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 		rbd.setFactoryMethodName("createInstance"); | ||||
| 
 | ||||
| 		Map<String, String> input = new HashMap<>(); | ||||
| 		input.put("4", "5"); | ||||
| 		input.put("6", "7"); | ||||
| 		Map<String, String> input = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue("http://localhost:8080"); | ||||
| 
 | ||||
|  | @ -510,22 +465,22 @@ class BeanFactoryGenericsTests { | |||
| 
 | ||||
| 		assertThat(gb.getShortMap().get(Short.valueOf("4"))).isEqualTo(5); | ||||
| 		assertThat(gb.getShortMap().get(Short.valueOf("6"))).isEqualTo(7); | ||||
| 		assertThat(gb.getResourceList().get(0)).isEqualTo(new UrlResource("http://localhost:8080")); | ||||
| 		assertThat(gb.getResourceList()).containsExactly(new UrlResource("http://localhost:8080")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapMapFactoryMethod() { | ||||
| 	void genericMapMapFactoryMethod() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 		rbd.setFactoryMethodName("createInstance"); | ||||
| 
 | ||||
| 		Map<String, String> input = new HashMap<>(); | ||||
| 		input.put("1", "0"); | ||||
| 		input.put("2", "3"); | ||||
| 		Map<String, String> input2 = new HashMap<>(); | ||||
| 		input2.put("4", "5"); | ||||
| 		input2.put("6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 		Map<String, String> input1 = Map.of( | ||||
| 				"1", "0", | ||||
| 				"2", "3"); | ||||
| 		Map<String, String> input2 = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input1); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input2); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
|  | @ -538,14 +493,14 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapWithKeyTypeFactoryMethod() { | ||||
| 	void genericMapWithKeyTypeFactoryMethod() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 		rbd.setFactoryMethodName("createInstance"); | ||||
| 
 | ||||
| 		Map<String, String> input = new HashMap<>(); | ||||
| 		input.put("4", "5"); | ||||
| 		input.put("6", "7"); | ||||
| 		Map<String, String> input = Map.of( | ||||
| 				"4", "5", | ||||
| 				"6", "7"); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
|  | @ -556,62 +511,54 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapWithCollectionValueFactoryMethod() { | ||||
| 	void genericMapWithCollectionValueFactoryMethod() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.addPropertyEditorRegistrar(registry -> registry.registerCustomEditor(Number.class, new CustomNumberEditor(Integer.class, false))); | ||||
| 		RootBeanDefinition rbd = new RootBeanDefinition(GenericBean.class); | ||||
| 		rbd.setFactoryMethodName("createInstance"); | ||||
| 
 | ||||
| 		Map<String, AbstractCollection<?>> input = new HashMap<>(); | ||||
| 		HashSet<Integer> value1 = new HashSet<>(); | ||||
| 		value1.add(1); | ||||
| 		input.put("1", value1); | ||||
| 		ArrayList<Boolean> value2 = new ArrayList<>(); | ||||
| 		value2.add(Boolean.TRUE); | ||||
| 		input.put("2", value2); | ||||
| 		Map<String, Collection<?>> input = Map.of( | ||||
| 				"1", Set.of(1), | ||||
| 				"2", List.of(Boolean.TRUE)); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(Boolean.TRUE); | ||||
| 		rbd.getConstructorArgumentValues().addGenericArgumentValue(input); | ||||
| 
 | ||||
| 		bf.registerBeanDefinition("genericBean", rbd); | ||||
| 		GenericBean<?> gb = (GenericBean<?>) bf.getBean("genericBean"); | ||||
| 
 | ||||
| 		assertThat(gb.getCollectionMap().get(1) instanceof HashSet).isTrue(); | ||||
| 		assertThat(gb.getCollectionMap().get(2) instanceof ArrayList).isTrue(); | ||||
| 		assertThat(gb.getCollectionMap().get(1)).isInstanceOf(Set.class); | ||||
| 		assertThat(gb.getCollectionMap().get(2)).isInstanceOf(List.class); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericListBean() throws Exception { | ||||
| 	void genericListBean() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions( | ||||
| 				new ClassPathResource("genericBeanTests.xml", getClass())); | ||||
| 		List<?> list = (List<?>) bf.getBean("list"); | ||||
| 		assertThat(list).hasSize(1); | ||||
| 		assertThat(list.get(0)).isEqualTo(new URL("http://localhost:8080")); | ||||
| 		NamedUrlList list = bf.getBean("list", NamedUrlList.class); | ||||
| 		assertThat(list).containsExactly(new URL("http://localhost:8080")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericSetBean() throws Exception { | ||||
| 	void genericSetBean() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions( | ||||
| 				new ClassPathResource("genericBeanTests.xml", getClass())); | ||||
| 		Set<?> set = (Set<?>) bf.getBean("set"); | ||||
| 		assertThat(set).hasSize(1); | ||||
| 		assertThat(set.iterator().next()).isEqualTo(new URL("http://localhost:8080")); | ||||
| 		NamedUrlSet set = bf.getBean("set", NamedUrlSet.class); | ||||
| 		assertThat(set).containsExactly(new URL("http://localhost:8080")); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMapBean() throws Exception { | ||||
| 	void genericMapBean() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions( | ||||
| 				new ClassPathResource("genericBeanTests.xml", getClass())); | ||||
| 		Map<?, ?> map = (Map<?, ?>) bf.getBean("map"); | ||||
| 		assertThat(map).hasSize(1); | ||||
| 		assertThat(map.keySet().iterator().next()).isEqualTo(10); | ||||
| 		assertThat(map.values().iterator().next()).isEqualTo(new URL("http://localhost:8080")); | ||||
| 		NamedUrlMap map = bf.getBean("map", NamedUrlMap.class); | ||||
| 		assertThat(map).containsExactly(entry(10, new URL("http://localhost:8080"))); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericallyTypedIntegerBean() { | ||||
| 	void genericallyTypedIntegerBean() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions( | ||||
| 				new ClassPathResource("genericBeanTests.xml", getClass())); | ||||
|  | @ -622,7 +569,7 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericallyTypedSetOfIntegerBean() { | ||||
| 	void genericallyTypedSetOfIntegerBean() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions( | ||||
| 				new ClassPathResource("genericBeanTests.xml", getClass())); | ||||
|  | @ -633,14 +580,12 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	@EnabledForTestGroups(LONG_RUNNING) | ||||
| 	void testSetBean() throws Exception { | ||||
| 	void setBean() throws Exception { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		new XmlBeanDefinitionReader(bf).loadBeanDefinitions( | ||||
| 				new ClassPathResource("genericBeanTests.xml", getClass())); | ||||
| 		UrlSet us = (UrlSet) bf.getBean("setBean"); | ||||
| 		assertThat(us).hasSize(1); | ||||
| 		assertThat(us.iterator().next()).isEqualTo(new URL("https://www.springframework.org")); | ||||
| 		UrlSet urlSet = bf.getBean("setBean", UrlSet.class); | ||||
| 		assertThat(urlSet).containsExactly(new URL("https://www.springframework.org")); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
|  | @ -801,7 +746,7 @@ class BeanFactoryGenericsTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMatchingWithBeanNameDifferentiation() { | ||||
| 	void genericMatchingWithBeanNameDifferentiation() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver()); | ||||
| 
 | ||||
|  | @ -817,15 +762,13 @@ class BeanFactoryGenericsTests { | |||
| 		String[] numberStoreNames = bf.getBeanNamesForType(ResolvableType.forClass(NumberStore.class)); | ||||
| 		String[] doubleStoreNames = bf.getBeanNamesForType(ResolvableType.forClassWithGenerics(NumberStore.class, Double.class)); | ||||
| 		String[] floatStoreNames = bf.getBeanNamesForType(ResolvableType.forClassWithGenerics(NumberStore.class, Float.class)); | ||||
| 		assertThat(numberStoreNames).hasSize(2); | ||||
| 		assertThat(numberStoreNames[0]).isEqualTo("doubleStore"); | ||||
| 		assertThat(numberStoreNames[1]).isEqualTo("floatStore"); | ||||
| 		assertThat(numberStoreNames).containsExactly("doubleStore", "floatStore"); | ||||
| 		assertThat(doubleStoreNames).isEmpty(); | ||||
| 		assertThat(floatStoreNames).isEmpty(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMatchingWithFullTypeDifferentiation() { | ||||
| 	void genericMatchingWithFullTypeDifferentiation() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); | ||||
| 		bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver()); | ||||
|  | @ -846,13 +789,9 @@ class BeanFactoryGenericsTests { | |||
| 		String[] numberStoreNames = bf.getBeanNamesForType(ResolvableType.forClass(NumberStore.class)); | ||||
| 		String[] doubleStoreNames = bf.getBeanNamesForType(ResolvableType.forClassWithGenerics(NumberStore.class, Double.class)); | ||||
| 		String[] floatStoreNames = bf.getBeanNamesForType(ResolvableType.forClassWithGenerics(NumberStore.class, Float.class)); | ||||
| 		assertThat(numberStoreNames).hasSize(2); | ||||
| 		assertThat(numberStoreNames[0]).isEqualTo("store1"); | ||||
| 		assertThat(numberStoreNames[1]).isEqualTo("store2"); | ||||
| 		assertThat(doubleStoreNames).hasSize(1); | ||||
| 		assertThat(doubleStoreNames[0]).isEqualTo("store1"); | ||||
| 		assertThat(floatStoreNames).hasSize(1); | ||||
| 		assertThat(floatStoreNames[0]).isEqualTo("store2"); | ||||
| 		assertThat(numberStoreNames).containsExactly("store1", "store2"); | ||||
| 		assertThat(doubleStoreNames).containsExactly("store1"); | ||||
| 		assertThat(floatStoreNames).containsExactly("store2"); | ||||
| 
 | ||||
| 		ObjectProvider<NumberStore<?>> numberStoreProvider = bf.getBeanProvider(ResolvableType.forClass(NumberStore.class)); | ||||
| 		ObjectProvider<NumberStore<Double>> doubleStoreProvider = bf.getBeanProvider(ResolvableType.forClassWithGenerics(NumberStore.class, Double.class)); | ||||
|  | @ -889,35 +828,29 @@ class BeanFactoryGenericsTests { | |||
| 		for (NumberStore<Double> instance : doubleStoreProvider) { | ||||
| 			resolved.add(instance); | ||||
| 		} | ||||
| 		assertThat(resolved).hasSize(1); | ||||
| 		assertThat(resolved.contains(bf.getBean("store1"))).isTrue(); | ||||
| 		assertThat(resolved).containsExactly(bf.getBean("store1", NumberStore.class)); | ||||
| 
 | ||||
| 		resolved = doubleStoreProvider.stream().collect(Collectors.toList()); | ||||
| 		assertThat(resolved).hasSize(1); | ||||
| 		assertThat(resolved.contains(bf.getBean("store1"))).isTrue(); | ||||
| 		assertThat(resolved).containsExactly(bf.getBean("store1", NumberStore.class)); | ||||
| 
 | ||||
| 		resolved = doubleStoreProvider.orderedStream().collect(Collectors.toList()); | ||||
| 		assertThat(resolved).hasSize(1); | ||||
| 		assertThat(resolved.contains(bf.getBean("store1"))).isTrue(); | ||||
| 		assertThat(resolved).containsExactly(bf.getBean("store1", NumberStore.class)); | ||||
| 
 | ||||
| 		resolved = new ArrayList<>(); | ||||
| 		for (NumberStore<Float> instance : floatStoreProvider) { | ||||
| 			resolved.add(instance); | ||||
| 		} | ||||
| 		assertThat(resolved).hasSize(1); | ||||
| 		assertThat(resolved.contains(bf.getBean("store2"))).isTrue(); | ||||
| 		assertThat(resolved).containsExactly(bf.getBean("store2", NumberStore.class)); | ||||
| 
 | ||||
| 		resolved = floatStoreProvider.stream().collect(Collectors.toList()); | ||||
| 		assertThat(resolved).hasSize(1); | ||||
| 		assertThat(resolved.contains(bf.getBean("store2"))).isTrue(); | ||||
| 		assertThat(resolved).containsExactly(bf.getBean("store2", NumberStore.class)); | ||||
| 
 | ||||
| 		resolved = floatStoreProvider.orderedStream().collect(Collectors.toList()); | ||||
| 		assertThat(resolved).hasSize(1); | ||||
| 		assertThat(resolved.contains(bf.getBean("store2"))).isTrue(); | ||||
| 		assertThat(resolved).containsExactly(bf.getBean("store2", NumberStore.class)); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void testGenericMatchingWithUnresolvedOrderedStream() { | ||||
| 	void genericMatchingWithUnresolvedOrderedStream() { | ||||
| 		DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); | ||||
| 		bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE); | ||||
| 		bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver()); | ||||
|  | @ -999,7 +932,7 @@ class BeanFactoryGenericsTests { | |||
| 		@SuppressWarnings("unchecked") | ||||
| 		public <T> T createMock(Class<T> toMock) { | ||||
| 			return (T) Proxy.newProxyInstance(BeanFactoryGenericsTests.class.getClassLoader(), new Class<?>[] {toMock}, | ||||
| 					(InvocationHandler) (proxy, method, args) -> { | ||||
| 					(proxy, method, args) -> { | ||||
| 						throw new UnsupportedOperationException("mocked!"); | ||||
| 					}); | ||||
| 		} | ||||
|  |  | |||
|  | @ -39,9 +39,7 @@ | |||
| 		<constructor-arg ref="map" /> | ||||
| 	</bean> | ||||
| 
 | ||||
| 	<bean class="org.springframework.beans.factory.support.BeanFactoryGenericsTests$CollectionDependentBean" | ||||
| 			autowire="constructor"> | ||||
| 	</bean> | ||||
| 	<bean class="org.springframework.beans.factory.support.BeanFactoryGenericsTests$CollectionDependentBean" autowire="constructor" /> | ||||
| 
 | ||||
| 	<bean id="integerBean" class="org.springframework.beans.testfixture.beans.GenericIntegerBean"> | ||||
| 		<property name="genericProperty" value="10" /> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue