Add default value for arrays

Previously, a property holding an array did not have a proper default
value in the meta-data even though the related field was initialized
properly.

An explicit support for arrays has been added. The "defaultValue" now
holds the default value for singular properties or an array of values for
array-based properties. If the value is initalized with an empty array,
the default value is an empty array as well.

Closes gh-1996
This commit is contained in:
Stephane Nicoll
2014-12-03 15:25:48 +01:00
parent 0b19884f58
commit 7d57cb7081
8 changed files with 121 additions and 20 deletions

View File

@@ -17,6 +17,8 @@
package org.springframework.boot.configurationprocessor.fieldvalues.javac;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* Reflection based access to {@code com.sun.source.tree.ExpressionTree}.
@@ -30,6 +32,10 @@ class ExpressionTree extends ReflectionWrapper {
private final Method literalValueMethod = findMethod(this.literalTreeType, "getValue");
private final Class<?> newArrayTreeType = findClass("com.sun.source.tree.NewArrayTree");
private final Method arrayValueMethod = findMethod(this.newArrayTreeType, "getInitializers");
public ExpressionTree(Object instance) {
super(instance);
}
@@ -45,4 +51,19 @@ class ExpressionTree extends ReflectionWrapper {
return null;
}
public List<? extends ExpressionTree> getArrayExpression() throws Exception {
if (this.newArrayTreeType.isAssignableFrom(getInstance().getClass())) {
List<?> elements = (List<?>) this.arrayValueMethod.invoke(getInstance());
List<ExpressionTree> result = new ArrayList<ExpressionTree>();
if (elements == null) {
return result;
}
for (Object element : elements) {
result.add(new ExpressionTree(element));
}
return result;
}
return null;
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.boot.configurationprocessor.fieldvalues.javac;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -107,18 +108,33 @@ public class JavaCompilerFieldValuesParser implements FieldValuesParser {
private Object getValue(VariableTree variable) throws Exception {
ExpressionTree initializer = variable.getInitializer();
Class<?> wrapperType = WRAPPER_TYPES.get(variable.getType());
Object defaultValue = DEFAULT_TYPE_VALUES.get(wrapperType);
if (initializer != null) {
if (initializer.getLiteralValue() != null) {
return initializer.getLiteralValue();
}
if (initializer.getKind().equals("IDENTIFIER")) {
return this.staticFinals.get(initializer.toString());
}
if (initializer.getKind().equals("MEMBER_SELECT")) {
return WELL_KNOWN_STATIC_FINALS.get(initializer.toString());
}
return getValue(initializer, defaultValue);
}
return DEFAULT_TYPE_VALUES.get(wrapperType);
return defaultValue;
}
private Object getValue(ExpressionTree expression, Object defaultValue) throws Exception {
Object literalValue = expression.getLiteralValue();
if (literalValue != null) {
return literalValue;
}
List<? extends ExpressionTree> arrayValues = expression.getArrayExpression();
if (arrayValues != null) {
Object[] result = new Object[arrayValues.size()];
for (int i = 0; i < arrayValues.size(); i++) {
result[i] = getValue(arrayValues.get(i), null);
}
return result;
}
if (expression.getKind().equals("IDENTIFIER")) {
return this.staticFinals.get(expression.toString());
}
if (expression.getKind().equals("MEMBER_SELECT")) {
return WELL_KNOWN_STATIC_FINALS.get(expression.toString());
}
return defaultValue;
}
public Map<String, Object> getFieldValues() {

View File

@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.nio.charset.Charset;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -67,7 +68,10 @@ public class JsonMarshaller {
putIfPresent(jsonObject, "description", item.getDescription());
putIfPresent(jsonObject, "sourceType", item.getSourceType());
putIfPresent(jsonObject, "sourceMethod", item.getSourceMethod());
putIfPresent(jsonObject, "defaultValue", item.getDefaultValue());
Object defaultValue = item.getDefaultValue();
if (defaultValue != null) {
putDefaultValue(jsonObject, defaultValue);
}
if (item.isDeprecated()) {
jsonObject.put("deprecated", true);
}
@@ -80,6 +84,20 @@ public class JsonMarshaller {
}
}
private void putDefaultValue(JSONObject jsonObject, Object value) {
Object defaultValue = value;
if (value.getClass().isArray()) {
JSONArray array = new JSONArray();
int length = Array.getLength(value);
for (int i = 0; i < length; i++) {
array.put(Array.get(value, i));
}
defaultValue = array;
}
jsonObject.put("defaultValue", defaultValue);
}
public ConfigurationMetadata read(InputStream inputStream) throws IOException {
ConfigurationMetadata metadata = new ConfigurationMetadata();
JSONObject object = new JSONObject(toString(inputStream));
@@ -105,12 +123,25 @@ public class JsonMarshaller {
String description = object.optString("description", null);
String sourceType = object.optString("sourceType", null);
String sourceMethod = object.optString("sourceMethod", null);
Object defaultValue = object.opt("defaultValue");
Object defaultValue = readDefaultValue(object);
boolean deprecated = object.optBoolean("deprecated");
return new ItemMetadata(itemType, name, null, type, sourceType, sourceMethod,
description, defaultValue, deprecated);
}
private Object readDefaultValue(JSONObject object) {
Object defaultValue = object.opt("defaultValue");
if (defaultValue instanceof JSONArray) {
JSONArray array = (JSONArray) defaultValue;
Object[] content = new Object[array.length()];
for (int i = 0; i < array.length(); i++) {
content[i] = array.get(i);
}
return content;
}
return defaultValue;
}
private String toString(InputStream inputStream) throws IOException {
StringBuilder out = new StringBuilder();
InputStreamReader reader = new InputStreamReader(inputStream, UTF_8);