Support nested arrays when translating properties to map when generating yml or json
Fixes gh-518
This commit is contained in:
@@ -31,17 +31,12 @@ import java.util.TreeMap;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.boot.bind.PropertiesConfigurationFactory;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.environment.PropertySource;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -62,14 +57,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
* @author Rafal Zukowski
|
||||
* @author Ivan Corrales Solera
|
||||
* @author Daniel Frey
|
||||
* @author Ian Bondoc
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(method = RequestMethod.GET, path = "${spring.cloud.config.server.prefix:}")
|
||||
public class EnvironmentController {
|
||||
|
||||
private static final String MAP_PREFIX = "map";
|
||||
|
||||
private EnvironmentRepository repository;
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@@ -152,7 +146,7 @@ public class EnvironmentController {
|
||||
throws Exception {
|
||||
validateProfiles(profiles);
|
||||
Environment environment = labelled(name, profiles, label);
|
||||
Map<String, Object> properties = convertToMap(environment, resolvePlaceholders);
|
||||
Map<String, Object> properties = convertToMap(environment);
|
||||
String json = this.objectMapper.writeValueAsString(properties);
|
||||
if (resolvePlaceholders) {
|
||||
json = resolvePlaceholders(prepareEnvironment(environment), json);
|
||||
@@ -188,7 +182,7 @@ public class EnvironmentController {
|
||||
throws Exception {
|
||||
validateProfiles(profiles);
|
||||
Environment environment = labelled(name, profiles, label);
|
||||
Map<String, Object> result = convertToMap(environment, resolvePlaceholders);
|
||||
Map<String, Object> result = convertToMap(environment);
|
||||
if (this.stripDocument && result.size() == 1
|
||||
&& result.keySet().iterator().next().equals("document")) {
|
||||
Object value = result.get("document");
|
||||
@@ -208,26 +202,25 @@ public class EnvironmentController {
|
||||
return getSuccess(yaml);
|
||||
}
|
||||
|
||||
private Map<String, Object> convertToMap(Environment input, boolean resolvePlaceholders) throws BindException {
|
||||
Map<String, Object> target = new LinkedHashMap<>();
|
||||
PropertiesConfigurationFactory<Map<String, Object>> factory = new PropertiesConfigurationFactory<>(
|
||||
target);
|
||||
if (!resolvePlaceholders) {
|
||||
factory.setResolvePlaceholders(false);
|
||||
/**
|
||||
* Method {@code convertToMap} converts an {@code Environment} to a nested Map which represents a yml/json structure.
|
||||
*
|
||||
* @param input the environment to be converted
|
||||
* @return the nested map containing the environment's properties
|
||||
*/
|
||||
private Map<String, Object> convertToMap(Environment input) {
|
||||
// First use the current convertToProperties to get a flat Map from the environment
|
||||
Map<String, Object> properties = convertToProperties(input);
|
||||
|
||||
// The root map which holds all the first level properties
|
||||
Map<String, Object> rootMap = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Object> entry : properties.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
PropertyNavigator nav = new PropertyNavigator(key);
|
||||
nav.setMapValue(rootMap, value);
|
||||
}
|
||||
Map<String, Object> data = convertToProperties(input);
|
||||
LinkedHashMap<String, Object> properties = new LinkedHashMap<>();
|
||||
for (String key : data.keySet()) {
|
||||
properties.put(MAP_PREFIX + "." + key, data.get(key));
|
||||
}
|
||||
addArrays(target, properties);
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MapPropertySource("properties", properties));
|
||||
factory.setPropertySources(propertySources);
|
||||
factory.bindPropertiesToTarget();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> result = (Map<String, Object>) target.get(MAP_PREFIX);
|
||||
return result == null ? new LinkedHashMap<String, Object>() : result;
|
||||
return rootMap;
|
||||
}
|
||||
|
||||
@ExceptionHandler(NoSuchLabelException.class)
|
||||
@@ -262,55 +255,6 @@ public class EnvironmentController {
|
||||
return new ResponseEntity<>(body, getHttpHeaders(mediaType), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Lists of the right size for any YAML arrays that are going to need to be
|
||||
* bound. Some of this might be do-able in RelaxedDataBinder, but we need to do it
|
||||
* here for now. Only supports arrays at leaf level currently (i.e. the properties
|
||||
* keys end in [*]).
|
||||
*
|
||||
* @param target the target Map
|
||||
* @param properties the properties (with key names to check)
|
||||
*/
|
||||
private void addArrays(Map<String, Object> target, Map<String, Object> properties) {
|
||||
for (String key : properties.keySet()) {
|
||||
int index = key.indexOf("[");
|
||||
Map<String, Object> current = target;
|
||||
if (index > 0) {
|
||||
String stem = key.substring(0, index);
|
||||
String[] keys = StringUtils.delimitedListToStringArray(stem, ".");
|
||||
for (int i = 0; i < keys.length - 1; i++) {
|
||||
if (current.get(keys[i]) == null) {
|
||||
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||
current.put(keys[i], map);
|
||||
current = map;
|
||||
}
|
||||
else {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) current
|
||||
.get(keys[i]);
|
||||
current = map;
|
||||
}
|
||||
}
|
||||
String name = keys[keys.length - 1];
|
||||
if (current.get(name) == null) {
|
||||
current.put(name, new ArrayList<>());
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> value = (List<Object>) current.get(name);
|
||||
int position = Integer
|
||||
.valueOf(key.substring(index + 1, key.indexOf("]")));
|
||||
while (position >= value.size()) {
|
||||
if (key.indexOf("].", index) > 0) {
|
||||
value.add(new LinkedHashMap<String, Object>());
|
||||
}
|
||||
else {
|
||||
value.add("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> convertToProperties(Environment profiles) {
|
||||
|
||||
// Map of unique keys containing full map of properties for each unique
|
||||
@@ -367,4 +311,144 @@ public class EnvironmentController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class {@code PropertyNavigator} is used to navigate through the property key and create necessary Maps and Lists
|
||||
* making up the nested structure to finally set the property value at the leaf node.
|
||||
* <p>
|
||||
* The following rules in yml/json are implemented:
|
||||
* <pre>
|
||||
* 1. an array element can be:
|
||||
* - a value (leaf)
|
||||
* - a map
|
||||
* - a nested array
|
||||
* 2. a map value can be:
|
||||
* - a value (leaf)
|
||||
* - a nested map
|
||||
* - an array
|
||||
* </pre>
|
||||
*/
|
||||
private static class PropertyNavigator {
|
||||
|
||||
private enum NodeType {LEAF, MAP, ARRAY}
|
||||
|
||||
private final String propertyKey;
|
||||
private int currentPos;
|
||||
private NodeType valueType;
|
||||
|
||||
private PropertyNavigator(String propertyKey) {
|
||||
this.propertyKey = propertyKey;
|
||||
currentPos = -1;
|
||||
valueType = NodeType.MAP;
|
||||
}
|
||||
|
||||
private void setMapValue(Map<String, Object> map, Object value) {
|
||||
String key = getKey();
|
||||
if (NodeType.MAP.equals(valueType)) {
|
||||
Map<String, Object> nestedMap = (Map<String, Object>) map.get(key);
|
||||
if (nestedMap == null) {
|
||||
nestedMap = new LinkedHashMap<>();
|
||||
map.put(key, nestedMap);
|
||||
}
|
||||
setMapValue(nestedMap, value);
|
||||
} else if (NodeType.ARRAY.equals(valueType)) {
|
||||
List<Object> list = (List<Object>) map.get(key);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
map.put(key, list);
|
||||
}
|
||||
setListValue(list, value);
|
||||
} else {
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void setListValue(List<Object> list, Object value) {
|
||||
int index = getIndex();
|
||||
// Fill missing elements if needed
|
||||
while (list.size() <= index) {
|
||||
list.add(null);
|
||||
}
|
||||
if (NodeType.MAP.equals(valueType)) {
|
||||
Map<String, Object> map = (Map<String, Object>) list.get(index);
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<>();
|
||||
list.set(index, map);
|
||||
}
|
||||
setMapValue(map, value);
|
||||
} else if (NodeType.ARRAY.equals(valueType)) {
|
||||
List<Object> nestedList = (List<Object>) list.get(index);
|
||||
if (nestedList == null) {
|
||||
nestedList = new ArrayList<>();
|
||||
list.set(index, nestedList);
|
||||
}
|
||||
setListValue(nestedList, value);
|
||||
} else {
|
||||
list.set(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
private int getIndex() {
|
||||
// Consider [
|
||||
int start = currentPos + 1;
|
||||
|
||||
for (int i = start; i < propertyKey.length(); i++) {
|
||||
char c = propertyKey.charAt(i);
|
||||
if (c == ']') {
|
||||
currentPos = i;
|
||||
break;
|
||||
} else if (!Character.isDigit(c)) {
|
||||
throw new IllegalArgumentException("Invalid key: " + propertyKey);
|
||||
}
|
||||
}
|
||||
// If no closing ] or if '[]'
|
||||
if (currentPos < start || currentPos == start) {
|
||||
throw new IllegalArgumentException("Invalid key: " + propertyKey);
|
||||
} else {
|
||||
int index = Integer.parseInt(propertyKey.substring(start, currentPos));
|
||||
// Skip the closing ]
|
||||
currentPos++;
|
||||
if (currentPos == propertyKey.length()) {
|
||||
valueType = NodeType.LEAF;
|
||||
} else {
|
||||
switch (propertyKey.charAt(currentPos)) {
|
||||
case '.':
|
||||
valueType = NodeType.MAP;
|
||||
break;
|
||||
case '[':
|
||||
valueType = NodeType.ARRAY;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid key: " + propertyKey);
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
private String getKey() {
|
||||
// Consider initial value or previous char '.' or '['
|
||||
int start = currentPos + 1;
|
||||
for (int i = start; i < propertyKey.length(); i++) {
|
||||
char currentChar = propertyKey.charAt(i);
|
||||
if (currentChar == '.') {
|
||||
valueType = NodeType.MAP;
|
||||
currentPos = i;
|
||||
break;
|
||||
} else if (currentChar == '[') {
|
||||
valueType = NodeType.ARRAY;
|
||||
currentPos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If there's no delimiter then it's a key of a leaf
|
||||
if (currentPos < start) {
|
||||
currentPos = propertyKey.length();
|
||||
valueType = NodeType.LEAF;
|
||||
// Else if we encounter '..' or '.[' or start of the property is . or [ then it's invalid
|
||||
} else if (currentPos == start) {
|
||||
throw new IllegalArgumentException("Invalid key: " + propertyKey);
|
||||
}
|
||||
return propertyKey.substring(start, currentPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,6 @@
|
||||
*/
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -34,6 +26,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.environment.PropertySource;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -42,11 +35,21 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Roy Clarkson
|
||||
* @author Ivan Corrales Solera
|
||||
* @author Daniel Frey
|
||||
* @author Ian Bondoc
|
||||
*/
|
||||
public class EnvironmentControllerTests {
|
||||
|
||||
@@ -74,7 +77,8 @@ public class EnvironmentControllerTests {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("a.b.c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("a:\n b:\n c: d\n", yaml);
|
||||
}
|
||||
@@ -84,8 +88,10 @@ public class EnvironmentControllerTests {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("a.b.c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
this.environment.addFirst(new PropertySource("two", Collections.singletonMap("a.b.c", "e")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
this.environment.addFirst(
|
||||
new PropertySource("two", Collections.singletonMap("a.b.c", "e")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("a:\n b:\n c: e\n", yaml);
|
||||
}
|
||||
@@ -101,7 +107,8 @@ public class EnvironmentControllerTests {
|
||||
map.put("A", "Z");
|
||||
map.put("S", 3);
|
||||
this.environment.addFirst(new PropertySource("two", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("A: Z\nS: 3\nY: 0\n", yaml);
|
||||
}
|
||||
@@ -128,14 +135,16 @@ public class EnvironmentControllerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersNotResolvedInYamlFromSystemPropertiesWhenNotFlagged() throws Exception {
|
||||
public void placeholdersNotResolvedInYamlFromSystemPropertiesWhenNotFlagged()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemProps();
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("a:\n b:\n c: ${foo}\n", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersNotResolvedInYamlFromSystemPropertiesWhenNotFlaggedWithDefault() throws Exception {
|
||||
public void placeholdersNotResolvedInYamlFromSystemPropertiesWhenNotFlaggedWithDefault()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemPropsWithDefault();
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
// If there is a default value we prevent the placeholder being resolved
|
||||
@@ -143,7 +152,8 @@ public class EnvironmentControllerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersResolvedInYamlFromSystemPropertiesWhenFlagged() throws Exception {
|
||||
public void placeholdersResolvedInYamlFromSystemPropertiesWhenFlagged()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemPropsWithDefault();
|
||||
String yaml = this.controller.yaml("foo", "bar", true).getBody();
|
||||
// If there is a default value we do not prevent the placeholder being resolved
|
||||
@@ -156,7 +166,8 @@ public class EnvironmentControllerTests {
|
||||
map.put("a.b[0]", "c");
|
||||
map.put("a.b[1]", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("a:\n b:\n - c\n - d\n", yaml);
|
||||
}
|
||||
@@ -176,7 +187,8 @@ public class EnvironmentControllerTests {
|
||||
twoMap.put("a.b[1]", "h");
|
||||
this.environment.addFirst(new PropertySource("two", twoMap));
|
||||
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "two")).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "two"))
|
||||
.thenReturn(this.environment);
|
||||
Environment environment = this.controller.labelled("foo", "bar", "two");
|
||||
assertThat(environment, not(nullValue()));
|
||||
assertThat(environment.getName(), equalTo("foo"));
|
||||
@@ -185,9 +197,11 @@ public class EnvironmentControllerTests {
|
||||
assertThat(environment.getVersion(), nullValue());
|
||||
assertThat(environment.getPropertySources(), hasSize(2));
|
||||
assertThat(environment.getPropertySources().get(0).getName(), equalTo("two"));
|
||||
assertThat(environment.getPropertySources().get(0).getSource().entrySet(), hasSize(2));
|
||||
assertThat(environment.getPropertySources().get(0).getSource().entrySet(),
|
||||
hasSize(2));
|
||||
assertThat(environment.getPropertySources().get(1).getName(), equalTo("one"));
|
||||
assertThat(environment.getPropertySources().get(1).getSource().entrySet(), hasSize(3));
|
||||
assertThat(environment.getPropertySources().get(1).getSource().entrySet(),
|
||||
hasSize(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -205,7 +219,8 @@ public class EnvironmentControllerTests {
|
||||
twoMap.put("a.b[1]", "h");
|
||||
this.environment.addFirst(new PropertySource("two", twoMap));
|
||||
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
|
||||
// Result will not contain original, extra values from oneMap
|
||||
@@ -217,7 +232,8 @@ public class EnvironmentControllerTests {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("document", "blah");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("blah\n", yaml);
|
||||
}
|
||||
@@ -228,7 +244,8 @@ public class EnvironmentControllerTests {
|
||||
map.put("document[0]", "c");
|
||||
map.put("document[1]", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("- c\n- d\n", yaml);
|
||||
}
|
||||
@@ -239,7 +256,8 @@ public class EnvironmentControllerTests {
|
||||
map.put("document[0].a", "c");
|
||||
map.put("document[1].a", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("- a: c\n- a: d\n", yaml);
|
||||
}
|
||||
@@ -251,10 +269,61 @@ public class EnvironmentControllerTests {
|
||||
map.put("a.b[0].d", "e");
|
||||
map.put("a.b[1].c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertTrue("Wrong output: " + yaml, "a:\n b:\n - d: e\n c: d\n - c: d\n".equals(yaml)
|
||||
|| "a:\n b:\n - c: d\n d: e\n - c: d\n".equals(yaml));
|
||||
assertTrue("Wrong output: " + yaml,
|
||||
"a:\n b:\n - d: e\n c: d\n - c: d\n".equals(yaml)
|
||||
|| "a:\n b:\n - c: d\n d: e\n - c: d\n".equals(yaml));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedArraysOfObjectInYaml() throws Exception {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("a.b[0].c", "x");
|
||||
map.put("a.b[2].e[0].d", "z");
|
||||
map.put("a.b[0].d[2]", "yy");
|
||||
map.put("a.b[0].d[0]", "xx");
|
||||
map.put("a.b[2].c", "y");
|
||||
map.put("a.b[3][0]", "r");
|
||||
map.put("a.b[3][1]", "s");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
String expected = // @formatter:off
|
||||
"a:\n" +
|
||||
" b:\n" +
|
||||
" - c: x\n" +
|
||||
" d:\n" +
|
||||
" - xx\n" +
|
||||
" - null\n" +
|
||||
" - yy\n" +
|
||||
" - null\n" +
|
||||
" - c: y\n" +
|
||||
" e:\n" +
|
||||
" - d: z\n" +
|
||||
" - - r\n" +
|
||||
" - s\n";
|
||||
// @formatter:on
|
||||
assertThat("Wrong output: " + yaml, yaml, is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedArraysOfObjectInJson() throws Exception {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("a.b[0].c", "x");
|
||||
map.put("a.b[0].d[0]", "xx");
|
||||
map.put("a.b[0].d[1]", "yy");
|
||||
map.put("a.b[1].c", "y");
|
||||
map.put("a.b[1].e[0].d", "z");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String json = this.controller.jsonProperties("foo", "bar", false).getBody();
|
||||
System.err.println(json);
|
||||
assertThat("Wrong output: " + json, json, is(
|
||||
"{\"a\":{\"b\":[{\"c\":\"x\",\"d\":[\"xx\",\"yy\"]},{\"c\":\"y\",\"e\":[{\"d\":\"z\"}]}]}}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -263,7 +332,8 @@ public class EnvironmentControllerTests {
|
||||
map.put("b[0].c", "d");
|
||||
map.put("b[1].c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("b:\n- c: d\n- c: d\n", yaml);
|
||||
}
|
||||
@@ -274,7 +344,8 @@ public class EnvironmentControllerTests {
|
||||
map.put("x.a.b[0].c", "d");
|
||||
map.put("x.a.b[1].c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("x:\n a:\n b:\n - c: d\n - c: d\n", yaml);
|
||||
}
|
||||
@@ -294,21 +365,24 @@ public class EnvironmentControllerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersNotResolvedInPropertiesFromSystemProperties() throws Exception {
|
||||
public void placeholdersNotResolvedInPropertiesFromSystemProperties()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemProps();
|
||||
String text = this.controller.properties("foo", "bar", true).getBody();
|
||||
assertEquals("a.b.c: ${foo}", text);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersNotResolvedInPropertiesFromSystemPropertiesWhenNotFlagged() throws Exception {
|
||||
public void placeholdersNotResolvedInPropertiesFromSystemPropertiesWhenNotFlagged()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemProps();
|
||||
String text = this.controller.properties("foo", "bar", false).getBody();
|
||||
assertEquals("a.b.c: ${foo}", text);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersNotResolvedInPropertiesFromSystemPropertiesWhenNotFlaggedWithDefault() throws Exception {
|
||||
public void placeholdersNotResolvedInPropertiesFromSystemPropertiesWhenNotFlaggedWithDefault()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemPropsWithDefault();
|
||||
String text = this.controller.properties("foo", "bar", false).getBody();
|
||||
assertEquals("a.b.c: ${foo:spam}", text);
|
||||
@@ -336,14 +410,16 @@ public class EnvironmentControllerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersNotResolvedInJsonFromSystemPropertiesWhenNotFlagged() throws Exception {
|
||||
public void placeholdersNotResolvedInJsonFromSystemPropertiesWhenNotFlagged()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemProps();
|
||||
String json = this.controller.jsonProperties("foo", "bar", false).getBody();
|
||||
assertEquals("{\"a\":{\"b\":{\"c\":\"${foo}\"}}}", json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersNotResolvedInJsonFromSystemPropertiesWhenNotFlaggedWithDefault() throws Exception {
|
||||
public void placeholdersNotResolvedInJsonFromSystemPropertiesWhenNotFlaggedWithDefault()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemPropsWithDefault();
|
||||
String json = this.controller.jsonProperties("foo", "bar", false).getBody();
|
||||
// If there is a default value we prevent the placeholder being resolved
|
||||
@@ -351,7 +427,8 @@ public class EnvironmentControllerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersResolvedInJsonFromSystemPropertiesWhenFlagged() throws Exception {
|
||||
public void placeholdersResolvedInJsonFromSystemPropertiesWhenFlagged()
|
||||
throws Exception {
|
||||
whenPlaceholdersSystemPropsWithDefault();
|
||||
String json = this.controller.jsonProperties("foo", "bar", true).getBody();
|
||||
// If there is a default value we do not prevent the placeholder being resolved
|
||||
@@ -362,108 +439,131 @@ public class EnvironmentControllerTests {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("foo", "bar");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
this.environment.addFirst(new PropertySource("two", Collections.singletonMap("a.b.c", "${foo}")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
this.environment.addFirst(
|
||||
new PropertySource("two", Collections.singletonMap("a.b.c", "${foo}")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
}
|
||||
|
||||
private void whenPlaceholdersSystemProps() {
|
||||
System.setProperty("foo", "bar");
|
||||
this.environment.addFirst(new PropertySource("two", Collections.singletonMap("a.b.c", "${foo}")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
this.environment.addFirst(
|
||||
new PropertySource("two", Collections.singletonMap("a.b.c", "${foo}")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
}
|
||||
|
||||
private void whenPlaceholdersSystemPropsWithDefault() {
|
||||
System.setProperty("foo", "bar");
|
||||
this.environment.addFirst(new PropertySource("two", Collections.singletonMap("a.b.c", "${foo:spam}")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
this.environment.addFirst(new PropertySource("two",
|
||||
Collections.singletonMap("a.b.c", "${foo:spam}")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForEnvironment() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo/bar")).andExpect(MockMvcResultMatchers.status().isOk());
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo/bar"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledEnvironment() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other")).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other"))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo/bar/other")).andExpect(MockMvcResultMatchers.status().isOk());
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo/bar/other"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForYaml() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.yml"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN))
|
||||
.andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN))
|
||||
.andExpect(MockMvcResultMatchers.content().string("{}\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForJson() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.json"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.content()
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.content().string("{}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledYaml() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other")).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other"))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.yml"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.yml")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledProperties() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other")).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other"))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.properties"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.properties")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForProperties() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.properties"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.properties")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledYamlWithHyphen() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo-bar-foo2-bar2", "spam", "other")).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo-bar-foo2-bar2", "spam", "other"))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar-foo2-bar2-spam.yml"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
.andExpect(MockMvcResultMatchers.content()
|
||||
.contentType(MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingforLabelledJsonProperties() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other")).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other"))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.json"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.json")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingforJsonProperties() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.json"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.json")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledJsonPropertiesWithHyphen() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo-bar-foo2-bar2", "spam", "other")).thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo-bar-foo2-bar2", "spam", "other"))
|
||||
.thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar-foo2-bar2-spam.json"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
.andExpect(MockMvcResultMatchers.content()
|
||||
.contentType(MediaType.APPLICATION_JSON));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user