Ignore binding failures for env vars and system properties

1.3.0.M4 tightened up the configuration property binding such that
ignoreUnknownFields = false now works as intended. Unfortunately, this
has led to some complaints as applications that worked with 1.2.x have
stopped working. For example, a SERVER_HOME environment variable does
not cause a failure in 1.2.x despite there being no home property on
ServerProperties but will now fail in 1.3.0.M4.

This commit updates RelaxedDataBinder to ignore binding failures for
properties that come from a source outside of the application’s control,
namely environment variables and system properties.

Closes gh-3775
pull/3535/merge
Andy Wilkinson 9 years ago
parent d74d657372
commit a0870c1c4a

@ -18,6 +18,7 @@ package org.springframework.boot.bind;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -35,6 +36,7 @@ import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.beans.PropertyValue;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
@ -54,6 +56,11 @@ import org.springframework.validation.DataBinder;
*/
public class RelaxedDataBinder extends DataBinder {
private static final Set<String> BENIGN_PROPERTY_SOURCE_NAMES = Collections
.unmodifiableSet(new HashSet<String>(Arrays.asList(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)));
private static final Object BLANK = new Object();
private String namePrefix;
@ -254,13 +261,21 @@ public class RelaxedDataBinder extends DataBinder {
}
catch (NotWritablePropertyException ex) {
PropertyOrigin origin = findPropertyOrigin(pv);
if (isFatal(origin)) {
if (origin != null) {
throw new RelaxedBindingNotWritablePropertyException(ex,
origin);
throw new RelaxedBindingNotWritablePropertyException(
ex, origin);
}
else {
throw ex;
}
}
else {
logger.debug("Ignoring benign property binding failure",
ex);
}
}
}
};
beanWrapper.setConversionService(new RelaxedConversionService(
getConversionService()));
@ -271,6 +286,13 @@ public class RelaxedDataBinder extends DataBinder {
};
}
private boolean isFatal(PropertyOrigin origin) {
if (origin == null) {
return true;
}
return !BENIGN_PROPERTY_SOURCE_NAMES.contains(origin.getSource().getName());
}
private PropertyOrigin findPropertyOrigin(PropertyValue propertyValue) {
if (propertyValue instanceof OriginCapablePropertyValue) {
return ((OriginCapablePropertyValue) propertyValue).getOrigin();

@ -24,8 +24,11 @@ import javax.validation.constraints.NotNull;
import org.junit.Test;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.context.support.StaticMessageSource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.mock.env.MockPropertySource;
import org.springframework.validation.BindException;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
@ -82,6 +85,37 @@ public class PropertiesConfigurationFactoryTests {
bindFoo("bar: blah");
}
@Test
public void systemEnvironmentBindingFailuresAreIgnored() throws Exception {
setupFactory();
MutablePropertySources propertySources = new MutablePropertySources();
MockPropertySource propertySource = new MockPropertySource(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
propertySource.setProperty("doesNotExist", "foo");
propertySource.setProperty("name", "bar");
propertySources.addFirst(propertySource);
this.factory.setPropertySources(propertySources);
this.factory.setIgnoreUnknownFields(false);
this.factory.afterPropertiesSet();
this.factory.getObject();
Foo foo = this.factory.getObject();
assertEquals("bar", foo.name);
}
@Test
public void systemPropertyBindingFailuresAreIgnored() throws Exception {
setupFactory();
MutablePropertySources propertySources = new MutablePropertySources();
MockPropertySource propertySource = new MockPropertySource(
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);
propertySource.setProperty("doesNotExist", "foo");
propertySource.setProperty("name", "bar");
propertySources.addFirst(propertySource);
this.factory.setPropertySources(propertySources);
this.factory.setIgnoreUnknownFields(false);
this.factory.afterPropertiesSet();
}
private Foo createFoo(final String values) throws Exception {
setupFactory();
return bindFoo(values);

Loading…
Cancel
Save