Fix YAML output if arrays are nested or contain objects
Fixes gh-92
This commit is contained in:
@@ -21,9 +21,9 @@ import java.net.URLDecoder;
|
||||
import java.security.KeyPair;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -225,7 +225,7 @@ public class EncryptionController {
|
||||
Environment result = new Environment(environment.getName(),
|
||||
environment.getLabel());
|
||||
for (PropertySource source : environment.getPropertySources()) {
|
||||
ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<Object, Object>(
|
||||
Map<Object, Object> map = new LinkedHashMap<Object, Object>(
|
||||
source.getSource());
|
||||
for (Entry<Object,Object> entry : map.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -16,6 +15,8 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.bind.PropertiesConfigurationFactory;
|
||||
import org.springframework.cloud.configure.Environment;
|
||||
import org.springframework.cloud.configure.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;
|
||||
@@ -30,7 +31,9 @@ import org.yaml.snakeyaml.Yaml;
|
||||
@RestController
|
||||
@RequestMapping("${spring.cloud.config.server.prefix:}")
|
||||
public class EnvironmentController {
|
||||
|
||||
|
||||
private static final String MAP_PREFIX = "map";
|
||||
|
||||
@Qualifier("MultipleJGitEnvironmentRepository")
|
||||
private EnvironmentRepository repository;
|
||||
|
||||
@@ -63,7 +66,7 @@ public class EnvironmentController {
|
||||
}
|
||||
return environment;
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("/{name}-{profiles}.properties")
|
||||
public ResponseEntity<String> properties(@PathVariable String name,
|
||||
@PathVariable String profiles) throws IOException {
|
||||
@@ -77,13 +80,14 @@ public class EnvironmentController {
|
||||
throw new IllegalArgumentException(
|
||||
"Properties output not supported for name or profiles containing hyphens");
|
||||
}
|
||||
Properties properties = convertToProperties(labelled(name, profiles, label));
|
||||
Map<String, Object> properties = convertToProperties(labelled(name, profiles,
|
||||
label));
|
||||
return getSuccess(sortLines(properties));
|
||||
}
|
||||
|
||||
private String sortLines(Properties properties) throws IOException {
|
||||
private String sortLines(Map<String, Object> properties) throws IOException {
|
||||
List<String> list = new ArrayList<String>();
|
||||
for (Entry<Object, Object> entry : properties.entrySet()) {
|
||||
for (Entry<String, Object> entry : properties.entrySet()) {
|
||||
if (entry.getKey().equals("spring.profiles")) {
|
||||
continue;
|
||||
}
|
||||
@@ -117,12 +121,18 @@ public class EnvironmentController {
|
||||
LinkedHashMap<String, Object> target = new LinkedHashMap<String, Object>();
|
||||
PropertiesConfigurationFactory<Map<String, Object>> factory = new PropertiesConfigurationFactory<Map<String, Object>>(
|
||||
target);
|
||||
Properties properties = convertToProperties(labelled(name, profiles, label));
|
||||
Map<String, Object> data = convertToProperties(labelled(name, profiles,
|
||||
label));
|
||||
LinkedHashMap<String, Object> properties = new LinkedHashMap<String, Object>();
|
||||
for (String key : data.keySet()) {
|
||||
properties.put(MAP_PREFIX + "." + key, data.get(key));
|
||||
}
|
||||
addArrays(target, properties);
|
||||
factory.setProperties(properties);
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
propertySources.addFirst(new MapPropertySource("properties", properties));
|
||||
factory.setPropertySources(propertySources);
|
||||
factory.bindPropertiesToTarget();
|
||||
Map<String, Object> input = factory.getObject();
|
||||
return getSuccess(new Yaml().dumpAsMap(input));
|
||||
return getSuccess(new Yaml().dumpAsMap(target.get(MAP_PREFIX)));
|
||||
}
|
||||
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
@@ -145,13 +155,14 @@ public class EnvironmentController {
|
||||
* @param target the target Map
|
||||
* @param properties the properties (with key names to check)
|
||||
*/
|
||||
private void addArrays(LinkedHashMap<String, Object> target, Properties properties) {
|
||||
for (String key : properties.stringPropertyNames()) {
|
||||
private void addArrays(LinkedHashMap<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.split(stem, ".");
|
||||
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<String, Object>();
|
||||
@@ -174,24 +185,27 @@ public class EnvironmentController {
|
||||
int position = Integer
|
||||
.valueOf(key.substring(index + 1, key.indexOf("]")));
|
||||
while (position >= value.size()) {
|
||||
value.add("");
|
||||
if (key.indexOf("].", index) > 0) {
|
||||
value.add(new LinkedHashMap<String, Object>());
|
||||
}
|
||||
else {
|
||||
value.add("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Properties convertToProperties(Environment profiles) {
|
||||
Properties map = new Properties();
|
||||
List<PropertySource> sources = new ArrayList<PropertySource>(profiles.getPropertySources());
|
||||
private Map<String, Object> convertToProperties(Environment profiles) {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
List<PropertySource> sources = new ArrayList<PropertySource>(
|
||||
profiles.getPropertySources());
|
||||
Collections.reverse(sources);
|
||||
for (PropertySource source : sources) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> value = (Map<String, String>) source.getSource();
|
||||
map.putAll(value);
|
||||
}
|
||||
for (Entry<Object, Object> entry : map.entrySet()) {
|
||||
map.put(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,6 @@ import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.cloud.configure.Environment;
|
||||
import org.springframework.cloud.configure.PropertySource;
|
||||
import org.springframework.cloud.configure.server.EncryptionController;
|
||||
import org.springframework.cloud.configure.server.EnvironmentController;
|
||||
import org.springframework.cloud.configure.server.EnvironmentRepository;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
@@ -65,7 +62,7 @@ public class EnvironmentControllerTests {
|
||||
|
||||
@Test
|
||||
public void propertyOverrideInYaml() throws Exception {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("a.b.c", "d");
|
||||
environment.add(new PropertySource("one", map));
|
||||
environment.addFirst(new PropertySource("two", Collections.singletonMap("a.b.c", "e")));
|
||||
@@ -85,6 +82,42 @@ public class EnvironmentControllerTests {
|
||||
assertEquals("a:\n b:\n - c\n - d\n", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrayOfObjectInYaml() throws Exception {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("a.b[0].c", "d");
|
||||
map.put("a.b[0].d", "e");
|
||||
map.put("a.b[1].c", "d");
|
||||
environment.add(new PropertySource("one", map));
|
||||
Mockito.when(repository.findOne("foo", "bar", "master")).thenReturn(environment);
|
||||
String yaml = controller.yaml("foo", "bar").getBody();
|
||||
assertEquals("a:\n b:\n - d: e\n c: d\n - c: d\n", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrayOfObjectAtTopLevelInYaml() throws Exception {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("b[0].c", "d");
|
||||
map.put("b[0].d", "e");
|
||||
map.put("b[1].c", "d");
|
||||
environment.add(new PropertySource("one", map));
|
||||
Mockito.when(repository.findOne("foo", "bar", "master")).thenReturn(environment);
|
||||
String yaml = controller.yaml("foo", "bar").getBody();
|
||||
assertEquals("b:\n- c: d\n d: e\n- c: d\n", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrayOfObjectNestedLevelInYaml() throws Exception {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("x.a.b[0].c", "d");
|
||||
map.put("x.a.b[0].d", "e");
|
||||
map.put("x.a.b[1].c", "d");
|
||||
environment.add(new PropertySource("one", map));
|
||||
Mockito.when(repository.findOne("foo", "bar", "master")).thenReturn(environment);
|
||||
String yaml = controller.yaml("foo", "bar").getBody();
|
||||
assertEquals("x:\n a:\n b:\n - c: d\n d: e\n - c: d\n", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForEnvironment() throws Exception {
|
||||
Mockito.when(repository.findOne("foo", "bar", "master")).thenReturn(environment);
|
||||
|
||||
Reference in New Issue
Block a user