From cc526c13b993d4d03a80aa4e032a13b3b02be19d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 12 Dec 2024 22:24:46 +1300 Subject: [PATCH] [json-node] Rename JsonNodeAdapter to JsonNodeMapper (#306) * [json-node] Rename JsonNodeAdapter to JsonNodeMapper Although this provides all the JsonAdapters for the JsonNode types, for developers using it directly they will view it more like a "mapper" with convenience methods for toJson() and fromJson() * [json-node] Add NodeMapper API for reading/writing options using all options like InputStream, OutputStream etc --- json-core/src/main/java/module-info.java | 3 +- .../io/avaje/json/node/JsonNodeAdapter.java | 118 ------------ .../io/avaje/json/node/JsonNodeMapper.java | 178 ++++++++++++++++++ .../java/io/avaje/json/node/NodeMapper.java | 78 ++++++++ ...nNodeAdapter.java => DJsonNodeMapper.java} | 41 +++- .../io/avaje/json/node/adapter/DMapper.java | 116 ++++++++++++ .../json/node/adapter/JsonNodeComponent.java | 10 +- .../avaje/json/node/adapter/NodeAdapter.java | 4 +- .../json/node/adapter/NodeAdapterBuilder.java | 14 +- .../io/avaje/json/node/ExtractNodeTest.java | 10 +- .../io/avaje/json/node/JsonArrayTest.java | 4 +- .../io/avaje/json/node/NodeMapperTest.java | 92 +++++++++ .../node/adapter/JsonNodeAdaptersTest.java | 56 +++--- 13 files changed, 549 insertions(+), 175 deletions(-) delete mode 100644 json-node/src/main/java/io/avaje/json/node/JsonNodeAdapter.java create mode 100644 json-node/src/main/java/io/avaje/json/node/JsonNodeMapper.java create mode 100644 json-node/src/main/java/io/avaje/json/node/NodeMapper.java rename json-node/src/main/java/io/avaje/json/node/adapter/{DJsonNodeAdapter.java => DJsonNodeMapper.java} (70%) create mode 100644 json-node/src/main/java/io/avaje/json/node/adapter/DMapper.java create mode 100644 json-node/src/test/java/io/avaje/json/node/NodeMapperTest.java diff --git a/json-core/src/main/java/module-info.java b/json-core/src/main/java/module-info.java index 5f480a3c..1626faac 100644 --- a/json-core/src/main/java/module-info.java +++ b/json-core/src/main/java/module-info.java @@ -1,10 +1,9 @@ module io.avaje.json { exports io.avaje.json; - exports io.avaje.json.core to io.avaje.jsonb; exports io.avaje.json.stream; - exports io.avaje.json.stream.core; exports io.avaje.json.view; + exports io.avaje.json.core to io.avaje.jsonb; requires static io.helidon.webserver; } diff --git a/json-node/src/main/java/io/avaje/json/node/JsonNodeAdapter.java b/json-node/src/main/java/io/avaje/json/node/JsonNodeAdapter.java deleted file mode 100644 index c242cb0a..00000000 --- a/json-node/src/main/java/io/avaje/json/node/JsonNodeAdapter.java +++ /dev/null @@ -1,118 +0,0 @@ -package io.avaje.json.node; - -import io.avaje.json.JsonAdapter; -import io.avaje.json.node.adapter.NodeAdapterBuilder; -import io.avaje.json.stream.JsonStream; - -import java.lang.reflect.Type; - -/** - * Provide JsonAdapters for the JsonNode types. - * - *
{@code
- *
- * static final JsonNodeAdapter node = JsonNodeAdapter.builder().build();
- *
- * JsonArray jsonArray = JsonArray.create()
- * .add(JsonInteger.of(42))
- * .add(JsonString.of("foo"));
- *
- * var asJson = node.toJson(jsonArray);
- *
- * JsonNode jsonNodeFromJson = node.fromJson(asJson);
- * assertThat(jsonNodeFromJson).isInstanceOf(JsonArray.class);
- *
- * JsonArray arrayFromJson = node.fromJson(JsonArray.class, asJson);
- * assertThat(arrayFromJson.elements()).hasSize(2);
- *
- * }
- */ -public interface JsonNodeAdapter { - - /** - * Create a Builder for the JsonNodeAdapter. - */ - static Builder builder() { - return new NodeAdapterBuilder(); - } - - /** - * Return the JsonAdapter for the given JsonNode type. - * - * @param type The JsonNode type - * @return The adapter for the given type - */ - JsonAdapter of(Class type); - - /** - * Helper method to write the node to JSON. - * - *
{@code
-   * static final JsonNodeAdapter node = JsonNodeAdapter.builder().build();
-   *
-   * JsonArray jsonArray = JsonArray.create()
-   * .add(JsonInteger.of(42))
-   * .add(JsonString.of("foo"));
-   *
-   * var asJson = node.toJson(jsonArray);
-   * }
- */ - String toJson(JsonNode node); - - /** - * Helper method to read JSON returning a JsonNode. - * - *
{@code
-   * static final JsonNodeAdapter node = JsonNodeAdapter.builder().build();
-   *
-   * JsonNode nodeFromJson = node.fromJson(jsonContent);
-   * }
- */ - JsonNode fromJson(String json); - - /** - * Helper method to read JSON with an expected JsonNode type. - * - *
{@code
-   * static final JsonNodeAdapter node = JsonNodeAdapter.builder().build();
-   *
-   * JsonArray arrayFromJson = node.fromJson(JsonArray.class, jsonContent);
-   * }
- */ - T fromJson(Class type, String json); - - /** - * Create a JsonAdapter for the given generic type or null if the - * type is not actually a JsonNode type. - */ - JsonAdapter create(Type type); - - /** - * Build the JsonNodeAdapter. - */ - interface Builder { - - /** - * Set the default JsonStream to use when using {@link JsonNodeAdapter#toJson(JsonNode)} - * {@link JsonNodeAdapter#fromJson(String)}. - *

- * When not set this defaults to {@code JsonStream.builder().build()}. - * - * @see JsonStream#builder() - */ - Builder jsonStream(JsonStream jsonStream); - - /** - * Set the adapter to use when reading {@link JsonNode.Type#NUMBER}. - *

- * The default will read as a double and test for the value being an - * integral returning a long if is. - */ - Builder numberAdapter(JsonAdapter numberAdapter); - - /** - * Build and return the JsonNodeAdapter. - */ - JsonNodeAdapter build(); - } -} diff --git a/json-node/src/main/java/io/avaje/json/node/JsonNodeMapper.java b/json-node/src/main/java/io/avaje/json/node/JsonNodeMapper.java new file mode 100644 index 00000000..1a9b4d52 --- /dev/null +++ b/json-node/src/main/java/io/avaje/json/node/JsonNodeMapper.java @@ -0,0 +1,178 @@ +package io.avaje.json.node; + +import io.avaje.json.JsonAdapter; +import io.avaje.json.node.adapter.NodeAdapterBuilder; +import io.avaje.json.stream.JsonStream; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Type; + +/** + * Provide JsonAdapters for the JsonNode types. + * + *

{@code
+ *
+ * static final JsonNodeMapper mapper = JsonNodeMapper.builder().build();
+ *
+ * JsonArray jsonArray = JsonArray.create()
+ * .add(JsonInteger.of(42))
+ * .add(JsonString.of("foo"));
+ *
+ * var asJson = mapper.toJson(jsonArray);
+ *
+ * JsonNode jsonNodeFromJson = mapper.fromJson(asJson);
+ * assertThat(jsonNodeFromJson).isInstanceOf(JsonArray.class);
+ *
+ * JsonArray arrayFromJson = mapper.fromJson(JsonArray.class, asJson);
+ * assertThat(arrayFromJson.elements()).hasSize(2);
+ *
+ * }
+ */ +public interface JsonNodeMapper { + + /** + * Create a Builder for the JsonNodeAdapter. + */ + static Builder builder() { + return new NodeAdapterBuilder(); + } + + /** + * Return a NodeMapper for ANY json content. + *

+ * The NodeMapper provides support for all reading and writing options + * such as InputStream, OutputStream, Reader, Writer etc. + */ + NodeMapper nodeMapper(); + + /** + * Return a NodeMapper for json OBJECT content. + *

+ * The NodeMapper provides support for all reading and writing options + * such as InputStream, OutputStream, Reader, Writer etc. + */ + NodeMapper objectMapper(); + + /** + * Return a NodeMapper for json ARRAY content. + *

+ * The NodeMapper provides support for all reading and writing options + * such as InputStream, OutputStream, Reader, Writer etc. + */ + NodeMapper arrayMapper(); + + /** + * Write the node to JSON string. + *

+ * For options to write json content to OutputStream, Writer etc + * use {@link #nodeMapper()}. + * + *

{@code
+   * static final JsonNodeMapper mapper = JsonNodeMapper.builder().build();
+   *
+   * JsonArray jsonArray = JsonArray.create()
+   * .add(JsonInteger.of(42))
+   * .add(JsonString.of("foo"));
+   *
+   * var asJson = mapper.toJson(jsonArray);
+   * }
+ * + * @see NodeMapper#toJson(JsonNode, OutputStream) + * @see NodeMapper#toJson(JsonNode, Writer) + */ + String toJson(JsonNode node); + + /** + * Read any json content returning a JsonNode. + *

+ * For options to read json content from InputStream, Reader etc + * use the fromJson methods on {@link NodeMapper}. + * + *

{@code
+   * static final JsonNodeMapper mapper = JsonNodeMapper.builder().build();
+   *
+   * JsonNode nodeFromJson = mapper.fromJson(jsonContent);
+   * }
+ * + * @see NodeMapper#fromJson(Reader) + * @see NodeMapper#fromJson(InputStream) + */ + JsonNode fromJson(String json); + + /** + * Read a JsonObject from json string content. + *

+ * Use this when we know that the json content is a JsonObject. + * + * @param json The json content. + * @return The JsonObject parsed from the content. + */ + JsonObject fromJsonObject(String json); + + /** + * Read a JsonArray from json string content. + *

+ * Use this when we know that the json content is a JsonArray. + * + * @param json The json content. + * @return The JsonArray parsed from the content. + */ + JsonArray fromJsonArray(String json); + + /** + * Helper method to read JSON with an expected JsonNode type. + * + *

{@code
+   * static final JsonNodeMapper mapper = JsonNodeMapper.builder().build();
+   *
+   * JsonArray arrayFromJson = mapper.fromJson(JsonArray.class, jsonContent);
+   * }
+ */ + T fromJson(Class type, String json); + + /** + * Return the JsonAdapter for the given JsonNode type. + * + * @param type The JsonNode type + * @return The adapter for the given type + */ + JsonAdapter adapter(Class type); + + /** + * Create a JsonAdapter for the given generic type or null if the + * type is not actually a JsonNode type. + */ + JsonAdapter adapter(Type type); + + /** + * Build the JsonNodeMapper. + */ + interface Builder { + + /** + * Set the default JsonStream to use when using {@link JsonNodeMapper#toJson(JsonNode)} + * {@link JsonNodeMapper#fromJson(String)}. + *

+ * When not set this defaults to {@code JsonStream.builder().build()}. + * + * @see JsonStream#builder() + */ + Builder jsonStream(JsonStream jsonStream); + + /** + * Set the adapter to use when reading {@link JsonNode.Type#NUMBER}. + *

+ * The default will read as a double and test for the value being an + * integral returning a long if is. + */ + Builder numberAdapter(JsonAdapter numberAdapter); + + /** + * Build and return the JsonNodeMapper. + */ + JsonNodeMapper build(); + } +} diff --git a/json-node/src/main/java/io/avaje/json/node/NodeMapper.java b/json-node/src/main/java/io/avaje/json/node/NodeMapper.java new file mode 100644 index 00000000..cb8d9fda --- /dev/null +++ b/json-node/src/main/java/io/avaje/json/node/NodeMapper.java @@ -0,0 +1,78 @@ +package io.avaje.json.node; + +import io.avaje.json.JsonReader; +import io.avaje.json.JsonWriter; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/** + * Mappers for JsonNode, JsonArray and JsonObject. + *

+ * This supports more options for reading and writing json content + * such as InputStream, OutputStream, Reader, Writer etc. + * + * @see JsonNodeMapper#arrayMapper() + * @see JsonNodeMapper#objectMapper() + * @see JsonNodeMapper#nodeMapper() + */ +public interface NodeMapper { + + /** + * Read the return the value from the json content. + */ + T fromJson(String content); + + /** + * Read the return the value from the reader. + */ + T fromJson(JsonReader reader); + + /** + * Read the return the value from the json content. + */ + T fromJson(byte[] content); + + /** + * Read the return the value from the reader. + */ + T fromJson(Reader reader); + + /** + * Read the return the value from the inputStream. + */ + T fromJson(InputStream inputStream); + + /** + * Return as json string. + */ + String toJson(T value); + + /** + * Return as json string in pretty format. + */ + String toJsonPretty(T value); + + /** + * Return the value as json content in bytes form. + */ + byte[] toJsonBytes(T value); + + /** + * Write to the given writer. + */ + void toJson(T value, JsonWriter writer); + + /** + * Write to the given writer. + */ + void toJson(T value, Writer writer); + + /** + * Write to the given outputStream. + */ + void toJson(T value, OutputStream outputStream); + +} diff --git a/json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeAdapter.java b/json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeMapper.java similarity index 70% rename from json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeAdapter.java rename to json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeMapper.java index 0d5350c1..e1bfe5e5 100644 --- a/json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeAdapter.java +++ b/json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeMapper.java @@ -7,7 +7,7 @@ import java.lang.reflect.Type; -final class DJsonNodeAdapter implements JsonNodeAdapter { +final class DJsonNodeMapper implements JsonNodeMapper { static final BooleanAdapter BOOLEAN_ADAPTER = new BooleanAdapter(); static final StringAdapter STRING_ADAPTER = new StringAdapter(); @@ -22,13 +22,28 @@ final class DJsonNodeAdapter implements JsonNodeAdapter { private final ObjectAdapter objectAdapter; private final ArrayAdapter arrayAdapter; - DJsonNodeAdapter(JsonStream jsonStream, NodeAdapter nodeAdapter, ObjectAdapter objectAdapter, ArrayAdapter arrayAdapter) { + DJsonNodeMapper(JsonStream jsonStream, NodeAdapter nodeAdapter, ObjectAdapter objectAdapter, ArrayAdapter arrayAdapter) { this.jsonStream = jsonStream; this.nodeAdapter = nodeAdapter; this.objectAdapter = objectAdapter; this.arrayAdapter = arrayAdapter; } + @Override + public NodeMapper nodeMapper() { + return new DMapper<>(nodeAdapter, jsonStream); + } + + @Override + public NodeMapper objectMapper() { + return new DMapper<>(objectAdapter, jsonStream); + } + + @Override + public NodeMapper arrayMapper() { + return new DMapper<>(arrayAdapter, jsonStream); + } + @Override public String toJson(JsonNode node) { final var writer = jsonStream.bufferedWriter(); @@ -43,9 +58,23 @@ public JsonNode fromJson(String json) { } } + @Override + public JsonObject fromJsonObject(String json) { + try (JsonReader reader = jsonStream.reader(json)) { + return objectAdapter.fromJson(reader); + } + } + + @Override + public JsonArray fromJsonArray(String json) { + try (JsonReader reader = jsonStream.reader(json)) { + return arrayAdapter.fromJson(reader); + } + } + @Override public T fromJson(Class type, String json) { - JsonAdapter adapter = of(type); + JsonAdapter adapter = adapter(type); try (JsonReader reader = jsonStream.reader(json)) { return adapter.fromJson(reader); } @@ -53,11 +82,11 @@ public T fromJson(Class type, String json) { @SuppressWarnings("unchecked") @Override - public JsonAdapter create(Type type) { + public JsonAdapter adapter(Type type) { if (type instanceof Class) { Class cls = (Class) type; if (JsonNode.class.isAssignableFrom(cls)) { - return of((Class)cls); + return adapter((Class)cls); } } return null; @@ -65,7 +94,7 @@ public JsonAdapter create(Type type) { @SuppressWarnings("unchecked") @Override - public JsonAdapter of(Class type) { + public JsonAdapter adapter(Class type) { if (type == JsonNode.class) return (JsonAdapter) nodeAdapter; if (type == JsonObject.class) return (JsonAdapter) objectAdapter; if (type == JsonArray.class) return (JsonAdapter) arrayAdapter; diff --git a/json-node/src/main/java/io/avaje/json/node/adapter/DMapper.java b/json-node/src/main/java/io/avaje/json/node/adapter/DMapper.java new file mode 100644 index 00000000..ca075449 --- /dev/null +++ b/json-node/src/main/java/io/avaje/json/node/adapter/DMapper.java @@ -0,0 +1,116 @@ +package io.avaje.json.node.adapter; + +import io.avaje.json.JsonAdapter; +import io.avaje.json.JsonException; +import io.avaje.json.JsonReader; +import io.avaje.json.JsonWriter; +import io.avaje.json.node.JsonNode; +import io.avaje.json.node.NodeMapper; +import io.avaje.json.stream.BufferedJsonWriter; +import io.avaje.json.stream.BytesJsonWriter; +import io.avaje.json.stream.JsonStream; + +import java.io.*; + +final class DMapper implements NodeMapper { + + private final JsonAdapter adapter; + private final JsonStream jsonStream; + + DMapper(JsonAdapter adapter, JsonStream jsonStream) { + this.adapter = adapter; + this.jsonStream = jsonStream; + } + + @Override + public T fromJson(JsonReader reader) { + return adapter.fromJson(reader); + } + + @Override + public T fromJson(String content) { + try (JsonReader reader = jsonStream.reader(content)) { + return adapter.fromJson(reader); + } + } + + @Override + public T fromJson(byte[] content) { + try (JsonReader reader = jsonStream.reader(content)) { + return adapter.fromJson(reader); + } + } + + @Override + public T fromJson(Reader content) { + try (JsonReader reader = jsonStream.reader(content)) { + return adapter.fromJson(reader); + } + } + + @Override + public T fromJson(InputStream content) { + try (JsonReader reader = jsonStream.reader(content)) { + return adapter.fromJson(reader); + } + } + + @Override + public String toJson(T value) { + try (BufferedJsonWriter writer = jsonStream.bufferedWriter()) { + toJson(value, writer); + return writer.result(); + } + } + + @Override + public String toJsonPretty(T value) { + try (BufferedJsonWriter writer = jsonStream.bufferedWriter()) { + writer.pretty(true); + toJson(value, writer); + return writer.result(); + } + } + + @Override + public byte[] toJsonBytes(T value) { + try (BytesJsonWriter writer = jsonStream.bufferedWriterAsBytes()) { + toJson(value, writer); + return writer.result(); + } + } + + @Override + public void toJson(T value, JsonWriter writer) { + try { + adapter.toJson(writer, value); + } catch (RuntimeException e) { + writer.markIncomplete(); + throw new JsonException(e); + } + } + + @Override + public void toJson(T value, Writer writer) { + try (JsonWriter jsonWriter = jsonStream.writer(writer)) { + toJson(value, jsonWriter); + } + } + + @Override + public void toJson(T value, OutputStream outputStream) { + try (JsonWriter writer = jsonStream.writer(outputStream)) { + toJson(value, writer); + } + close(outputStream); + } + + private void close(Closeable outputStream) { + try { + outputStream.close(); + } catch (IOException e) { + throw new UncheckedIOException("Error closing stream", e); + } + } + +} diff --git a/json-node/src/main/java/io/avaje/json/node/adapter/JsonNodeComponent.java b/json-node/src/main/java/io/avaje/json/node/adapter/JsonNodeComponent.java index 70a21373..e67c5d6d 100644 --- a/json-node/src/main/java/io/avaje/json/node/adapter/JsonNodeComponent.java +++ b/json-node/src/main/java/io/avaje/json/node/adapter/JsonNodeComponent.java @@ -1,7 +1,7 @@ package io.avaje.json.node.adapter; import io.avaje.json.JsonAdapter; -import io.avaje.json.node.JsonNodeAdapter; +import io.avaje.json.node.JsonNodeMapper; import io.avaje.jsonb.AdapterFactory; import io.avaje.jsonb.Jsonb; import io.avaje.jsonb.spi.JsonbComponent; @@ -15,20 +15,20 @@ public final class JsonNodeComponent implements JsonbComponent { @Override public void register(Jsonb.Builder builder) { - builder.add(new JsonBFactory(JsonNodeAdapter.builder().build())); + builder.add(new JsonBFactory(JsonNodeMapper.builder().build())); } private static final class JsonBFactory implements AdapterFactory { - private final JsonNodeAdapter nodeAdapter; + private final JsonNodeMapper nodeAdapter; - JsonBFactory(JsonNodeAdapter nodeAdapter) { + JsonBFactory(JsonNodeMapper nodeAdapter) { this.nodeAdapter = nodeAdapter; } @Override public JsonAdapter create(Type type, Jsonb jsonb) { - return nodeAdapter.create(type); + return nodeAdapter.adapter(type); } } } diff --git a/json-node/src/main/java/io/avaje/json/node/adapter/NodeAdapter.java b/json-node/src/main/java/io/avaje/json/node/adapter/NodeAdapter.java index 66e8e10b..956113af 100644 --- a/json-node/src/main/java/io/avaje/json/node/adapter/NodeAdapter.java +++ b/json-node/src/main/java/io/avaje/json/node/adapter/NodeAdapter.java @@ -14,8 +14,8 @@ final class NodeAdapter implements JsonAdapter { private final JsonAdapter numberAdapter; NodeAdapter(JsonAdapter numberAdapter) { - this.booleanAdapter = DJsonNodeAdapter.BOOLEAN_ADAPTER; - this.stringAdapter = DJsonNodeAdapter.STRING_ADAPTER; + this.booleanAdapter = DJsonNodeMapper.BOOLEAN_ADAPTER; + this.stringAdapter = DJsonNodeMapper.STRING_ADAPTER; this.numberAdapter = numberAdapter; this.arrayAdapter = new ArrayAdapter(this); this.objectAdapter = new ObjectAdapter(this); diff --git a/json-node/src/main/java/io/avaje/json/node/adapter/NodeAdapterBuilder.java b/json-node/src/main/java/io/avaje/json/node/adapter/NodeAdapterBuilder.java index f1919a48..613b5288 100644 --- a/json-node/src/main/java/io/avaje/json/node/adapter/NodeAdapterBuilder.java +++ b/json-node/src/main/java/io/avaje/json/node/adapter/NodeAdapterBuilder.java @@ -1,38 +1,38 @@ package io.avaje.json.node.adapter; import io.avaje.json.JsonAdapter; -import io.avaje.json.node.JsonNodeAdapter; +import io.avaje.json.node.JsonNodeMapper; import io.avaje.json.node.JsonNumber; import io.avaje.json.stream.JsonStream; /** * Builder for JsonNodeAdapter. */ -public final class NodeAdapterBuilder implements JsonNodeAdapter.Builder { +public final class NodeAdapterBuilder implements JsonNodeMapper.Builder { private JsonStream jsonStream; private JsonAdapter numberAdapter; @Override - public JsonNodeAdapter.Builder jsonStream(JsonStream jsonStream) { + public JsonNodeMapper.Builder jsonStream(JsonStream jsonStream) { this.jsonStream = jsonStream; return this; } @Override - public JsonNodeAdapter.Builder numberAdapter(JsonAdapter numberAdapter) { + public JsonNodeMapper.Builder numberAdapter(JsonAdapter numberAdapter) { this.numberAdapter = numberAdapter; return this; } @Override - public JsonNodeAdapter build() { + public JsonNodeMapper build() { final var stream = jsonStream != null ? jsonStream : JsonStream.builder().build(); - final var number = numberAdapter != null ? numberAdapter : DJsonNodeAdapter.NUMBER_ADAPTER; + final var number = numberAdapter != null ? numberAdapter : DJsonNodeMapper.NUMBER_ADAPTER; final var nodeAdapter = new NodeAdapter(number); final var objectAdapter = nodeAdapter.objectAdapter(); final var arrayAdapter = nodeAdapter.arrayAdapter(); - return new DJsonNodeAdapter(stream, nodeAdapter, objectAdapter, arrayAdapter); + return new DJsonNodeMapper(stream, nodeAdapter, objectAdapter, arrayAdapter); } } diff --git a/json-node/src/test/java/io/avaje/json/node/ExtractNodeTest.java b/json-node/src/test/java/io/avaje/json/node/ExtractNodeTest.java index cae8753e..d8a2fbf3 100644 --- a/json-node/src/test/java/io/avaje/json/node/ExtractNodeTest.java +++ b/json-node/src/test/java/io/avaje/json/node/ExtractNodeTest.java @@ -39,12 +39,12 @@ class ExtractNodeTest { " ]\n" + " }"; - static final JsonNodeAdapter node = JsonNodeAdapter.builder().build(); + static final JsonNodeMapper mapper = JsonNodeMapper.builder().build(); @Test void extract() { - JsonObject object = ExtractNodeTest.node.fromJson(JsonObject.class, content); + JsonObject object = mapper.fromJsonObject(content); JsonArray arrayWithNestedPerson = (JsonArray) object.get("people"); List peopleNodes = @@ -79,7 +79,7 @@ void extract() { @Test void extractMissing_expect_IllegalArgumentException() { - JsonObject object = ExtractNodeTest.node.fromJson(JsonObject.class, content); + JsonObject object = ExtractNodeTest.mapper.fromJsonObject(content); assertThatThrownBy(() -> object.extractNode("missing.path.here")) .isInstanceOf(IllegalArgumentException.class) @@ -88,7 +88,7 @@ void extractMissing_expect_IllegalArgumentException() { @Test void extractMissing_missing_object() { - JsonObject object = ExtractNodeTest.node.fromJson(JsonObject.class, content); + JsonObject object = ExtractNodeTest.mapper.fromJsonObject(content); JsonNode result = object.extractNode("missing.path.here", JsonObject.empty()); assertThat(result).isSameAs(JsonObject.empty()); @@ -96,7 +96,7 @@ void extractMissing_missing_object() { @Test void extractMissing_missing_array() { - JsonObject object = ExtractNodeTest.node.fromJson(JsonObject.class, content); + JsonObject object = ExtractNodeTest.mapper.fromJson(JsonObject.class, content); JsonNode result = object.extractNode("missing.path.here", JsonArray.empty()); assertThat(result).isSameAs(JsonArray.empty()); diff --git a/json-node/src/test/java/io/avaje/json/node/JsonArrayTest.java b/json-node/src/test/java/io/avaje/json/node/JsonArrayTest.java index 64a7087a..4c9090bc 100644 --- a/json-node/src/test/java/io/avaje/json/node/JsonArrayTest.java +++ b/json-node/src/test/java/io/avaje/json/node/JsonArrayTest.java @@ -36,7 +36,7 @@ class JsonArrayTest { " ]\n" + "}"; - static final JsonNodeAdapter node = JsonNodeAdapter.builder().build(); + static final JsonNodeMapper mapper = JsonNodeMapper.builder().build(); static final JsonArray basicArray = JsonArray.create() .add(JsonInteger.of(42)) @@ -45,7 +45,7 @@ class JsonArrayTest { @Test void streamFilter() { - JsonObject top = node.fromJson(JsonObject.class, input); + JsonObject top = mapper.fromJson(JsonObject.class, input); JsonArray phoneNumbers = (JsonArray)top.get("phoneNumbers"); List result = diff --git a/json-node/src/test/java/io/avaje/json/node/NodeMapperTest.java b/json-node/src/test/java/io/avaje/json/node/NodeMapperTest.java new file mode 100644 index 00000000..bc8ce2e5 --- /dev/null +++ b/json-node/src/test/java/io/avaje/json/node/NodeMapperTest.java @@ -0,0 +1,92 @@ +package io.avaje.json.node; + +import io.avaje.json.JsonWriter; +import io.avaje.json.stream.JsonStream; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.StringWriter; + +import static org.assertj.core.api.Assertions.assertThat; + +class NodeMapperTest { + + static final JsonNodeMapper mapper = JsonNodeMapper.builder().build(); + static final NodeMapper nodeMapper = mapper.nodeMapper(); + + @Test + void toJson() { + var obj = JsonObject.create().add("greet", "hi"); + + var asJson = nodeMapper.toJson(obj); + assertThat(asJson).isEqualTo("{\"greet\":\"hi\"}"); + } + + @Test + void toJsonPretty() { + var obj = JsonObject.create().add("greet", "hi"); + + String asJsonPretty = nodeMapper.toJsonPretty(obj); + assertThat(asJsonPretty).isEqualTo("{\n" + + " \"greet\": \"hi\"\n" + + "}"); + } + + @Test + void toJsonWriter() { + var obj = JsonObject.create().add("greet", "hi"); + + StringWriter writer = new StringWriter(); + nodeMapper.toJson(obj, writer); + assertThat(writer.toString()).isEqualTo("{\"greet\":\"hi\"}"); + } + + @Test + void toJsonWriteBytes() { + var obj = JsonObject.create().add("greet", "hi"); + + var baos = new ByteArrayOutputStream(); + nodeMapper.toJson(obj, baos); + String asStr = baos.toString(); + assertThat(asStr).isEqualTo("{\"greet\":\"hi\"}"); + } + + @Test + void toJsonBytes() { + var obj = JsonObject.create().add("greet", "hi"); + + var bytes = nodeMapper.toJsonBytes(obj); + String asStr = new String(bytes); + assertThat(asStr).isEqualTo("{\"greet\":\"hi\"}"); + } + + @Test + void toJsonUsingJsonWriter() { + var obj = JsonObject.create().add("greet", "hi"); + + JsonStream otherJsonStream = JsonStream.builder().build(); + + StringWriter stringWriter = new StringWriter(); + try (JsonWriter jsonWriter = otherJsonStream.writer(stringWriter)) { + nodeMapper.toJson(obj, jsonWriter); + } + assertThat(stringWriter.toString()).isEqualTo("{\"greet\":\"hi\"}"); + } + + @Test + void objectMapper() { + NodeMapper objectMapper = mapper.objectMapper(); + + JsonObject jsonObject = objectMapper.fromJson("{\"greet\":\"hi\"}"); + assertThat(jsonObject.toString()).isEqualTo("{greet=hi}"); + } + + @Test + void arrayMapper() { + NodeMapper arrayMapper = mapper.arrayMapper(); + + JsonArray jsonArray = arrayMapper.fromJson("[\"a\",\"b\",\"c\"]"); + assertThat(jsonArray.toString()).isEqualTo("[a, b, c]"); + } + +} diff --git a/json-node/src/test/java/io/avaje/json/node/adapter/JsonNodeAdaptersTest.java b/json-node/src/test/java/io/avaje/json/node/adapter/JsonNodeAdaptersTest.java index 873f6ddf..3f8b097a 100644 --- a/json-node/src/test/java/io/avaje/json/node/adapter/JsonNodeAdaptersTest.java +++ b/json-node/src/test/java/io/avaje/json/node/adapter/JsonNodeAdaptersTest.java @@ -13,84 +13,84 @@ class JsonNodeAdaptersTest { - static final JsonNodeAdapter node = JsonNodeAdapter.builder().build(); + static final JsonNodeMapper mapper = JsonNodeMapper.builder().build(); static final JsonStream stream = JsonStream.builder().build(); - static final JsonAdapter nodeAdapter = node.of(JsonNode.class); + static final JsonAdapter nodeAdapter = mapper.adapter(JsonNode.class); @Test void create_expect_null() { - assertThat(node.create(LocalDate.class)).isNull(); + assertThat(mapper.adapter(LocalDate.class)).isNull(); } @Test void create_JsonNode_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonNode.class); - JsonAdapter adapter = node.of(JsonNode.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonNode.class); + JsonAdapter adapter = mapper.adapter(JsonNode.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonObject_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonObject.class); - JsonAdapter adapter = node.of(JsonObject.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonObject.class); + JsonAdapter adapter = mapper.adapter(JsonObject.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonArray_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonArray.class); - JsonAdapter adapter = node.of(JsonArray.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonArray.class); + JsonAdapter adapter = mapper.adapter(JsonArray.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonInteger_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonInteger.class); - JsonAdapter adapter = node.of(JsonInteger.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonInteger.class); + JsonAdapter adapter = mapper.adapter(JsonInteger.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonLong_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonLong.class); - JsonAdapter adapter = node.of(JsonLong.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonLong.class); + JsonAdapter adapter = mapper.adapter(JsonLong.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonDouble_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonDouble.class); - JsonAdapter adapter = node.of(JsonDouble.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonDouble.class); + JsonAdapter adapter = mapper.adapter(JsonDouble.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonDecimal_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonDecimal.class); - JsonAdapter adapter = node.of(JsonDecimal.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonDecimal.class); + JsonAdapter adapter = mapper.adapter(JsonDecimal.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonNumber_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonNumber.class); - JsonAdapter adapter = node.of(JsonNumber.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonNumber.class); + JsonAdapter adapter = mapper.adapter(JsonNumber.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonBoolean_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonBoolean.class); - JsonAdapter adapter = node.of(JsonBoolean.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonBoolean.class); + JsonAdapter adapter = mapper.adapter(JsonBoolean.class); assertThat(jsonAdapter).isSameAs(adapter); } @Test void create_JsonString_expect_sameInstance() { - JsonAdapter jsonAdapter = node.create(JsonString.class); - JsonAdapter adapter = node.of(JsonString.class); + JsonAdapter jsonAdapter = mapper.adapter(JsonString.class); + JsonAdapter adapter = mapper.adapter(JsonString.class); assertThat(jsonAdapter).isSameAs(adapter); } @@ -101,13 +101,13 @@ void arrayCreateOfMixed_defaultStream() { .add(42) .add("foo"); - var asJson = node.toJson(jsonArray); + var asJson = mapper.toJson(jsonArray); assertThat(asJson).isEqualTo("[42,\"foo\"]"); - JsonArray arrayFromJson = node.fromJson(JsonArray.class, asJson); + JsonArray arrayFromJson = mapper.fromJsonArray(asJson); assertThat(arrayFromJson.elements()).hasSize(2); - JsonNode jsonNodeFromJson = node.fromJson(asJson); + JsonNode jsonNodeFromJson = mapper.fromJson(asJson); assertThat(jsonNodeFromJson).isInstanceOf(JsonArray.class); } @@ -139,10 +139,10 @@ void object() { assertThat(obj.containsKey("name")).isTrue(); assertThat(obj.containsKey("DoesNotExist")).isFalse(); - String asJson0 = node.toJson(obj); + String asJson0 = mapper.toJson(obj); assertThat(asJson0).isEqualTo("{\"name\":\"foo\",\"other\":42}"); - JsonObject jsonObjectFromJson = node.fromJson(JsonObject.class, asJson0); + JsonObject jsonObjectFromJson = mapper.fromJson(JsonObject.class, asJson0); assertThat(jsonObjectFromJson.elements()).containsKeys("name", "other"); var writer = stream.bufferedWriter();