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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.TypeDescriptor;
|
||||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||||
import org.springframework.core.convert.support.GenericConversionService;
|
import org.springframework.core.convert.support.GenericConversionService;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,8 +155,8 @@ final class BindConverter {
|
||||||
private static class TypeConverterConversionService extends GenericConversionService {
|
private static class TypeConverterConversionService extends GenericConversionService {
|
||||||
|
|
||||||
TypeConverterConversionService(Consumer<PropertyEditorRegistry> initializer) {
|
TypeConverterConversionService(Consumer<PropertyEditorRegistry> initializer) {
|
||||||
addConverter(new TypeConverterConverter(initializer));
|
|
||||||
ApplicationConversionService.addDelimitedStringConverters(this);
|
ApplicationConversionService.addDelimitedStringConverters(this);
|
||||||
|
addConverter(new TypeConverterConverter(initializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -196,16 +197,23 @@ final class BindConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
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
|
@Override
|
||||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
Class<?> type = targetType.getType();
|
Class<?> type = targetType.getType();
|
||||||
if (type == null || type == Object.class || Collection.class.isAssignableFrom(type)
|
if (type == null || type == Object.class || Map.class.isAssignableFrom(type)) {
|
||||||
|| Map.class.isAssignableFrom(type)) {
|
|
||||||
return false;
|
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);
|
PropertyEditor editor = this.matchesOnlyTypeConverter.getDefaultEditor(type);
|
||||||
if (editor == null) {
|
if (editor == null) {
|
||||||
editor = this.matchesOnlyTypeConverter.findCustomEditor(type, null);
|
editor = this.matchesOnlyTypeConverter.findCustomEditor(type, null);
|
||||||
|
@ -218,7 +226,7 @@ final class BindConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
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() {
|
private SimpleTypeConverter createTypeConverter() {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.time.Duration;
|
||||||
import java.time.Period;
|
import java.time.Period;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
@ -1173,6 +1174,22 @@ class ConfigurationPropertiesTests {
|
||||||
assertThat(properties.getProp()).isEqualTo("alpha");
|
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) {
|
private AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) {
|
||||||
return load(new Class<?>[] { configuration }, 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