[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:
Dave Syer
2013-05-03 12:42:50 +01:00
parent 7e6651c0a2
commit 7e548b5bd4
8 changed files with 293 additions and 19 deletions

View File

@@ -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;
}
}
}

View File

@@ -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);
}