diff --git a/pom.xml b/pom.xml index 6096e09..bfe02ac 100644 --- a/pom.xml +++ b/pom.xml @@ -124,6 +124,11 @@ maven-plugin-annotations provided + + org.yaml + snakeyaml + 2.3 + diff --git a/src/main/java/org/codehaus/mojo/properties/managers/YmlPropertiesManager.java b/src/main/java/org/codehaus/mojo/properties/managers/YmlPropertiesManager.java new file mode 100644 index 0000000..23182b6 --- /dev/null +++ b/src/main/java/org/codehaus/mojo/properties/managers/YmlPropertiesManager.java @@ -0,0 +1,108 @@ +package org.codehaus.mojo.properties.managers; + +import javax.inject.Named; +import javax.inject.Singleton; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.yaml.snakeyaml.Yaml; + +/** + * Properties manager using YAML as backand. + */ +@Named +@Singleton +public class YmlPropertiesManager implements PropertiesManager { + + private static final String SUPPORTED_EXTENSION_YML = "yml"; + private static final String SUPPORTED_EXTENSION_YAML = "yaml"; + + @Override + public boolean isExtensionSupport(final String extension) { + return SUPPORTED_EXTENSION_YML.equals(extension) || SUPPORTED_EXTENSION_YAML.equals(extension); + } + + @Override + public Properties load(final InputStream in) throws IOException { + final Properties properties = new Properties(); + final Map map = flattenYamlToMap("", new Yaml().load(in)); + properties.putAll(map); + return properties; + } + + public Map flattenYamlToMap(String parentKey, final Map yamlMap) { + if (parentKey != null && !parentKey.trim().isEmpty()) { + parentKey = parentKey.trim() + "."; + } + final Map result = new HashMap<>(); + + for (final Map.Entry entry : yamlMap.entrySet()) { + final String key = String.format("%s%s", parentKey, entry.getKey().trim()); + final Object value = entry.getValue(); + if (value instanceof Map) { + final Map stringObjectMap = flattenYamlToMap(key, (Map) value); + result.putAll(stringObjectMap); + } else if (value instanceof Collection) { + final Object[] values = ((Collection) value).toArray(); + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof Map) { + result.putAll(flattenYamlToMap( + String.format("%s%s[%d]", parentKey, entry.getKey(), i), (Map) values[i])); + } else { + result.put(String.format("%s%s[%d]", parentKey, entry.getKey(), i), String.valueOf(values[i])); + } + } + } else { + result.put(key, value); + } + } + return result; + } + + @Override + public void save(final Properties properties, final OutputStream out, String comments) throws IOException { + + final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(out, StandardCharsets.ISO_8859_1); + + try (PrintWriter pw = new PrintWriter(outputStreamWriter); + StringWriter sw = new StringWriter()) { + properties.store(sw, comments); + comments = '#' + comments; + + final List lines = new ArrayList<>(); + try (BufferedReader r = new BufferedReader(new StringReader(sw.toString()))) { + String line; + while ((line = r.readLine()) != null) { + if (!line.startsWith("#") || line.equals(comments)) { + lines.add(line); + } + } + } + + Collections.sort(lines); + for (final String l : lines) { + pw.println(l); + } + } + } + + @Override + public String toString() { + return String.format("%s [extension=%s]", getClass().getSimpleName(), SUPPORTED_EXTENSION_YML); + } +} diff --git a/src/test/java/org/codehaus/mojo/properties/managers/YmlPropertiesManagerTest.java b/src/test/java/org/codehaus/mojo/properties/managers/YmlPropertiesManagerTest.java new file mode 100644 index 0000000..e0d4eb2 --- /dev/null +++ b/src/test/java/org/codehaus/mojo/properties/managers/YmlPropertiesManagerTest.java @@ -0,0 +1,55 @@ +package org.codehaus.mojo.properties.managers; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Properties; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class YmlPropertiesManagerTest { + + private static final String NL = System.lineSeparator(); + + private final YmlPropertiesManager manager = new YmlPropertiesManager(); + + @Test + public void testLoad() throws IOException { + + // given + final String props = "# comments" + NL + NL + "key1:" + NL + " key2: value1" + NL + "key3: value2" + NL + + "key4: " + NL + " - A" + NL + " - B" + NL + " - C" + NL; + + final ByteArrayInputStream inputStream = new ByteArrayInputStream(props.getBytes()); + + // when + final Properties properties = manager.load(inputStream); + + // then + assertEquals(5, properties.size()); + assertEquals("value1", properties.getProperty("key1.key2")); + assertEquals("value2", properties.getProperty("key3")); + assertEquals("A", properties.getProperty("key4[0]")); + } + + @Test + public void testSave() throws IOException { + + // given + final Properties properties = new Properties(); + properties.setProperty("key1", "value1"); + properties.setProperty("key2", "value2"); + + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + // when + manager.save(properties, outputStream, "Test comments"); + + // then + final String expected = "#Test comments" + NL + "key1=value1" + NL + "key2=value2" + NL; + + assertEquals(expected, outputStream.toString()); + } +}