diff --git a/media-json-api/pom.xml b/media-json-api/pom.xml index a886295..2a99ade 100644 --- a/media-json-api/pom.xml +++ b/media-json-api/pom.xml @@ -21,6 +21,11 @@ ${project.version} + + com.github.spotbugs + spotbugs-annotations + + org.junit.jupiter junit-jupiter-api @@ -37,6 +42,13 @@ test + + ${project.groupId} + media-core + ${project.version} + test + + org.eclipse.parsson parsson diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/JsonObjectPrintable.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/JsonObjectPrintable.java new file mode 100644 index 0000000..e03f4c7 --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/JsonObjectPrintable.java @@ -0,0 +1,30 @@ +package io.github.sebastiantoepfer.ddd.media.json; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.common.Printable; +import io.github.sebastiantoepfer.ddd.media.json.printable.JsonMappedPrintables; +import jakarta.json.JsonObject; +import java.util.List; +import java.util.Objects; + +public class JsonObjectPrintable implements Printable { + + private final JsonObject json; + + public JsonObjectPrintable(final JsonObject json) { + this.json = Objects.requireNonNull(json); + } + + @Override + public > T printOn(final T media) { + T result = media; + for (Printable printable : createPrintables()) { + result = printable.printOn(result); + } + return result; + } + + private List createPrintables() { + return json.entrySet().stream().map(JsonMappedPrintables::new).map(JsonMappedPrintables::toPrintable).toList(); + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/ArrayJsonMappedValue.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/ArrayJsonMappedValue.java new file mode 100644 index 0000000..d2bff1a --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/ArrayJsonMappedValue.java @@ -0,0 +1,35 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.common.Printable; +import jakarta.json.JsonArray; +import java.util.List; + +class ArrayJsonMappedValue implements JsonMappedValue { + + private final JsonArray array; + + public ArrayJsonMappedValue(final JsonArray array) { + this.array = array; + } + + @Override + public List toValue() { + return array + .stream() + .map(JsonMappedValues::new) + .map(JsonMappedValues::toMappedValue) + .map(JsonMappedValue::toValue) + .toList(); + } + + @Override + public Printable toPrintable(final String name) { + return new Printable() { + @Override + public > T printOn(final T media) { + return media.withValue(name, toValue()); + } + }; + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/BooleanJsonMappedValue.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/BooleanJsonMappedValue.java new file mode 100644 index 0000000..04354e8 --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/BooleanJsonMappedValue.java @@ -0,0 +1,29 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.common.Printable; +import jakarta.json.JsonValue; + +class BooleanJsonMappedValue implements JsonMappedValue { + + private final JsonValue.ValueType value; + + public BooleanJsonMappedValue(final JsonValue.ValueType value) { + this.value = value; + } + + @Override + public Boolean toValue() { + return value == JsonValue.ValueType.TRUE; + } + + @Override + public Printable toPrintable(final String name) { + return new Printable() { + @Override + public > T printOn(final T media) { + return media.withValue(name, toValue()); + } + }; + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/DecimalNumberJsonMappedValue.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/DecimalNumberJsonMappedValue.java new file mode 100644 index 0000000..0af6573 --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/DecimalNumberJsonMappedValue.java @@ -0,0 +1,29 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.common.Printable; +import jakarta.json.JsonNumber; + +class DecimalNumberJsonMappedValue implements JsonMappedValue { + + private final JsonNumber value; + + public DecimalNumberJsonMappedValue(final JsonNumber value) { + this.value = value; + } + + @Override + public Printable toPrintable(final String name) { + return new Printable() { + @Override + public > T printOn(final T media) { + return media.withValue(name, toValue()); + } + }; + } + + @Override + public Double toValue() { + return value.doubleValue(); + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/IntegerNumberJsonMappedValue.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/IntegerNumberJsonMappedValue.java new file mode 100644 index 0000000..b4df69e --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/IntegerNumberJsonMappedValue.java @@ -0,0 +1,29 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.common.Printable; +import jakarta.json.JsonNumber; + +class IntegerNumberJsonMappedValue implements JsonMappedValue { + + private final JsonNumber value; + + public IntegerNumberJsonMappedValue(final JsonNumber value) { + this.value = value; + } + + @Override + public Printable toPrintable(final String name) { + return new Printable() { + @Override + public > T printOn(final T media) { + return media.withValue(name, toValue()); + } + }; + } + + @Override + public Long toValue() { + return value.longValueExact(); + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedPrintables.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedPrintables.java new file mode 100644 index 0000000..5960355 --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedPrintables.java @@ -0,0 +1,20 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.github.sebastiantoepfer.ddd.common.Printable; +import jakarta.json.JsonValue; +import java.util.Map; + +public class JsonMappedPrintables { + + private final Map.Entry entry; + + @SuppressFBWarnings("EI_EXPOSE_REP2") + public JsonMappedPrintables(final Map.Entry entry) { + this.entry = entry; + } + + public Printable toPrintable() { + return new JsonMappedValues(entry.getValue()).toMappedValue().toPrintable(entry.getKey()); + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedValue.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedValue.java new file mode 100644 index 0000000..b4d8fca --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedValue.java @@ -0,0 +1,9 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import io.github.sebastiantoepfer.ddd.common.Printable; + +interface JsonMappedValue { + Object toValue(); + + Printable toPrintable(String name); +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedValues.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedValues.java new file mode 100644 index 0000000..058350a --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/JsonMappedValues.java @@ -0,0 +1,38 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import jakarta.json.JsonArray; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; + +class JsonMappedValues { + + private final JsonValue value; + + public JsonMappedValues(final JsonValue value) { + this.value = value; + } + + public JsonMappedValue toMappedValue() { + final JsonMappedValue result; + if (value instanceof JsonString str) { + result = new StringJsonMappedValue(str); + } else if (value instanceof JsonNumber number) { + if (number.isIntegral()) { + result = new IntegerNumberJsonMappedValue(number); + } else { + result = new DecimalNumberJsonMappedValue(number); + } + } else if (value instanceof JsonArray array) { + result = new ArrayJsonMappedValue(array); + } else if (value instanceof JsonObject obj) { + result = new ObjectJsonMappedValue(obj); + } else if (value.getValueType() == JsonValue.ValueType.NULL) { + result = new NullJsonMappedValue(); + } else { + result = new BooleanJsonMappedValue(value.getValueType()); + } + return result; + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/NullJsonMappedValue.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/NullJsonMappedValue.java new file mode 100644 index 0000000..b5e43fb --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/NullJsonMappedValue.java @@ -0,0 +1,22 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.common.Printable; + +class NullJsonMappedValue implements JsonMappedValue { + + @Override + public Void toValue() { + return null; + } + + @Override + public Printable toPrintable(final String name) { + return new Printable() { + @Override + public > T printOn(final T media) { + return media; + } + }; + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/ObjectJsonMappedValue.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/ObjectJsonMappedValue.java new file mode 100644 index 0000000..99bd379 --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/ObjectJsonMappedValue.java @@ -0,0 +1,30 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.common.Printable; +import io.github.sebastiantoepfer.ddd.media.json.JsonObjectPrintable; +import jakarta.json.JsonObject; + +class ObjectJsonMappedValue implements JsonMappedValue { + + private final JsonObject json; + + public ObjectJsonMappedValue(final JsonObject json) { + this.json = json; + } + + @Override + public Printable toPrintable(final String name) { + return new Printable() { + @Override + public > T printOn(final T media) { + return media.withValue(name, toValue()); + } + }; + } + + @Override + public Printable toValue() { + return new JsonObjectPrintable(json); + } +} diff --git a/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/StringJsonMappedValue.java b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/StringJsonMappedValue.java new file mode 100644 index 0000000..d3b66a8 --- /dev/null +++ b/media-json-api/src/main/java/io/github/sebastiantoepfer/ddd/media/json/printable/StringJsonMappedValue.java @@ -0,0 +1,29 @@ +package io.github.sebastiantoepfer.ddd.media.json.printable; + +import io.github.sebastiantoepfer.ddd.common.Media; +import io.github.sebastiantoepfer.ddd.common.Printable; +import jakarta.json.JsonString; + +class StringJsonMappedValue implements JsonMappedValue { + + private final JsonString value; + + public StringJsonMappedValue(final JsonString value) { + this.value = value; + } + + @Override + public Printable toPrintable(final String name) { + return new Printable() { + @Override + public > T printOn(final T media) { + return media.withValue(name, toValue()); + } + }; + } + + @Override + public String toValue() { + return value.getString(); + } +} diff --git a/media-json-api/src/test/java/io/github/sebastiantoepfer/ddd/media/json/JsonObjectPrintableTest.java b/media-json-api/src/test/java/io/github/sebastiantoepfer/ddd/media/json/JsonObjectPrintableTest.java new file mode 100644 index 0000000..834d7a9 --- /dev/null +++ b/media-json-api/src/test/java/io/github/sebastiantoepfer/ddd/media/json/JsonObjectPrintableTest.java @@ -0,0 +1,86 @@ +package io.github.sebastiantoepfer.ddd.media.json; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.is; + +import io.github.sebastiantoepfer.ddd.media.core.HashMapMedia; +import jakarta.json.Json; +import java.math.BigDecimal; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.Test; + +class JsonObjectPrintableTest { + + @Test + void should_print_string_property() { + assertThat( + new JsonObjectPrintable(Json.createObjectBuilder().add("name", "Jane").build()).printOn(new HashMapMedia()), + hasEntry("name", "Jane") + ); + } + + @Test + void should_print_number_property() { + assertThat( + new JsonObjectPrintable(Json.createObjectBuilder().add("name", 234).build()).printOn(new HashMapMedia()), + hasEntry("name", 234L) + ); + } + + @Test + void should_print_decimalnumber_property() { + assertThat( + new JsonObjectPrintable(Json.createObjectBuilder().add("name", 234.27261).build()).printOn(new HashMapMedia()), + hasEntry("name", 234.27261) + ); + } + + @Test + void should_print_array_property() { + assertThat( + new JsonObjectPrintable(Json.createObjectBuilder().add("name", Json.createArrayBuilder().add("Test")).build()) + .printOn(new HashMapMedia()), + (Matcher) hasEntry(is("name"), contains("Test")) + ); + } + + @Test + void should_print_true_boolean_property() { + assertThat( + new JsonObjectPrintable(Json.createObjectBuilder().add("name", true).build()).printOn(new HashMapMedia()), + (Matcher) hasEntry(is("name"), is(true)) + ); + } + + @Test + void should_print_false_boolean_property() { + assertThat( + new JsonObjectPrintable(Json.createObjectBuilder().add("name", false).build()).printOn(new HashMapMedia()), + (Matcher) hasEntry(is("name"), is(false)) + ); + } + + @Test + void should_print_object_property() { + assertThat( + new JsonObjectPrintable( + Json.createObjectBuilder().add("name", Json.createObjectBuilder().add("test", BigDecimal.ONE)).build() + ) + .printOn(new HashMapMedia()), + (Matcher) hasEntry(is("name"), hasEntry("test", 1L)) + ); + } + + @Test + void should_not_print_null_property() { + assertThat( + new JsonObjectPrintable(Json.createObjectBuilder().addNull("test").build()) + .printOn(new HashMapMedia()) + .entrySet(), + is(empty()) + ); + } +}