Merge branch '2.2.x'

Closes gh-21294
pull/21296/head
Phillip Webb 5 years ago
commit 9486842bad

@ -36,6 +36,7 @@ import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionException;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -94,16 +95,30 @@ class ValueObjectBinder implements DataObjectBinder {
Annotation[] annotations = parameter.getAnnotations(); Annotation[] annotations = parameter.getAnnotations();
for (Annotation annotation : annotations) { for (Annotation annotation : annotations) {
if (annotation instanceof DefaultValue) { if (annotation instanceof DefaultValue) {
DefaultValue defaultValue = (DefaultValue) annotation; String[] defaultValue = ((DefaultValue) annotation).value();
if (defaultValue.value().length == 0) { if (defaultValue.length == 0) {
return getNewInstanceIfPossible(context, type); return getNewInstanceIfPossible(context, type);
} }
return context.getConverter().convert(defaultValue.value(), type, annotations); return convertDefaultValue(context.getConverter(), defaultValue, type, annotations);
} }
} }
return null; return null;
} }
private <T> T convertDefaultValue(BindConverter converter, String[] defaultValue, ResolvableType type,
Annotation[] annotations) {
try {
return converter.convert(defaultValue, type, annotations);
}
catch (ConversionException ex) {
// Try again in case ArrayToObjectConverter is not in play
if (defaultValue.length == 1) {
return converter.convert(defaultValue[0], type, annotations);
}
throw ex;
}
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T> T getNewInstanceIfPossible(Binder.Context context, ResolvableType type) { private <T> T getNewInstanceIfPossible(Binder.Context context, ResolvableType type) {
Class<T> resolved = (Class<T>) type.resolve(); Class<T> resolved = (Class<T>) type.resolve();

@ -16,6 +16,8 @@
package org.springframework.boot.context.properties.bind; package org.springframework.boot.context.properties.bind;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -307,6 +309,29 @@ class ValueObjectBinderTests {
.withStackTraceContaining("Parameter of type int must have a non-empty default value."); .withStackTraceContaining("Parameter of type int must have a non-empty default value.");
} }
@Test
void bindWhenBindingToPathTypeWithValue() { // gh-21263
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("test.name", "test");
source.put("test.path", "specific_value");
this.sources.add(source);
Bindable<PathBean> target = Bindable.of(PathBean.class);
PathBean bound = this.binder.bind("test", target).get();
assertThat(bound.getName()).isEqualTo("test");
assertThat(bound.getPath()).isEqualTo(Paths.get("specific_value"));
}
@Test
void bindWhenBindingToPathTypeWithDefaultValue() { // gh-21263
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("test.name", "test");
this.sources.add(source);
Bindable<PathBean> target = Bindable.of(PathBean.class);
PathBean bound = this.binder.bindOrCreate("test", target);
assertThat(bound.getName()).isEqualTo("test");
assertThat(bound.getPath()).isEqualTo(Paths.get("default_value"));
}
private void noConfigurationProperty(BindException ex) { private void noConfigurationProperty(BindException ex) {
assertThat(ex.getProperty()).isNull(); assertThat(ex.getProperty()).isNull();
} }
@ -684,4 +709,25 @@ class ValueObjectBinderTests {
} }
static class PathBean {
private final String name;
private final Path path;
PathBean(String name, @DefaultValue("default_value") Path path) {
this.name = name;
this.path = path;
}
String getName() {
return this.name;
}
Path getPath() {
return this.path;
}
}
} }

Loading…
Cancel
Save