From f0ed619347854260933d7c6c639b3cd2662d8e03 Mon Sep 17 00:00:00 2001 From: Daniel Fullarton Date: Wed, 11 Feb 2015 02:59:35 +1100 Subject: [PATCH] Supported relaxed binding on inner classes Update RelaxedDataBinder to support relaxed binding to inner classes in the same way as normal configuration objects. e.g. `nested.foo_bar` => `nested.fooBar` Fixes gh-2463 Closes gh- 2479 --- .../boot/bind/RelaxedDataBinder.java | 36 +++++++++++++++++-- .../boot/bind/RelaxedDataBinderTests.java | 30 +++++++++++++++- 2 files changed, 62 insertions(+), 4 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 939b11d506..7801d66b46 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 @@ -286,12 +286,38 @@ public class RelaxedDataBinder extends DataBinder { } private String getActualPropertyName(BeanWrapper target, String prefix, String name) { - prefix = StringUtils.hasText(prefix) ? prefix + "." : ""; + String propertyName = resolvePropertyName(target, prefix, name); + if (propertyName == null) { + propertyName = resolveNestedPropertyName(target, prefix, name); + } + return (propertyName == null ? name : propertyName); + } + + private String resolveNestedPropertyName(BeanWrapper target, String prefix, + String name) { + StringBuilder candidate = new StringBuilder(); + for (String field : name.split("[_\\-\\.]")) { + candidate.append(candidate.length() > 0 ? "." : ""); + candidate.append(field); + String nested = resolvePropertyName(target, prefix, candidate.toString()); + if (nested != null) { + String propertyName = resolvePropertyName(target, + joinString(prefix, nested), + name.substring(candidate.length() + 1)); + if (propertyName != null) { + return joinString(nested, propertyName); + } + } + } + return null; + } + + private String resolvePropertyName(BeanWrapper target, String prefix, String name) { Iterable names = getNameAndAliases(name); for (String nameOrAlias : names) { for (String candidate : new RelaxedNames(nameOrAlias)) { try { - if (target.getPropertyType(prefix + candidate) != null) { + if (target.getPropertyType(joinString(prefix, candidate)) != null) { return candidate; } } @@ -300,7 +326,11 @@ public class RelaxedDataBinder extends DataBinder { } } } - return name; + return null; + } + + private String joinString(String prefix, String name) { + return (StringUtils.hasLength(prefix) ? prefix + "." + name : name); } private Iterable getNameAndAliases(String name) { diff --git a/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedDataBinderTests.java b/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedDataBinderTests.java index 50729be019..9fe61f508a 100644 --- a/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedDataBinderTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedDataBinderTests.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,6 +201,22 @@ public class RelaxedDataBinderTests { assertEquals(123, target.getNested().getValue()); } + @Test + public void testBindRelaxedNestedValue() throws Exception { + TargetWithNestedObject target = new TargetWithNestedObject(); + bind(target, "nested_foo_Baz: bar\n" + "nested_value: 123"); + assertEquals("bar", target.getNested().getFooBaz()); + assertEquals(123, target.getNested().getValue()); + } + + @Test + public void testBindRelaxedNestedCamelValue() throws Exception { + TargetWithNestedObject target = new TargetWithNestedObject(); + bind(target, "another_nested_foo_Baz: bar\n" + "another-nested_value: 123"); + assertEquals("bar", target.getAnotherNested().getFooBaz()); + assertEquals(123, target.getAnotherNested().getValue()); + } + @Test public void testBindNestedWithEnviromentStyle() throws Exception { TargetWithNestedObject target = new TargetWithNestedObject(); @@ -736,8 +752,11 @@ public class RelaxedDataBinderTests { } public static class TargetWithNestedObject { + private VanillaTarget nested; + private VanillaTarget anotherNested; + public VanillaTarget getNested() { return this.nested; } @@ -745,6 +764,15 @@ public class RelaxedDataBinderTests { public void setNested(VanillaTarget nested) { this.nested = nested; } + + public VanillaTarget getAnotherNested() { + return this.anotherNested; + } + + public void setAnotherNested(VanillaTarget anotherNested) { + this.anotherNested = anotherNested; + } + } public static class VanillaTarget {