From 6056b968286aabd3d0f58e1e66f837d9d4869e98 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 7 Jan 2015 17:06:00 -0800 Subject: [PATCH] Fix relaxed binding of camel-case properties Extended RelaxedDataBinder to include a case insensitive version of SEPARATED_TO_CAMELCASE. This allow properties of the form TEST_THE_VALUE to to bound to a @ConfigurationProperties class with a prefix of "test" and a field of `theValue`. Fixes gh-2304 --- .../boot/bind/RelaxedDataBinder.java | 3 +- .../boot/bind/RelaxedNames.java | 36 ++++++++++++------- .../boot/bind/RelaxedNamesTests.java | 3 +- ...onPropertiesBindingPostProcessorTests.java | 26 +++++++++----- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/bind/RelaxedDataBinder.java b/spring-boot/src/main/java/org/springframework/boot/bind/RelaxedDataBinder.java index 9194bf23e8..939b11d506 100644 --- a/spring-boot/src/main/java/org/springframework/boot/bind/RelaxedDataBinder.java +++ b/spring-boot/src/main/java/org/springframework/boot/bind/RelaxedDataBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -201,7 +201,6 @@ public class RelaxedDataBinder extends DataBinder { } private String initializePath(BeanWrapper wrapper, BeanPath path, int index) { - String prefix = path.prefix(index); String key = path.name(index); if (path.isProperty(index)) { diff --git a/spring-boot/src/main/java/org/springframework/boot/bind/RelaxedNames.java b/spring-boot/src/main/java/org/springframework/boot/bind/RelaxedNames.java index 72299b1cfa..444acfc367 100644 --- a/spring-boot/src/main/java/org/springframework/boot/bind/RelaxedNames.java +++ b/spring-boot/src/main/java/org/springframework/boot/bind/RelaxedNames.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -158,22 +158,34 @@ public final class RelaxedNames implements Iterable { SEPARATED_TO_CAMELCASE { @Override public String apply(String value) { - StringBuilder builder = new StringBuilder(); - for (String field : value.split("[_\\-.]")) { - builder.append(builder.length() == 0 ? field : StringUtils - .capitalize(field)); - } - for (String suffix : new String[] { "_", "-", "." }) { - if (value.endsWith(suffix)) { - builder.append(suffix); - } - } - return builder.toString(); + return separatedToCamelCase(value, false); + } + }, + + CASE_INSENSITIVE_SEPARATED_TO_CAMELCASE { + @Override + public String apply(String value) { + return separatedToCamelCase(value, true); } }; public abstract String apply(String value); + private static String separatedToCamelCase(String value, boolean caseInsensitive) { + StringBuilder builder = new StringBuilder(); + for (String field : value.split("[_\\-.]")) { + field = (caseInsensitive ? field.toLowerCase() : field); + builder.append(builder.length() == 0 ? field : StringUtils + .capitalize(field)); + } + for (String suffix : new String[] { "_", "-", "." }) { + if (value.endsWith(suffix)) { + builder.append(suffix); + } + } + return builder.toString(); + + } } } diff --git a/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedNamesTests.java b/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedNamesTests.java index 37acee80ff..20296592a0 100644 --- a/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedNamesTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedNamesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ public class RelaxedNamesTests { assertThat(iterator.next(), equalTo("my-RELAXED-property")); assertThat(iterator.next(), equalTo("my_RELAXED_property")); assertThat(iterator.next(), equalTo("myRELAXEDProperty")); + assertThat(iterator.next(), equalTo("myRelaxedProperty")); assertThat(iterator.next(), equalTo("my-relaxed-property")); assertThat(iterator.next(), equalTo("my_relaxed_property")); assertThat(iterator.next(), equalTo("myrelaxedproperty")); diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java index debb44a57d..a0444c9e09 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -136,10 +136,20 @@ public class ConfigurationPropertiesBindingPostProcessorTests { @Test public void testPropertyWithEnum() throws Exception { this.context = new AnnotationConfigApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, "test.value:foo"); + EnvironmentTestUtils.addEnvironment(this.context, "test.the-value:foo"); this.context.register(PropertyWithEnum.class); this.context.refresh(); - assertThat(this.context.getBean(PropertyWithEnum.class).getValue(), + assertThat(this.context.getBean(PropertyWithEnum.class).getTheValue(), + equalTo(FooEnum.FOO)); + } + + @Test + public void testRelaxedPropertyWithEnum() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, "TEST_THE_VALUE:FoO"); + this.context.register(PropertyWithEnum.class); + this.context.refresh(); + assertThat(this.context.getBean(PropertyWithEnum.class).getTheValue(), equalTo(FooEnum.FOO)); } @@ -349,14 +359,14 @@ public class ConfigurationPropertiesBindingPostProcessorTests { @ConfigurationProperties(prefix = "test") public static class PropertyWithEnum { - private FooEnum value; + private FooEnum theValue; - public void setValue(FooEnum value) { - this.value = value; + public void setTheValue(FooEnum value) { + this.theValue = value; } - public FooEnum getValue() { - return this.value; + public FooEnum getTheValue() { + return this.theValue; } }