Merge branch '2.1.x'

Closes gh-16857
pull/16875/head
Phillip Webb 6 years ago
commit e03f3b8e9a

@ -102,16 +102,16 @@ class JavaBeanBinder implements BeanBinder {
private static Bean<?> cached;
private final Class<?> type;
private final ResolvableType type;
private final ResolvableType resolvableType;
private final Class<?> resolvedType;
private final Map<String, BeanProperty> properties = new LinkedHashMap<>();
Bean(ResolvableType resolvableType, Class<?> type) {
this.resolvableType = resolvableType;
Bean(ResolvableType type, Class<?> resolvedType) {
this.type = type;
putProperties(type);
this.resolvedType = resolvedType;
putProperties(resolvedType);
}
private void putProperties(Class<?> type) {
@ -155,7 +155,7 @@ class JavaBeanBinder implements BeanBinder {
}
private BeanProperty getBeanProperty(String name) {
return new BeanProperty(name, this.resolvableType);
return new BeanProperty(name, this.type);
}
private void addField(Field field) {
@ -165,10 +165,6 @@ class JavaBeanBinder implements BeanBinder {
}
}
public Class<?> getType() {
return this.type;
}
public Map<String, BeanProperty> getProperties() {
return this.properties;
}
@ -181,27 +177,36 @@ class JavaBeanBinder implements BeanBinder {
instance = target.getValue().get();
}
if (instance == null) {
instance = (T) BeanUtils.instantiateClass(this.type);
instance = (T) BeanUtils.instantiateClass(this.resolvedType);
}
return instance;
});
}
private boolean isOfDifferentType(ResolvableType targetType) {
if (this.type.hasGenerics() || targetType.hasGenerics()) {
return !this.type.equals(targetType);
}
return this.resolvedType == null
|| !this.resolvedType.equals(targetType.resolve());
}
@SuppressWarnings("unchecked")
public static <T> Bean<T> get(Bindable<T> bindable, boolean canCallGetValue) {
Class<?> type = bindable.getType().resolve(Object.class);
ResolvableType type = bindable.getType();
Class<?> resolvedType = type.resolve(Object.class);
Supplier<T> value = bindable.getValue();
T instance = null;
if (canCallGetValue && value != null) {
instance = value.get();
type = (instance != null) ? instance.getClass() : type;
resolvedType = (instance != null) ? instance.getClass() : resolvedType;
}
if (instance == null && !isInstantiable(type)) {
if (instance == null && !isInstantiable(resolvedType)) {
return null;
}
Bean<?> bean = Bean.cached;
if (bean == null || !type.equals(bean.getType())) {
bean = new Bean<>(bindable.getType(), type);
if (bean == null || bean.isOfDifferentType(type)) {
bean = new Bean<>(type, resolvedType);
cached = bean;
}
return (Bean<T>) bean;

@ -494,6 +494,19 @@ public class JavaBeanBinderTests {
assertThat(bean.getCounter()).isEqualTo(42);
}
@Test
public void bindToClassShouldCacheWithGenerics() {
// gh-16821
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
source.put("foo.integers[a].value", "1");
source.put("foo.booleans[b].value", "true");
this.sources.add(source);
ExampleWithGenericMap bean = this.binder
.bind("foo", Bindable.of(ExampleWithGenericMap.class)).get();
assertThat(bean.getIntegers().get("a").getValue()).isEqualTo(1);
assertThat(bean.getBooleans().get("b").getValue()).isEqualTo(true);
}
public static class ExampleValueBean {
private int intValue;
@ -914,4 +927,34 @@ public class JavaBeanBinderTests {
}
public static class ExampleWithGenericMap {
private final Map<String, GenericValue<Integer>> integers = new LinkedHashMap<>();
private final Map<String, GenericValue<Boolean>> booleans = new LinkedHashMap<>();
public Map<String, GenericValue<Integer>> getIntegers() {
return this.integers;
}
public Map<String, GenericValue<Boolean>> getBooleans() {
return this.booleans;
}
}
public static class GenericValue<T> {
private T value;
public T getValue() {
return this.value;
}
public void setValue(T value) {
this.value = value;
}
}
}

Loading…
Cancel
Save