Fix binding of classpath*: to resource arrays and collections
Fixes gh-15835
This commit is contained in:
		
							parent
							
								
									339f75d309
								
							
						
					
					
						commit
						0e3a196af5
					
				|  | @ -1,5 +1,5 @@ | |||
| /* | ||||
|  * Copyright 2012-2022 the original author or authors. | ||||
|  * Copyright 2012-2023 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  | @ -42,6 +42,7 @@ import org.springframework.core.convert.ConverterNotFoundException; | |||
| import org.springframework.core.convert.TypeDescriptor; | ||||
| import org.springframework.core.convert.converter.ConditionalGenericConverter; | ||||
| import org.springframework.core.convert.support.GenericConversionService; | ||||
| import org.springframework.core.io.Resource; | ||||
| import org.springframework.util.CollectionUtils; | ||||
| 
 | ||||
| /** | ||||
|  | @ -154,8 +155,8 @@ final class BindConverter { | |||
| 	private static class TypeConverterConversionService extends GenericConversionService { | ||||
| 
 | ||||
| 		TypeConverterConversionService(Consumer<PropertyEditorRegistry> initializer) { | ||||
| 			addConverter(new TypeConverterConverter(initializer)); | ||||
| 			ApplicationConversionService.addDelimitedStringConverters(this); | ||||
| 			addConverter(new TypeConverterConverter(initializer)); | ||||
| 		} | ||||
| 
 | ||||
| 		@Override | ||||
|  | @ -196,16 +197,23 @@ final class BindConverter { | |||
| 
 | ||||
| 		@Override | ||||
| 		public Set<ConvertiblePair> getConvertibleTypes() { | ||||
| 			return Collections.singleton(new ConvertiblePair(String.class, Object.class)); | ||||
| 			return Set.of(new ConvertiblePair(String.class, Object.class), | ||||
| 					new ConvertiblePair(String.class, Object[].class), | ||||
| 					new ConvertiblePair(String.class, Collection.class)); | ||||
| 		} | ||||
| 
 | ||||
| 		@Override | ||||
| 		public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { | ||||
| 			Class<?> type = targetType.getType(); | ||||
| 			if (type == null || type == Object.class || Collection.class.isAssignableFrom(type) | ||||
| 					|| Map.class.isAssignableFrom(type)) { | ||||
| 			if (type == null || type == Object.class || Map.class.isAssignableFrom(type)) { | ||||
| 				return false; | ||||
| 			} | ||||
| 			if (Collection.class.isAssignableFrom(type)) { | ||||
| 				TypeDescriptor elementType = targetType.getElementTypeDescriptor(); | ||||
| 				if (elementType == null || (!Resource.class.isAssignableFrom(elementType.getType()))) { | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 			PropertyEditor editor = this.matchesOnlyTypeConverter.getDefaultEditor(type); | ||||
| 			if (editor == null) { | ||||
| 				editor = this.matchesOnlyTypeConverter.findCustomEditor(type, null); | ||||
|  | @ -218,7 +226,7 @@ final class BindConverter { | |||
| 
 | ||||
| 		@Override | ||||
| 		public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { | ||||
| 			return createTypeConverter().convertIfNecessary(source, targetType.getType()); | ||||
| 			return createTypeConverter().convertIfNecessary(source, targetType.getType(), targetType); | ||||
| 		} | ||||
| 
 | ||||
| 		private SimpleTypeConverter createTypeConverter() { | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ import java.time.Duration; | |||
| import java.time.Period; | ||||
| import java.time.temporal.ChronoUnit; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedHashMap; | ||||
|  | @ -1173,6 +1174,22 @@ class ConfigurationPropertiesTests { | |||
| 		assertThat(properties.getProp()).isEqualTo("alpha"); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void loadWhenBindingClasspathPatternToResourceArrayShouldBindMultipleValues() { | ||||
| 		load(ResourceArrayPropertiesConfiguration.class, | ||||
| 				"test.resources=classpath*:org/springframework/boot/context/properties/*.class"); | ||||
| 		ResourceArrayProperties properties = this.context.getBean(ResourceArrayProperties.class); | ||||
| 		assertThat(properties.getResources()).hasSizeGreaterThan(1); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void loadWhenBindingClasspathPatternToResourceCollectionShouldBindMultipleValues() { | ||||
| 		load(ResourceCollectionPropertiesConfiguration.class, | ||||
| 				"test.resources=classpath*:org/springframework/boot/context/properties/*.class"); | ||||
| 		ResourceCollectionProperties properties = this.context.getBean(ResourceCollectionProperties.class); | ||||
| 		assertThat(properties.getResources()).hasSizeGreaterThan(1); | ||||
| 	} | ||||
| 
 | ||||
| 	private AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) { | ||||
| 		return load(new Class<?>[] { configuration }, inlinedProperties); | ||||
| 	} | ||||
|  | @ -3058,4 +3075,44 @@ class ConfigurationPropertiesTests { | |||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@EnableConfigurationProperties(ResourceArrayProperties.class) | ||||
| 	static class ResourceArrayPropertiesConfiguration { | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@ConfigurationProperties("test") | ||||
| 	static class ResourceArrayProperties { | ||||
| 
 | ||||
| 		private Resource[] resources; | ||||
| 
 | ||||
| 		Resource[] getResources() { | ||||
| 			return this.resources; | ||||
| 		} | ||||
| 
 | ||||
| 		void setResources(Resource[] resources) { | ||||
| 			this.resources = resources; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@EnableConfigurationProperties(ResourceCollectionProperties.class) | ||||
| 	static class ResourceCollectionPropertiesConfiguration { | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@ConfigurationProperties("test") | ||||
| 	static class ResourceCollectionProperties { | ||||
| 
 | ||||
| 		private Collection<Resource> resources; | ||||
| 
 | ||||
| 		Collection<Resource> getResources() { | ||||
| 			return this.resources; | ||||
| 		} | ||||
| 
 | ||||
| 		void setResources(Collection<Resource> resources) { | ||||
| 			this.resources = resources; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue