Skip to content

Commit

Permalink
chore: Add jSON and YAML implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
Romuald Rousseau committed Sep 28, 2024
1 parent 9a1bdd7 commit 7f0ceb3
Show file tree
Hide file tree
Showing 10 changed files with 684 additions and 48 deletions.
13 changes: 9 additions & 4 deletions any2json-commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@
<artifactId>snappy-java</artifactId>
<version>${snappy.version}</version>
</dependency>
<!-- Reflections Framework -->
<!-- Jackson Framework -->
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>${reflections.version}</version>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- Test Framework -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,16 @@
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;
import java.util.Map;
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 <T> JSONFactory newFactoryInstance(Class<T> 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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <T> Optional<T> 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 <T> 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 <T> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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<String> keys() {
return new Iterable<String>() {
@Override
public Iterator<String> iterator()
{
return JSONJacksonObject.this.objectNode.fieldNames();
}
};
}

@Override
@SuppressWarnings("unchecked")
public <T> Optional<T> 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 <T> 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();
}
}
Loading

0 comments on commit 7f0ceb3

Please sign in to comment.