From 7f0ceb38fb6f0847808b7ab637f5d67ceb8838ec Mon Sep 17 00:00:00 2001 From: Romuald Rousseau Date: Sat, 28 Sep 2024 10:54:17 +0800 Subject: [PATCH] chore: Add jSON and YAML implementations --- any2json-commons/pom.xml | 13 +- .../any2json/commons/json/JSON.java | 24 +--- .../json/jackson/JSONJacksonArray.java | 108 +++++++++++++++ .../json/jackson/JSONJacksonFactory.java | 123 +++++++++++++++++ .../json/jackson/JSONJacksonObject.java | 98 +++++++++++++ .../any2json/commons/yaml/YAML.java | 24 +--- .../yaml/jackson/YAMLJacksonArray.java | 108 +++++++++++++++ .../yaml/jackson/YAMLJacksonFactory.java | 129 ++++++++++++++++++ .../yaml/jackson/YAMLJacksonObject.java | 99 ++++++++++++++ any2json/pom.xml | 6 + 10 files changed, 684 insertions(+), 48 deletions(-) create mode 100644 any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonArray.java create mode 100644 any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonFactory.java create mode 100644 any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonObject.java create mode 100644 any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonArray.java create mode 100644 any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonFactory.java create mode 100644 any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonObject.java diff --git a/any2json-commons/pom.xml b/any2json-commons/pom.xml index 6bd3eec3..a029c628 100644 --- a/any2json-commons/pom.xml +++ b/any2json-commons/pom.xml @@ -35,11 +35,16 @@ snappy-java ${snappy.version} - + - org.reflections - reflections - ${reflections.version} + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.version} diff --git a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/JSON.java b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/JSON.java index ec6a0f23..4539e07c 100644 --- a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/JSON.java +++ b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/JSON.java @@ -1,6 +1,5 @@ package com.github.romualdrousseau.any2json.commons.json; -import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.util.Arrays; import java.util.List; @@ -8,29 +7,10 @@ import java.util.Optional; import java.util.stream.Stream; -import org.reflections.Reflections; +import com.github.romualdrousseau.any2json.commons.json.jackson.JSONJacksonFactory; public class JSON { - public final static String PACKAGE_LOADER_PREFIX = "com.github.romualdrousseau.shuju.json"; - - private static JSONFactory Factory; - static { - final Reflections reflections = new Reflections(PACKAGE_LOADER_PREFIX); - JSON.Factory = reflections.getSubTypesOf(JSONFactory.class).stream() - .map(JSON::newFactoryInstance) - .findFirst() - .get(); - } - - private static JSONFactory newFactoryInstance(Class clazz) { - try { - return (JSONFactory) clazz.getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException - | IllegalArgumentException | InvocationTargetException - | NoSuchMethodException | SecurityException e) { - throw new RuntimeException(e); - } - } + private static JSONFactory Factory = new JSONJacksonFactory(); public static JSONArray newArray() { return JSON.Factory.newArray(); diff --git a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonArray.java b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonArray.java new file mode 100644 index 00000000..e8e73cee --- /dev/null +++ b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonArray.java @@ -0,0 +1,108 @@ +package com.github.romualdrousseau.any2json.commons.json.jackson; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Optional; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.github.romualdrousseau.any2json.commons.json.JSONArray; +import com.github.romualdrousseau.any2json.commons.json.JSONObject; + +public class JSONJacksonArray implements JSONArray { + private ObjectMapper mapper; + protected ArrayNode arrayNode; + + public JSONJacksonArray(ObjectMapper mapper, JsonNode node) { + this.mapper = mapper; + if (node == null) { + this.arrayNode = mapper.createArrayNode(); + } else { + this.arrayNode = (ArrayNode) node; + } + } + + protected JsonNode getJsonNode() { + return this.arrayNode; + } + + @Override + public int size() { + return (this.arrayNode == null) ? 0 : this.arrayNode.size(); + } + + @Override + @SuppressWarnings("unchecked") + public Optional get(final int i) { + final var node = this.arrayNode.get(i); + if (node == null) { + return Optional.empty(); + } + final T object; + if (node.isObject()) { + object = (T) new JSONJacksonObject(this.mapper, node); + } else if (node.isArray()) { + object = (T) new JSONJacksonArray(this.mapper, node); + } else if (node.isInt()) { + object = (T) Integer.valueOf(node.intValue()); + } else if (node.isFloat()) { + object = (T) Float.valueOf(node.floatValue()); + } else { + object = (T) node.textValue(); + } + return Optional.ofNullable(object); + } + + @Override + public JSONArray set(final int i, final T o) { + if (o instanceof JSONObject) { + this.arrayNode.set(i, ((JSONJacksonObject) o).getJsonNode()); + } else if (o instanceof JSONArray) { + this.arrayNode.set(i, ((JSONJacksonArray) o).getJsonNode()); + } else { + this.arrayNode.set(i, this.mapper.convertValue(o, JsonNode.class)); + } + return this; + } + + @Override + public JSONArray append(final T o) { + if (o instanceof JSONObject) { + this.arrayNode.add(((JSONJacksonObject) o).getJsonNode()); + } else if (o instanceof JSONArray) { + this.arrayNode.add(((JSONJacksonArray) o).getJsonNode()); + } else if (o instanceof Integer) { + this.arrayNode.add((Integer) o); + } else if (o instanceof Float) { + this.arrayNode.add((Float) o); + } else { + this.arrayNode.add(o.toString()); + } + return this; + } + + @Override + public JSONArray remove(final int i) { + this.arrayNode.remove(i); + return this; + } + + public String toString(final boolean pretty) { + try { + if (pretty) { + return this.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this.getJsonNode()); + } else { + return this.mapper.writeValueAsString(this.getJsonNode()); + } + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + //return this.objectNode.toString(); + } + + @Override + public String toString() { + return this.arrayNode.toString(); + } +} diff --git a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonFactory.java b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonFactory.java new file mode 100644 index 00000000..f4092f5a --- /dev/null +++ b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonFactory.java @@ -0,0 +1,123 @@ +package com.github.romualdrousseau.any2json.commons.json.jackson; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.io.FileInputStream; +import java.io.IOException; + +import com.fasterxml.jackson.core.StreamReadConstraints; +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.romualdrousseau.any2json.commons.json.JSONArray; +import com.github.romualdrousseau.any2json.commons.json.JSONFactory; +import com.github.romualdrousseau.any2json.commons.json.JSONObject; + +public class JSONJacksonFactory implements JSONFactory { + private final ObjectMapper mapper; + + public JSONJacksonFactory() { + this.mapper = new ObjectMapper(); + + DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); + prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); + mapper.setDefaultPrettyPrinter(prettyPrinter); + + final StreamReadConstraints streamReadConstraints = StreamReadConstraints + .builder() + .maxStringLength(Integer.MAX_VALUE) + .build(); + this.mapper.getFactory().setStreamReadConstraints(streamReadConstraints); + } + + public JSONArray newArray() { + return new JSONJacksonArray(this.mapper, this.mapper.createArrayNode()); + } + + public JSONArray parseArray(final String data) { + try { + return new JSONJacksonArray(this.mapper, this.mapper.readTree(data)); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public JSONArray parseArray(final Object object) { + return new JSONJacksonArray(this.mapper, (JsonNode) object); + } + + public JSONArray loadArray(final Path filePath) { + try (BufferedReader reader = this.createReader(filePath)) { + return new JSONJacksonArray(this.mapper, this.mapper.readTree(reader)); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public void saveArray(final JSONArray a, final Path filePath, final boolean pretty) { + try { + if (pretty) { + mapper.writerWithDefaultPrettyPrinter().writeValue(filePath.toFile(), ((JSONJacksonArray) a).arrayNode); + } else{ + mapper.writeValue(filePath.toFile(), ((JSONJacksonArray) a).arrayNode); + } + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public JSONObject newObject() { + return new JSONJacksonObject(this.mapper, this.mapper.createObjectNode()); + } + + public JSONObject parseObject(final String data) { + try { + return new JSONJacksonObject(this.mapper, this.mapper.readTree(data)); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public JSONObject parseObject(final Object object) { + return new JSONJacksonObject(this.mapper, (JsonNode) object); + } + + public JSONObject loadObject(final Path filePath) { + try (BufferedReader reader = this.createReader(filePath)) { + return new JSONJacksonObject(this.mapper, this.mapper.readTree(reader)); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public void saveObject(final JSONObject o, final Path filePath, final boolean pretty) { + try { + if (pretty) { + mapper.writerWithDefaultPrettyPrinter().writeValue(filePath.toFile(), ((JSONJacksonObject) o).objectNode); + } else{ + mapper.writeValue(filePath.toFile(), ((JSONJacksonObject) o).objectNode); + } + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + private BufferedReader createReader(final Path filePath) throws IOException { + final BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(filePath.toFile()), StandardCharsets.UTF_8)); + + // consume the Unicode BOM (byte order marker) if present + reader.mark(1); + final int c = reader.read(); + // if not the BOM, back up to the beginning again + if (c != '\uFEFF') { + reader.reset(); + } + + return reader; + } +} diff --git a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonObject.java b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonObject.java new file mode 100644 index 00000000..661f5e28 --- /dev/null +++ b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/json/jackson/JSONJacksonObject.java @@ -0,0 +1,98 @@ +package com.github.romualdrousseau.any2json.commons.json.jackson; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Iterator; +import java.util.Optional; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.github.romualdrousseau.any2json.commons.json.JSONObject; +import com.github.romualdrousseau.any2json.commons.json.JSONArray; + +public class JSONJacksonObject implements JSONObject { + private final ObjectMapper mapper; + protected ObjectNode objectNode; + + public JSONJacksonObject(final ObjectMapper mapper, final JsonNode node) { + this.mapper = mapper; + if (node == null) { + this.objectNode = mapper.createObjectNode(); + } else { + this.objectNode = (ObjectNode) node; + } + } + + protected JsonNode getJsonNode() { + return this.objectNode; + } + + @Override + public Iterable keys() { + return new Iterable() { + @Override + public Iterator iterator() + { + return JSONJacksonObject.this.objectNode.fieldNames(); + } + }; + } + + @Override + @SuppressWarnings("unchecked") + public Optional get(final String k) { + final JsonNode node = this.objectNode.get(k); + if (node == null) { + return Optional.empty(); + } + final T object; + if (node.isObject()) { + object = (T) new JSONJacksonObject(this.mapper, node); + } else if (node.isArray()) { + object = (T) new JSONJacksonArray(this.mapper, node); + } else if (node.isInt()) { + object = (T) Integer.valueOf(node.intValue()); + } else if (node.isFloat()) { + object = (T) Float.valueOf(node.floatValue()); + } else { + object = (T) node.textValue(); + } + return Optional.ofNullable(object); + } + + @Override + public JSONObject set(final String k, final T o) { + if (o instanceof JSONObject) { + this.objectNode.set(k, ((JSONJacksonObject) o).getJsonNode()); + } else if (o instanceof JSONArray) { + this.objectNode.set(k, ((JSONJacksonArray) o).getJsonNode()); + } else { + this.objectNode.set(k, this.mapper.convertValue(o, JsonNode.class)); + } + return this; + } + + @Override + public JSONObject remove(final String k) { + this.objectNode.remove(k); + return this; + } + + public String toString(final boolean pretty) { + try { + if (pretty) { + return this.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this.getJsonNode()); + } else { + return this.mapper.writeValueAsString(this.getJsonNode()); + } + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public String toString() { + return this.objectNode.toString(); + } +} diff --git a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/YAML.java b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/YAML.java index b4ddd0f7..e6d94f38 100644 --- a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/YAML.java +++ b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/YAML.java @@ -1,6 +1,5 @@ package com.github.romualdrousseau.any2json.commons.yaml; -import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.util.Arrays; import java.util.List; @@ -8,29 +7,10 @@ import java.util.Optional; import java.util.stream.Stream; -import org.reflections.Reflections; +import com.github.romualdrousseau.any2json.commons.yaml.jackson.YAMLJacksonFactory; public class YAML { - public final static String PACKAGE_LOADER_PREFIX = "com.github.romualdrousseau.shuju.yaml"; - - private static YAMLFactory Factory; - static { - final var reflections = new Reflections(PACKAGE_LOADER_PREFIX); - YAML.Factory = reflections.getSubTypesOf(YAMLFactory.class).stream() - .map(YAML::newFactoryInstance) - .findFirst() - .get(); - } - - private static YAMLFactory newFactoryInstance(final Class clazz) { - try { - return (YAMLFactory) clazz.getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException - | IllegalArgumentException | InvocationTargetException - | NoSuchMethodException | SecurityException e) { - throw new RuntimeException(e); - } - } + private static YAMLFactory Factory = new YAMLJacksonFactory(); public static YAMLArray newArray() { return YAML.Factory.newArray(); diff --git a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonArray.java b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonArray.java new file mode 100644 index 00000000..20b41d6e --- /dev/null +++ b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonArray.java @@ -0,0 +1,108 @@ +package com.github.romualdrousseau.any2json.commons.yaml.jackson; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Optional; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.github.romualdrousseau.any2json.commons.yaml.YAMLArray; +import com.github.romualdrousseau.any2json.commons.yaml.YAMLObject; + +public class YAMLJacksonArray implements YAMLArray { + private final ObjectMapper mapper; + private final ArrayNode arrayNode; + + public YAMLJacksonArray(final ObjectMapper mapper, final JsonNode node) { + this.mapper = mapper; + if (node == null) { + this.arrayNode = mapper.createArrayNode(); + } else { + this.arrayNode = (ArrayNode) node; + } + } + + protected JsonNode getJsonNode() { + return this.arrayNode; + } + + @Override + public int size() { + return (this.arrayNode == null) ? 0 : this.arrayNode.size(); + } + + @Override + @SuppressWarnings("unchecked") + public Optional get(final int i) { + final var node = this.arrayNode.get(i); + if (node == null) { + return Optional.empty(); + } + final T object; + if (node.isObject()) { + object = (T) new YAMLJacksonObject(this.mapper, node); + } else if (node.isArray()) { + object = (T) new YAMLJacksonArray(this.mapper, node); + } else if (node.isInt()) { + object = (T) Integer.valueOf(node.intValue()); + } else if (node.isFloat()) { + object = (T) Float.valueOf(node.floatValue()); + } else { + object = (T) node.textValue(); + } + return Optional.ofNullable(object); + } + + @Override + public YAMLArray set(final int i, final T o) { + if (o instanceof YAMLObject) { + this.arrayNode.set(i, ((YAMLJacksonObject) o).getJsonNode()); + } else if (o instanceof YAMLArray) { + this.arrayNode.set(i, ((YAMLJacksonArray) o).getJsonNode()); + } else { + this.arrayNode.set(i, this.mapper.convertValue(o, JsonNode.class)); + } + return this; + } + + @Override + public YAMLArray append(final T o) { + if (o instanceof YAMLObject) { + this.arrayNode.add(((YAMLJacksonObject) o).getJsonNode()); + } else if (o instanceof YAMLArray) { + this.arrayNode.add(((YAMLJacksonArray) o).getJsonNode()); + } else if (o instanceof Integer) { + this.arrayNode.add((Integer) o); + } else if (o instanceof Float) { + this.arrayNode.add((Float) o); + } else { + this.arrayNode.add(o.toString()); + } + return this; + } + + @Override + public YAMLArray remove(final int i) { + this.arrayNode.remove(i); + return this; + } + + public String toString(final boolean pretty) { + try { + if (pretty) { + return this.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this.getJsonNode()); + } else { + return this.mapper.writeValueAsString(this.getJsonNode()); + } + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + //return this.objectNode.toString(); + } + + @Override + public String toString() { + return this.arrayNode.toString(); + } +} diff --git a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonFactory.java b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonFactory.java new file mode 100644 index 00000000..effd7456 --- /dev/null +++ b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonFactory.java @@ -0,0 +1,129 @@ +package com.github.romualdrousseau.any2json.commons.yaml.jackson; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.io.FileInputStream; +import java.io.IOException; + +import com.fasterxml.jackson.core.StreamReadConstraints; +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; +import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; +import com.github.romualdrousseau.any2json.commons.yaml.YAMLArray; +import com.github.romualdrousseau.any2json.commons.yaml.YAMLFactory; +import com.github.romualdrousseau.any2json.commons.yaml.YAMLObject; + +public class YAMLJacksonFactory implements YAMLFactory { + private final ObjectMapper mapper; + + public YAMLJacksonFactory() { + this.mapper = YAMLMapper.builder() + .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER) + .build(); + + DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); + prettyPrinter.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE); + mapper.setDefaultPrettyPrinter(prettyPrinter); + + final StreamReadConstraints streamReadConstraints = StreamReadConstraints + .builder() + .maxStringLength(Integer.MAX_VALUE) + .build(); + this.mapper.getFactory().setStreamReadConstraints(streamReadConstraints); + } + + public YAMLArray newArray() { + return new YAMLJacksonArray(this.mapper, this.mapper.createArrayNode()); + } + + public YAMLArray parseArray(final String data) { + try { + return new YAMLJacksonArray(this.mapper, this.mapper.readTree(data)); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public YAMLArray parseArray(final Object object) { + return new YAMLJacksonArray(this.mapper, (JsonNode) object); + } + + public YAMLArray loadArray(final Path filePath) { + try (BufferedReader reader = this.createReader(filePath)) { + return new YAMLJacksonArray(this.mapper, this.mapper.readTree(reader)); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public void saveArray(final YAMLArray a, final Path filePath, final boolean pretty) { + try { + final var aa = (YAMLJacksonArray) a; + if (pretty) { + this.mapper.writerWithDefaultPrettyPrinter().writeValue(filePath.toFile(), aa.getJsonNode()); + } else { + this.mapper.writeValue(filePath.toFile(), aa.getJsonNode()); + } + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public YAMLObject newObject() { + return new YAMLJacksonObject(this.mapper, this.mapper.createObjectNode()); + } + + public YAMLObject parseObject(final String data) { + try { + return new YAMLJacksonObject(this.mapper, this.mapper.readTree(data)); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public YAMLObject parseObject(final Object object) { + return new YAMLJacksonObject(this.mapper, (JsonNode) object); + } + + public YAMLObject loadObject(final Path filePath) { + try (BufferedReader reader = this.createReader(filePath)) { + return new YAMLJacksonObject(this.mapper, this.mapper.readTree(reader)); + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + public void saveObject(final YAMLObject o, final Path filePath, final boolean pretty) { + try { + final var oo = (YAMLJacksonObject) o; + if (pretty) { + this.mapper.writerWithDefaultPrettyPrinter().writeValue(filePath.toFile(), oo.getJsonNode()); + } else { + this.mapper.writeValue(filePath.toFile(), oo.getJsonNode()); + } + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + } + + private BufferedReader createReader(final Path filePath) throws IOException { + final BufferedReader reader = new BufferedReader( + new InputStreamReader(new FileInputStream(filePath.toFile()), StandardCharsets.UTF_8)); + + // consume the Unicode BOM (byte order marker) if present + reader.mark(1); + final int c = reader.read(); + // if not the BOM, back up to the beginning again + if (c != '\uFEFF') { + reader.reset(); + } + + return reader; + } +} diff --git a/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonObject.java b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonObject.java new file mode 100644 index 00000000..d8102104 --- /dev/null +++ b/any2json-commons/src/main/java/com/github/romualdrousseau/any2json/commons/yaml/jackson/YAMLJacksonObject.java @@ -0,0 +1,99 @@ +package com.github.romualdrousseau.any2json.commons.yaml.jackson; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Iterator; +import java.util.Optional; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.github.romualdrousseau.any2json.commons.yaml.YAMLArray; +import com.github.romualdrousseau.any2json.commons.yaml.YAMLObject; + +public class YAMLJacksonObject implements YAMLObject { + private final ObjectMapper mapper; + private final ObjectNode objectNode; + + public YAMLJacksonObject(final ObjectMapper mapper, final JsonNode node) { + this.mapper = mapper; + if (node == null) { + this.objectNode = mapper.createObjectNode(); + } else { + this.objectNode = (ObjectNode) node; + } + } + + protected JsonNode getJsonNode() { + return this.objectNode; + } + + @Override + public Iterable keys() { + return new Iterable() { + @Override + public Iterator iterator() + { + return YAMLJacksonObject.this.objectNode.fieldNames(); + } + }; + } + + @Override + @SuppressWarnings("unchecked") + public Optional get(final String k) { + final JsonNode node = this.objectNode.get(k); + if (node == null) { + return Optional.empty(); + } + final T object; + if (node.isObject()) { + object = (T) new YAMLJacksonObject(this.mapper, node); + } else if (node.isArray()) { + object = (T) new YAMLJacksonArray(this.mapper, node); + } else if (node.isInt()) { + object = (T) Integer.valueOf(node.intValue()); + } else if (node.isFloat()) { + object = (T) Float.valueOf(node.floatValue()); + } else { + object = (T) node.textValue(); + } + return Optional.ofNullable(object); + } + + @Override + public YAMLObject set(final String k, final T o) { + if (o instanceof YAMLObject) { + this.objectNode.set(k, ((YAMLJacksonObject) o).getJsonNode()); + } else if (o instanceof YAMLArray) { + this.objectNode.set(k, ((YAMLJacksonArray) o).getJsonNode()); + } else { + this.objectNode.set(k, this.mapper.convertValue(o, JsonNode.class)); + } + return this; + } + + @Override + public YAMLObject remove(final String k) { + this.objectNode.remove(k); + return this; + } + + public String toString(final boolean pretty) { + try { + if (pretty) { + return this.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(this.getJsonNode()); + } else { + return this.mapper.writeValueAsString(this.getJsonNode()); + } + } catch (final IOException e) { + throw new UncheckedIOException(e); + } + //return this.objectNode.toString(); + } + + @Override + public String toString() { + return this.objectNode.toString(); + } +} diff --git a/any2json/pom.xml b/any2json/pom.xml index 8def13e7..25712239 100644 --- a/any2json/pom.xml +++ b/any2json/pom.xml @@ -31,6 +31,12 @@ jython-standalone ${jython.version} + + + org.reflections + reflections + ${reflections.version} + com.github.romualdrousseau