From 32e5b07d691360bcd8970bfbe44da8b812c106f3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 18 Dec 2024 11:35:56 +1300 Subject: [PATCH] [json-core] Add helper toJson() fromJson() methods that use JsonReader JsonWriter This makes it more trivially obvious when using SimpleMapper or JsonNodeMapper to implement a JsonAdapter [where the API uses JsonReader and JsonWriter] --- .../io/avaje/json/simple/DSimpleMapper.java | 22 ++++++++ .../io/avaje/json/simple/SimpleMapper.java | 27 ++++++++++ .../avaje/json/simple/SimpleMapperTest.java | 53 ++++++++++++++++++- .../io/avaje/json/node/JsonNodeMapper.java | 38 +++++++++++++ .../json/node/adapter/DJsonNodeMapper.java | 21 ++++++++ .../node/adapter/JsonNodeAdaptersTest.java | 31 +++++++++++ 6 files changed, 191 insertions(+), 1 deletion(-) diff --git a/json-core/src/main/java/io/avaje/json/simple/DSimpleMapper.java b/json-core/src/main/java/io/avaje/json/simple/DSimpleMapper.java index efeee792..24f35949 100644 --- a/json-core/src/main/java/io/avaje/json/simple/DSimpleMapper.java +++ b/json-core/src/main/java/io/avaje/json/simple/DSimpleMapper.java @@ -1,6 +1,8 @@ package io.avaje.json.simple; import io.avaje.json.JsonAdapter; +import io.avaje.json.JsonReader; +import io.avaje.json.JsonWriter; import io.avaje.json.PropertyNames; import io.avaje.json.core.CoreTypes; import io.avaje.json.stream.JsonStream; @@ -52,11 +54,26 @@ public String toJson(Object object) { return objectType.toJson(object); } + @Override + public void toJson(Object object, JsonWriter jsonWriter) { + objectType.toJson(object, jsonWriter); + } + @Override public Object fromJson(String json) { return objectType.fromJson(json); } + @Override + public Object fromJson(JsonReader jsonReader) { + return objectType.fromJson(jsonReader); + } + + @Override + public Map fromJsonObject(JsonReader jsonReader) { + return mapType.fromJson(jsonReader); + } + @Override public Map fromJsonObject(String json) { return mapType.fromJson(json); @@ -66,4 +83,9 @@ public Map fromJsonObject(String json) { public List fromJsonArray(String json) { return listType.fromJson(json); } + + @Override + public List fromJsonArray(JsonReader jsonReader) { + return listType.fromJson(jsonReader); + } } diff --git a/json-core/src/main/java/io/avaje/json/simple/SimpleMapper.java b/json-core/src/main/java/io/avaje/json/simple/SimpleMapper.java index 96681e9c..ed0246cb 100644 --- a/json-core/src/main/java/io/avaje/json/simple/SimpleMapper.java +++ b/json-core/src/main/java/io/avaje/json/simple/SimpleMapper.java @@ -73,11 +73,24 @@ static Builder builder() { */ String toJson(Object object); + /** + * Write the object to JsonWriter. + *

+ * For options to write json content to OutputStream, Writer etc + * use {@link Type}. + */ + void toJson(Object object, JsonWriter jsonWriter); + /** * Read the object from JSON string. */ Object fromJson(String json); + /** + * Read the object from JSON. + */ + Object fromJson(JsonReader jsonReader); + /** * Read a Map from JSON OBJECT string. *

@@ -85,6 +98,13 @@ static Builder builder() { */ Map fromJsonObject(String json); + /** + * Read a Map from JSON OBJECT. + *

+ * Use {@link #map()} for more reading options. + */ + Map fromJsonObject(JsonReader jsonReader); + /** * Read a List from JSON ARRAY string. *

@@ -92,6 +112,13 @@ static Builder builder() { */ List fromJsonArray(String json); + /** + * Read a List from JSON ARRAY. + *

+ * Use {@link #list()} for more reading options. + */ + List fromJsonArray(JsonReader jsonReader); + /** * Return the property names as PropertyNames. *

diff --git a/json-core/src/test/java/io/avaje/json/simple/SimpleMapperTest.java b/json-core/src/test/java/io/avaje/json/simple/SimpleMapperTest.java index 48c262d1..cb2ba8eb 100644 --- a/json-core/src/test/java/io/avaje/json/simple/SimpleMapperTest.java +++ b/json-core/src/test/java/io/avaje/json/simple/SimpleMapperTest.java @@ -1,6 +1,9 @@ package io.avaje.json.simple; +import io.avaje.json.JsonReader; +import io.avaje.json.stream.BufferedJsonWriter; +import io.avaje.json.stream.JsonStream; import org.junit.jupiter.api.Test; import java.util.LinkedHashMap; @@ -30,14 +33,52 @@ void mapToJsonFromJson() { Map mapFromJson2 = simpleMapper.map().fromJson(asJson); assertThat(mapFromJson2).isEqualTo(mapFromJson); + + JsonStream jsonStream = JsonStream.builder().build(); + try (JsonReader reader = jsonStream.reader(asJson)) { + Map mapFromJson3 = simpleMapper.fromJsonObject(reader); + assertThat(mapFromJson3).isEqualTo(mapFromJson); + } + } + + @Test + void toJsonWriter_scalar() { + JsonStream jsonStream = JsonStream.builder().build(); + BufferedJsonWriter writer0 = jsonStream.bufferedWriter(); + simpleMapper.toJson("hi", writer0); + assertThat(writer0.result()).isEqualTo("\"hi\""); + } + + @Test + void toJsonWriter_map() { + JsonStream jsonStream = JsonStream.builder().build(); + BufferedJsonWriter writer0 = jsonStream.bufferedWriter(); + simpleMapper.toJson(Map.of("key", 0), writer0); + assertThat(writer0.result()).isEqualTo("{\"key\":0}"); + } + + @Test + void toJsonWriter_list() { + JsonStream jsonStream = JsonStream.builder().build(); + BufferedJsonWriter writer0 = jsonStream.bufferedWriter(); + simpleMapper.toJson(List.of("a", 0), writer0); + assertThat(writer0.result()).isEqualTo("[\"a\",0]"); } @Test void nullDirectly() { - var mapFromJson = simpleMapper.fromJson("null"); + var mapFromJson = simpleMapper.fromJson("null"); assertThat(mapFromJson).isNull(); } + @Test + void objectJsonReader() { + try (var reader = JsonStream.builder().build().reader("\"hi\"")) { + var fromJson = simpleMapper.fromJson(reader); + assertThat(fromJson).isEqualTo("hi"); + } + } + @Test void mapWithNull() { Map mapFromJson = simpleMapper.fromJsonObject("{\"one\":1,\"two\":null,\"three\":3}"); @@ -58,6 +99,16 @@ void listWithNull() { assertThat(simpleMapper.toJson(listFromJson)).isEqualTo("[1,3]"); } + @Test + void listWithReader() { + try (JsonReader reader = JsonStream.builder().build().reader("[1,2]")) { + List listFromJson = simpleMapper.fromJsonArray(reader); + + assertThat(listFromJson).hasSize(2); + assertThat(simpleMapper.toJson(listFromJson)).isEqualTo("[1,2]"); + } + } + @Test void arrayToJsonFromJson() { 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 index 2a9d1033..508b55e8 100644 --- a/json-node/src/main/java/io/avaje/json/node/JsonNodeMapper.java +++ b/json-node/src/main/java/io/avaje/json/node/JsonNodeMapper.java @@ -1,6 +1,8 @@ package io.avaje.json.node; import io.avaje.json.JsonAdapter; +import io.avaje.json.JsonReader; +import io.avaje.json.JsonWriter; import io.avaje.json.PropertyNames; import io.avaje.json.node.adapter.NodeAdapterBuilder; import io.avaje.json.simple.SimpleMapper; @@ -87,6 +89,17 @@ static Builder builder() { */ String toJson(JsonNode node); + /** + * Write the node to JSON. + *

+ * For options to write json content to OutputStream, Writer etc + * use {@link #nodeMapper()}. + * + * @see SimpleMapper.Type#toJson(Object, OutputStream) + * @see SimpleMapper.Type#toJson(Object, Writer) + */ + void toJson(JsonNode node, JsonWriter jsonWriter); + /** * Read any json content returning a JsonNode. *

@@ -104,6 +117,17 @@ static Builder builder() { */ JsonNode fromJson(String json); + /** + * Read any json content returning a JsonNode. + *

+ * For options to read json content from InputStream, Reader etc + * use the fromJson methods on {@link SimpleMapper.Type}. + * + * @see SimpleMapper.Type#fromJson(Reader) + * @see SimpleMapper.Type#fromJson(InputStream) + */ + JsonNode fromJson(JsonReader jsonReader); + /** * Read a JsonObject from json string content. *

@@ -114,6 +138,13 @@ static Builder builder() { */ JsonObject fromJsonObject(String json); + /** + * Read a JsonObject from json string content. + *

+ * Use this when we know that the json content is a JsonObject. + */ + JsonObject fromJsonObject(JsonReader jsonReader); + /** * Read a JsonArray from json string content. *

@@ -124,6 +155,13 @@ static Builder builder() { */ JsonArray fromJsonArray(String json); + /** + * Read a JsonArray from json string content. + *

+ * Use this when we know that the json content is a JsonArray. + */ + JsonArray fromJsonArray(JsonReader jsonReader); + /** * Helper method to read JSON with an expected JsonNode type. * diff --git a/json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeMapper.java b/json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeMapper.java index 6152f80c..9a2281a1 100644 --- a/json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeMapper.java +++ b/json-node/src/main/java/io/avaje/json/node/adapter/DJsonNodeMapper.java @@ -2,6 +2,7 @@ import io.avaje.json.JsonAdapter; import io.avaje.json.JsonReader; +import io.avaje.json.JsonWriter; import io.avaje.json.PropertyNames; import io.avaje.json.node.*; import io.avaje.json.simple.SimpleMapper; @@ -63,6 +64,11 @@ public String toJson(JsonNode node) { return writer.result(); } + @Override + public void toJson(JsonNode node, JsonWriter jsonWriter) { + nodeAdapter.toJson(jsonWriter, node); + } + @Override public JsonNode fromJson(String json) { try (JsonReader reader = jsonStream.reader(json)) { @@ -84,6 +90,21 @@ public JsonArray fromJsonArray(String json) { } } + @Override + public JsonNode fromJson(JsonReader jsonReader) { + return nodeAdapter.fromJson(jsonReader); + } + + @Override + public JsonObject fromJsonObject(JsonReader jsonReader) { + return objectAdapter.fromJson(jsonReader); + } + + @Override + public JsonArray fromJsonArray(JsonReader jsonReader) { + return arrayAdapter.fromJson(jsonReader); + } + @Override public T fromJson(Class type, String json) { JsonAdapter adapter = adapter(type); 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 84538306..e440f906 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 @@ -4,6 +4,7 @@ import io.avaje.json.JsonReader; import io.avaje.json.node.*; import io.avaje.json.simple.SimpleMapper; +import io.avaje.json.stream.BufferedJsonWriter; import io.avaje.json.stream.JsonStream; import org.junit.jupiter.api.Test; @@ -102,6 +103,36 @@ void create_JsonString_expect_sameInstance() { assertThat(jsonAdapter).isSameAs(adapter); } + @Test + void toJsonWriter() { + BufferedJsonWriter writer = stream.bufferedWriter(); + mapper.toJson(JsonArray.create().add(1).add(2), writer); + assertThat(writer.result()).isEqualTo("[1,2]"); + } + + @Test + void fromJson_usingReader() { + try (var reader = stream.reader("[42, \"foo\"]")) { + JsonNode node = mapper.fromJson(reader); + assertThat(node).isEqualTo(JsonArray.create().add(42L).add("foo")); + } + } + + @Test + void fromJsonArray_usingReader() { + try (var reader = stream.reader("[42, \"foo\"]")) { + JsonArray node = mapper.fromJsonArray(reader); + assertThat(node).isEqualTo(JsonArray.create().add(42L).add("foo")); + } + } + + @Test + void fromJsonObject_usingReader() { + try (var reader = stream.reader("{\"a\":1,\"b\":2}")) { + JsonObject node = mapper.fromJsonObject(reader); + assertThat(node).isEqualTo(JsonObject.create().add("a", 1L).add("b", 2L)); + } + } @Test void arrayCreateOfMixed_defaultStream() {