Guard against binding non-instantiable types

Update `JavaBeanBinder` so that null instances that are non-instantiable
are not bound.

Fixes gh-10131
This commit is contained in:
Madhura Bhave 2017-09-20 11:26:28 -07:00 committed by Phillip Webb
parent b7c37c2807
commit 3ec3b64d45
2 changed files with 45 additions and 7 deletions

View File

@ -168,17 +168,17 @@ class JavaBeanBinder implements BeanBinder {
}
@SuppressWarnings("unchecked")
public static <T> Bean<T> get(Bindable<T> bindable,
boolean useExistingValueForType) {
public static <T> Bean<T> get(Bindable<T> bindable, boolean canCallGetValue) {
Class<?> type = bindable.getType().resolve();
Supplier<T> value = bindable.getValue();
if (value == null && !isInstantiable(type)) {
return null;
}
if (useExistingValueForType && value != null) {
T instance = value.get();
T instance = null;
if (canCallGetValue && value != null) {
instance = value.get();
type = (instance != null ? instance.getClass() : type);
}
if (instance == null && !isInstantiable(type)) {
return null;
}
Bean<?> bean = Bean.cached;
if (bean == null || !type.equals(bean.getType())) {
bean = new Bean<>(type);

View File

@ -21,6 +21,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.validation.Validation;
import org.assertj.core.matcher.AssertionMatcher;
import org.junit.Before;
import org.junit.Rule;
@ -30,14 +32,21 @@ import org.junit.rules.ExpectedException;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.springframework.boot.context.properties.bind.validation.ValidationBindHandler;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.context.properties.source.MockConfigurationPropertySource;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
@ -239,6 +248,20 @@ public class BinderTests {
this.binder.bind("foo", target);
}
@Test
public void bindToValidatedBeanWithResourceAndNonEnumerablePropertySource() {
ConfigurationPropertySources.from(new PropertySource<String>("test") {
@Override
public Object getProperty(String name) {
return null;
}
}).forEach(this.sources::add);
Validator validator = new SpringValidatorAdapter(Validation.byDefaultProvider()
.configure().buildValidatorFactory().getValidator());
this.binder.bind("foo", Bindable.of(ResourceBean.class),
new ValidationBindHandler(validator));
}
public static class JavaBean {
private String value;
@ -265,4 +288,19 @@ public class BinderTests {
}
@Validated
public static class ResourceBean {
private Resource resource;
public Resource getResource() {
return this.resource;
}
public void setResource(Resource resource) {
this.resource = resource;
}
}
}