Allow relaxed property name overrides

Update RelaxedDataBinder to so that property ordering is respected even
if relaxed names are used. Prior to this commit a System property named
`FOO_BAR` would never get bound to a `fooBar` field if `foo-bar` was
defined in application.properties.

Fixes gh-3385
pull/3885/head
Phillip Webb 10 years ago
parent 04dfac1c6c
commit 48009bfebe

@ -20,10 +20,12 @@ import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
@ -139,10 +141,14 @@ public class RelaxedDataBinder extends DataBinder {
wrapper.setConversionService(new RelaxedConversionService(getConversionService()));
wrapper.setAutoGrowNestedPaths(true);
List<PropertyValue> sortedValues = new ArrayList<PropertyValue>();
Set<String> modifiedNames = new HashSet<String>();
List<String> sortedNames = getSortedPropertyNames(propertyValues);
for (String name : sortedNames) {
sortedValues.add(modifyProperty(wrapper,
propertyValues.getPropertyValue(name)));
PropertyValue propertyValue = propertyValues.getPropertyValue(name);
PropertyValue modifiedProperty = modifyProperty(wrapper, propertyValue);
if (modifiedNames.add(modifiedProperty.getName())) {
sortedValues.add(modifiedProperty);
}
}
return new MutablePropertyValues(sortedValues);
}

@ -139,6 +139,8 @@ public class PropertiesConfigurationFactoryTests {
private String spring_foo_baz;
private String fooBar;
public String getSpringFooBaz() {
return this.spring_foo_baz;
}
@ -163,6 +165,14 @@ public class PropertiesConfigurationFactoryTests {
this.bar = bar;
}
public String getFooBar() {
return this.fooBar;
}
public void setFooBar(String fooBar) {
this.fooBar = fooBar;
}
}
}

@ -525,6 +525,18 @@ public class RelaxedDataBinderTests {
assertThat(target.getFoo(), equalTo("b"));
}
@Test
public void testMixed() throws Exception {
// gh-3385
VanillaTarget target = new VanillaTarget();
RelaxedDataBinder binder = getBinder(target, "test");
MutablePropertyValues values = new MutablePropertyValues();
values.add("test.FOO_BAZ", "boo");
values.add("test.foo-baz", "bar");
binder.bind(values);
assertEquals("boo", target.getFooBaz());
}
private void doTestBindCaseInsensitiveEnums(VanillaTarget target) throws Exception {
BindingResult result = bind(target, "bingo: THIS");
assertThat(result.getErrorCount(), equalTo(0));
@ -555,16 +567,6 @@ public class RelaxedDataBinderTests {
return bind(target, values, null);
}
private BindingResult bind(DataBinder binder, Object target, String values)
throws Exception {
Properties properties = PropertiesLoaderUtils
.loadProperties(new ByteArrayResource(values.getBytes()));
binder.bind(new MutablePropertyValues(properties));
binder.validate();
return binder.getBindingResult();
}
private BindingResult bind(Object target, String values, String namePrefix)
throws Exception {
return bind(getBinder(target, namePrefix), target, values);
@ -580,6 +582,16 @@ public class RelaxedDataBinderTests {
return binder;
}
private BindingResult bind(DataBinder binder, Object target, String values)
throws Exception {
Properties properties = PropertiesLoaderUtils
.loadProperties(new ByteArrayResource(values.getBytes()));
binder.bind(new MutablePropertyValues(properties));
binder.validate();
return binder.getBindingResult();
}
@Documented
@Target({ ElementType.FIELD })
@Retention(RUNTIME)

@ -236,6 +236,29 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
this.context.refresh();
}
@Test
public void relaxedPropertyNamesSame() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, "test.FOO_BAR:test1");
EnvironmentTestUtils.addEnvironment(this.context, "test.FOO_BAR:test2");
this.context.register(RelaxedPropertyNames.class);
this.context.refresh();
assertThat(this.context.getBean(RelaxedPropertyNames.class).getFooBar(),
equalTo("test2"));
}
@Test
public void relaxedPropertyNamesMixed() throws Exception {
// gh-3385
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, "test.foo-bar:test1");
EnvironmentTestUtils.addEnvironment(this.context, "test.FOO_BAR:test2");
this.context.register(RelaxedPropertyNames.class);
this.context.refresh();
assertThat(this.context.getBean(RelaxedPropertyNames.class).getFooBar(),
equalTo("test2"));
}
@Configuration
@EnableConfigurationProperties
public static class TestConfigurationWithValidatingSetter {
@ -468,6 +491,23 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
}
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "test")
public static class RelaxedPropertyNames {
private String fooBar;
public String getFooBar() {
return this.fooBar;
}
public void setFooBar(String fooBar) {
this.fooBar = fooBar;
}
}
@SuppressWarnings("rawtypes")
// Must be a raw type
static class FactoryBeanTester implements FactoryBean, InitializingBean {

Loading…
Cancel
Save