diff --git a/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/Json.java b/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/Json.java index 74f0141..8af774e 100644 --- a/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/Json.java +++ b/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/Json.java @@ -7,7 +7,10 @@ import org.xbib.datastructures.api.Generator; import org.xbib.datastructures.api.Node; import org.xbib.datastructures.api.Parser; import org.xbib.datastructures.api.TimeValue; + +import java.io.BufferedReader; import java.io.IOException; +import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.time.Instant; @@ -35,9 +38,15 @@ public class Json implements DataStructure { this.separator = separator; } - @SuppressWarnings("unchecked") - public static Map toMap(String yaml) throws IOException { - return (Map) INSTANCE.createParser().parse(new StringReader(yaml)).get(); + public static Map toMap(String json) throws IOException { + return toMap(new StringReader(json)); + } + + public static Map toMap(Reader reader) throws IOException { + // buffered reader is required for mark() support + try (BufferedReader bufferedReader = new BufferedReader(reader)){ + return JsonGenerator.toMap(INSTANCE.createParser().parse(bufferedReader)); + } } public static String toString(Map map) throws IOException { diff --git a/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/JsonBuilder.java b/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/JsonBuilder.java index 0d31dfb..458c6b0 100644 --- a/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/JsonBuilder.java +++ b/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/JsonBuilder.java @@ -263,16 +263,16 @@ public class JsonBuilder implements Builder { int l = string.length(); for (int i = 0; i < l; i++) { char c = string.charAt(i); - if (c == '"' || c < 32 || c >= 127 || c == '\\') { - if (start < i) { - sb.append(string, start, i - start); + if (c == '"' || c == '\\' || c < 32) { + if (i > start) { + sb.append(string, start, i); } - start = i; + start = i + 1; sb.append(escapeCharacter(c)); } } - if (start < l) { - sb.append(string, start, l - start); + if (l > start) { + sb.append(string, start, l); } sb.append('"'); return sb; diff --git a/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/JsonGenerator.java b/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/JsonGenerator.java index 607123a..056de1c 100644 --- a/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/JsonGenerator.java +++ b/datastructures-json-tiny/src/main/java/org/xbib/datastructures/json/tiny/JsonGenerator.java @@ -2,6 +2,8 @@ package org.xbib.datastructures.json.tiny; import org.xbib.datastructures.api.Generator; import org.xbib.datastructures.api.Node; +import org.xbib.datastructures.tiny.TinyList; +import org.xbib.datastructures.tiny.TinyMap; import java.io.IOException; import java.io.Writer; @@ -27,6 +29,11 @@ public class JsonGenerator implements Generator { } } + @SuppressWarnings("unchecked") + public static Map toMap(Node root) { + return (Map) internalMap(root); + } + private void internalWrite(Node curnode) throws IOException { if (curnode instanceof ValueNode) { ValueNode valueNode = (ValueNode) curnode; @@ -49,4 +56,27 @@ public class JsonGenerator implements Generator { builder.endCollection(); } } + + private static Object internalMap(Node curnode) { + if (curnode instanceof ValueNode) { + ValueNode valueNode = (ValueNode) curnode; + return valueNode.get(); + } else if (curnode instanceof MapNode) { + MapNode mapNode = (MapNode) curnode; + TinyMap.Builder map = TinyMap.builder(); + for (Map.Entry> e : mapNode.get().entrySet()) { + map.put(e.getKey().toString(), internalMap(e.getValue())); + } + return map.build(); + } else if (curnode instanceof ListNode) { + ListNode listNode = (ListNode) curnode; + TinyList.Builder list = TinyList.builder(); + for (Node node : listNode.get()) { + list.add(internalMap(node)); + } + return list.build(); + } else { + return null; + } + } } diff --git a/datastructures-json-tiny/src/test/java/org/xbib/datastructures/json/tiny/test/JsonBuilderTest.java b/datastructures-json-tiny/src/test/java/org/xbib/datastructures/json/tiny/test/JsonBuilderTest.java index 79c1a33..d6d61a8 100644 --- a/datastructures-json-tiny/src/test/java/org/xbib/datastructures/json/tiny/test/JsonBuilderTest.java +++ b/datastructures-json-tiny/src/test/java/org/xbib/datastructures/json/tiny/test/JsonBuilderTest.java @@ -1,6 +1,7 @@ package org.xbib.datastructures.json.tiny.test; import org.junit.jupiter.api.Test; +import org.xbib.datastructures.json.tiny.Json; import org.xbib.datastructures.json.tiny.JsonBuilder; import org.xbib.datastructures.json.tiny.StreamParser; @@ -11,9 +12,17 @@ import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class JsonBuilderTest { + @Test + public void testUmlautEncoding() throws IOException{ + JsonBuilder jsonBuilder = new JsonBuilder(); + jsonBuilder.buildMap(Map.of("Hello", "Jörg")); + assertEquals("{\"Hello\":\"Jörg\"}", jsonBuilder.build()); + } + @Test public void testObjectStrFromMap() throws IOException { JsonBuilder jsonBuilder = new JsonBuilder(); @@ -213,4 +222,11 @@ public class JsonBuilderTest { assertEquals("[{\"a\":\"b\"},{\"c\":\"d\"}]", jsonBuilder.build()); } + @SuppressWarnings("unchecked") + @Test + public void testJsonToMap() throws IOException { + Map map = Json.toMap("{\"map\":{\"a\":\"b\"}}"); + assertTrue(map.get("map") instanceof Map); + assertEquals("b", ((Map) map.get("map")).get("a")); + } } diff --git a/datastructures-json-tiny/src/test/java/org/xbib/datastructures/json/tiny/test/ParserTest.java b/datastructures-json-tiny/src/test/java/org/xbib/datastructures/json/tiny/test/ParserTest.java index af84775..f88905e 100644 --- a/datastructures-json-tiny/src/test/java/org/xbib/datastructures/json/tiny/test/ParserTest.java +++ b/datastructures-json-tiny/src/test/java/org/xbib/datastructures/json/tiny/test/ParserTest.java @@ -9,29 +9,33 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.logging.Level; -import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class ParserTest { @Test public void testStringParser() throws IOException { try (InputStream inputStream = ParserTest.class.getResourceAsStream("/org/xbib/datastructures/json/tiny/test/test.json")) { - byte [] b = inputStream.readAllBytes(); - String string = new String(b, StandardCharsets.UTF_8); - StringParser stringParser = new StringParser(new TinyJsonListener()); - stringParser.parse(string); - Logger.getLogger("").log(Level.INFO, stringParser.getNode().get().toString()); - stringParser.parse(string); - Logger.getLogger("").log(Level.INFO, stringParser.getNode().get().toString()); + if (inputStream != null) { + byte[] b = inputStream.readAllBytes(); + String string = new String(b, StandardCharsets.UTF_8); + StringParser stringParser = new StringParser(new TinyJsonListener()); + stringParser.parse(string); + assertEquals("{a=b, c=d, e=[f, g], h={i={j=k}}, l=null, m=true, n=false, o=0, p=1, q=-1, r=0.0, s=1.0, t=2.1, u=-1.0, v=-2.1, w=, x=₫, y=Jörg}", + stringParser.getNode().get().toString()); + } } } @Test public void testStreamParser() throws IOException { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(ParserTest.class.getResourceAsStream("/org/xbib/datastructures/json/tiny/test/test.json")))) { - StreamParser streamParser = new StreamParser(new TinyJsonListener()); - Logger.getLogger("").log(Level.INFO, streamParser.parse(reader).get().toString()); + InputStream inputStream = ParserTest.class.getResourceAsStream("/org/xbib/datastructures/json/tiny/test/test.json"); + if (inputStream != null) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + StreamParser streamParser = new StreamParser(new TinyJsonListener()); + assertEquals("{a=b, c=d, e=[f, g], h={i={j=k}}, l=null, m=true, n=false, o=0, p=1, q=-1, r=0.0, s=1.0, t=2.1, u=-1.0, v=-2.1, w=, x=₫, y=Jörg}", streamParser.parse(reader).get().toString()); + } } } } diff --git a/datastructures-json-tiny/src/test/resources/org/xbib/datastructures/json/tiny/test/test.json b/datastructures-json-tiny/src/test/resources/org/xbib/datastructures/json/tiny/test/test.json index f0cc5f4..25178d9 100644 --- a/datastructures-json-tiny/src/test/resources/org/xbib/datastructures/json/tiny/test/test.json +++ b/datastructures-json-tiny/src/test/resources/org/xbib/datastructures/json/tiny/test/test.json @@ -19,5 +19,6 @@ "u": -1.0, "v": -2.1, "w": "", - "x": "\u20AB" + "x": "\u20AB", + "y": "Jörg" } diff --git a/datastructures-yaml-tiny/src/main/java/org/xbib/datastructures/yaml/tiny/Yaml.java b/datastructures-yaml-tiny/src/main/java/org/xbib/datastructures/yaml/tiny/Yaml.java index 2692fa7..941be91 100644 --- a/datastructures-yaml-tiny/src/main/java/org/xbib/datastructures/yaml/tiny/Yaml.java +++ b/datastructures-yaml-tiny/src/main/java/org/xbib/datastructures/yaml/tiny/Yaml.java @@ -3,7 +3,9 @@ package org.xbib.datastructures.yaml.tiny; import org.xbib.datastructures.api.*; import org.xbib.datastructures.api.Builder; +import java.io.BufferedReader; import java.io.IOException; +import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.time.Instant; @@ -31,9 +33,15 @@ public class Yaml implements DataStructure { this.separator = separator; } - @SuppressWarnings("unchecked") public static Map toMap(String yaml) throws IOException { - return (Map) INSTANCE.createParser().parse(new StringReader(yaml)).get(); + return toMap(new StringReader(yaml)); + } + + public static Map toMap(Reader reader) throws IOException { + // buffered reader is required for mark() support + try (BufferedReader bufferedReader = new BufferedReader(reader)){ + return YamlGenerator.toMap(INSTANCE.createParser().parse(bufferedReader)); + } } public static String toString(Map map) throws IOException { diff --git a/datastructures-yaml-tiny/src/main/java/org/xbib/datastructures/yaml/tiny/YamlGenerator.java b/datastructures-yaml-tiny/src/main/java/org/xbib/datastructures/yaml/tiny/YamlGenerator.java index f902f5f..d2ff4c3 100644 --- a/datastructures-yaml-tiny/src/main/java/org/xbib/datastructures/yaml/tiny/YamlGenerator.java +++ b/datastructures-yaml-tiny/src/main/java/org/xbib/datastructures/yaml/tiny/YamlGenerator.java @@ -2,6 +2,8 @@ package org.xbib.datastructures.yaml.tiny; import org.xbib.datastructures.api.Generator; import org.xbib.datastructures.api.Node; +import org.xbib.datastructures.tiny.TinyList; +import org.xbib.datastructures.tiny.TinyMap; import java.io.IOException; import java.io.StringWriter; @@ -27,6 +29,11 @@ public class YamlGenerator implements Generator { this.indent = indent; } + @SuppressWarnings("unchecked") + public static Map toMap(Node root) { + return (Map) internalMap(root); + } + @Override public void generate(Writer writer) throws IOException { this.writer = writer; @@ -156,4 +163,28 @@ public class YamlGenerator implements Generator { } return sb.toString(); } + + + private static Object internalMap(Node curnode) { + if (curnode instanceof ValueNode) { + ValueNode valueNode = (ValueNode) curnode; + return valueNode.get(); + } else if (curnode instanceof MapNode) { + MapNode mapNode = (MapNode) curnode; + TinyMap.Builder map = TinyMap.builder(); + for (Map.Entry> e : mapNode.get().entrySet()) { + map.put(e.getKey().toString(), internalMap(e.getValue())); + } + return map.build(); + } else if (curnode instanceof ListNode) { + ListNode listNode = (ListNode) curnode; + TinyList.Builder list = TinyList.builder(); + for (Node node : listNode.get()) { + list.add(internalMap(node)); + } + return list.build(); + } else { + return null; + } + } } diff --git a/datastructures-yaml-tiny/src/test/java/org/xbib/datastructures/yaml/tiny/test/YamlBuilderTest.java b/datastructures-yaml-tiny/src/test/java/org/xbib/datastructures/yaml/tiny/test/YamlBuilderTest.java index 3925268..742dbb2 100644 --- a/datastructures-yaml-tiny/src/test/java/org/xbib/datastructures/yaml/tiny/test/YamlBuilderTest.java +++ b/datastructures-yaml-tiny/src/test/java/org/xbib/datastructures/yaml/tiny/test/YamlBuilderTest.java @@ -6,10 +6,12 @@ import org.xbib.datastructures.api.DataStructure; import org.xbib.datastructures.tiny.TinyMap; import org.xbib.datastructures.yaml.tiny.Yaml; +import java.io.IOException; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class YamlBuilderTest { @@ -104,4 +106,12 @@ public class YamlBuilderTest { "- e: f\n" + " g: h\n", builder.build()); } + + @SuppressWarnings("unchecked") + @Test + public void testYamlToMap() throws IOException { + Map map = Yaml.toMap("map:\n a: b\n"); + assertTrue(map.get("map") instanceof Map); + assertEquals("b", ((Map) map.get("map")).get("a")); + } }