[bs-93] Add /info endpoint with git properties etc.
* If git.properties is on the classpath (e.g. from the Maven plugin) /info will list the commit id, branch and dates. * If application.yml has an info object at the top level that will be diplayed as well (so e.g. you can use Maven resource filtering top add the project name, version etc.) * RelaxedDataBinder can now be used to bind to a Map (as opposed to a nested Map inside teh target bean) [Fixes #49130073]
This commit is contained in:
@@ -43,7 +43,16 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
* @param target the target into which properties are bound
|
||||
*/
|
||||
public RelaxedDataBinder(Object target) {
|
||||
super(target);
|
||||
super(wrapTarget(target));
|
||||
}
|
||||
|
||||
private static Object wrapTarget(Object target) {
|
||||
if (target instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) target;
|
||||
target = new MapHolder(map);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +60,7 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
* @param namePrefix An optional prefix to be used when reading properties
|
||||
*/
|
||||
public RelaxedDataBinder(Object target, String namePrefix) {
|
||||
super(target, (StringUtils.hasLength(namePrefix) ? namePrefix
|
||||
super(wrapTarget(target), (StringUtils.hasLength(namePrefix) ? namePrefix
|
||||
: DEFAULT_OBJECT_NAME));
|
||||
this.namePrefix = (StringUtils.hasLength(namePrefix) ? namePrefix + "." : null);
|
||||
}
|
||||
@@ -74,11 +83,15 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
private MutablePropertyValues modifyProperties(MutablePropertyValues propertyValues,
|
||||
Object target) {
|
||||
|
||||
propertyValues = getProperyValuesForNamePrefix(propertyValues);
|
||||
|
||||
if (target instanceof MapHolder) {
|
||||
propertyValues = addMapPrefix(propertyValues);
|
||||
}
|
||||
|
||||
BeanWrapper targetWrapper = new BeanWrapperImpl(target);
|
||||
targetWrapper.setAutoGrowNestedPaths(true);
|
||||
|
||||
propertyValues = getProperyValuesForNamePrefix(propertyValues);
|
||||
|
||||
List<PropertyValue> list = propertyValues.getPropertyValueList();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
modifyProperty(propertyValues, targetWrapper, list.get(i), i);
|
||||
@@ -86,6 +99,14 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
return propertyValues;
|
||||
}
|
||||
|
||||
private MutablePropertyValues addMapPrefix(MutablePropertyValues propertyValues) {
|
||||
MutablePropertyValues rtn = new MutablePropertyValues();
|
||||
for (PropertyValue pv : propertyValues.getPropertyValues()) {
|
||||
rtn.add("map." + pv.getName(), pv.getValue());
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
private MutablePropertyValues getProperyValuesForNamePrefix(
|
||||
MutablePropertyValues propertyValues) {
|
||||
if (this.namePrefix == null) {
|
||||
@@ -126,7 +147,6 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
// Any nested properties that are maps, are assumed to be simple nested
|
||||
// maps of maps...
|
||||
if (type != null && Map.class.isAssignableFrom(type)) {
|
||||
String suffix = name.substring(base.length());
|
||||
Map<String, Object> nested = new LinkedHashMap<String, Object>();
|
||||
if (target.getPropertyValue(base) != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -136,24 +156,33 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
} else {
|
||||
target.setPropertyValue(base, nested);
|
||||
}
|
||||
Map<String, Object> value = nested;
|
||||
nested = new LinkedHashMap<String, Object>();
|
||||
String[] tree = StringUtils.delimitedListToStringArray(suffix, ".");
|
||||
for (int j = 1; j < tree.length - 1; j++) {
|
||||
if (!value.containsKey(tree[j])) {
|
||||
value.put(tree[j], nested);
|
||||
}
|
||||
value = nested;
|
||||
nested = new LinkedHashMap<String, Object>();
|
||||
}
|
||||
String refName = base + suffix.replaceAll("\\.([a-zA-Z0-9]*)", "[$1]");
|
||||
propertyValues.setPropertyValueAt(new PropertyValue(refName,
|
||||
propertyValue.getValue()), index);
|
||||
modifyPopertiesForMap(nested, propertyValues, index, base);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void modifyPopertiesForMap(Map<String, Object> target,
|
||||
MutablePropertyValues propertyValues, int index, String base) {
|
||||
PropertyValue propertyValue = propertyValues.getPropertyValueList().get(index);
|
||||
String name = propertyValue.getName();
|
||||
String suffix = name.substring(base.length());
|
||||
Map<String, Object> value = new LinkedHashMap<String, Object>();
|
||||
String[] tree = StringUtils.delimitedListToStringArray(
|
||||
suffix.startsWith(".") ? suffix.substring(1) : suffix, ".");
|
||||
for (int j = 0; j < tree.length - 1; j++) {
|
||||
if (!target.containsKey(tree[j])) {
|
||||
target.put(tree[j], value);
|
||||
}
|
||||
target = value;
|
||||
value = new LinkedHashMap<String, Object>();
|
||||
}
|
||||
String refName = base + suffix.replaceAll("\\.([a-zA-Z0-9]*)", "[$1]");
|
||||
propertyValues.setPropertyValueAt(
|
||||
new PropertyValue(refName, propertyValue.getValue()), index);
|
||||
|
||||
}
|
||||
|
||||
private String getActualPropertyName(BeanWrapper target, String prefix, String name) {
|
||||
for (Variation variation : Variation.values()) {
|
||||
for (Manipulation manipulation : Manipulation.values()) {
|
||||
@@ -223,4 +252,20 @@ public class RelaxedDataBinder extends DataBinder {
|
||||
public abstract String apply(String value);
|
||||
}
|
||||
|
||||
static class MapHolder {
|
||||
private Map<String, Object> map;
|
||||
|
||||
public MapHolder(Map<String, Object> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public void setMap(Map<String, Object> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public Map<String, Object> getMap() {
|
||||
return this.map;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -181,6 +182,26 @@ public class RelaxedDataBinderTests {
|
||||
assertEquals(123, target.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindMap() throws Exception {
|
||||
Map<String, Object> target = new LinkedHashMap<String, Object>();
|
||||
BindingResult result = bind(target, "spam: bar\n" + "vanilla.value: 123",
|
||||
"vanilla");
|
||||
assertEquals(0, result.getErrorCount());
|
||||
assertEquals("123", target.get("value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindMapNestedInMap() throws Exception {
|
||||
Map<String, Object> target = new LinkedHashMap<String, Object>();
|
||||
BindingResult result = bind(target, "spam: bar\n" + "vanilla.foo.value: 123",
|
||||
"vanilla");
|
||||
assertEquals(0, result.getErrorCount());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) target.get("foo");
|
||||
assertEquals("123", map.get("value"));
|
||||
}
|
||||
|
||||
private BindingResult bind(Object target, String values) throws Exception {
|
||||
return bind(target, values, null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user