This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch spring6
in repository https://gitbox.apache.org/repos/asf/causeway.git


The following commit(s) were added to refs/heads/spring6 by this push:
     new a79274e017 CAUSEWAY-3684: [Commons] Json/YamlUtils support for Can<T>
a79274e017 is described below

commit a79274e01719582dd44e661a259a1ff3e76cc98f
Author: andi-huber <[email protected]>
AuthorDate: Sun Jan 28 15:42:40 2024 +0100

    CAUSEWAY-3684: [Commons] Json/YamlUtils support for Can<T>
---
 .../org/apache/causeway/commons/io/JsonUtils.java  | 67 +++++++++++++++++++++-
 .../org/apache/causeway/commons/io/YamlUtils.java  |  2 +
 .../apache/causeway/commons/io/JsonUtilsTest.java  |  9 ++-
 ...lsTest.toStringUtf8_indentedOutput.approved.txt |  7 +++
 .../apache/causeway/commons/io/YamlUtilsTest.java  |  5 ++
 .../io/YamlUtilsTest.toStringUtf8.approved.txt     |  5 ++
 .../apache/causeway/commons/io/_TestDomain.java    |  4 ++
 7 files changed, 96 insertions(+), 3 deletions(-)

diff --git 
a/commons/src/main/java/org/apache/causeway/commons/io/JsonUtils.java 
b/commons/src/main/java/org/apache/causeway/commons/io/JsonUtils.java
index b01e14223d..dd07eb9ec2 100644
--- a/commons/src/main/java/org/apache/causeway/commons/io/JsonUtils.java
+++ b/commons/src/main/java/org/apache/causeway/commons/io/JsonUtils.java
@@ -18,21 +18,34 @@
  */
 package org.apache.causeway.commons.io;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
 import java.util.Optional;
 import java.util.function.UnaryOperator;
 
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import 
com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationModule;
 
 import org.springframework.lang.Nullable;
 
+import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.functional.Try;
+import org.apache.causeway.commons.internal.base._Casts;
 import org.apache.causeway.commons.internal.context._Context;
 
 import lombok.NonNull;
@@ -104,8 +117,8 @@ public class JsonUtils {
         return source.tryReadAll((final InputStream is)->{
             return Try.call(()->{
                 val mapper = createJacksonReader(customizers);
-                val listFactory = 
mapper.getTypeFactory().constructCollectionType(List.class, elementType);
-                return mapper.readValue(is, listFactory);
+                val collectionType = 
mapper.getTypeFactory().constructCollectionType(List.class, elementType);
+                return mapper.readValue(is, collectionType);
             });
         });
     }
@@ -169,12 +182,61 @@ public class JsonUtils {
         return mapper;
     }
 
+    // -- CAN SUPPORT
+
+    static class CanDeserializer extends JsonDeserializer<Can<?>> implements 
ContextualDeserializer {
+        private Class<?> elementType;
+        public CanDeserializer(final @NonNull Class<?> elementType) {
+            this.elementType = elementType;
+        }
+        @Override
+        public JsonDeserializer<?> createContextual(final 
DeserializationContext ctxt, final BeanProperty beanProperty) throws 
JsonMappingException {
+            var type = ctxt.getContextualType() != null
+                ? ctxt.getContextualType()
+                : beanProperty!=null
+                    ? beanProperty.getMember().getType()
+                    : null;
+            var elementType = type!=null && type.containedTypeCount()==1
+                    ? type.containedType(0).getRawClass()
+                    : Object.class;
+            return new CanDeserializer(elementType);
+        }
+        @Override
+        public Can<?> deserialize(
+                final JsonParser p, final DeserializationContext ctxt) throws 
IOException {
+            val listType = 
ctxt.getTypeFactory().constructCollectionType(List.class, elementType);
+            var list = ctxt.readValue(p, listType);
+            return Can.ofCollection(_Casts.uncheckedCast(list));
+        }
+    }
+    /** add support for reading Can<T> */
+    public ObjectMapper readingCanSupport(final ObjectMapper mapper) {
+        mapper.registerModule(new SimpleModule().addDeserializer(Can.class, 
new CanDeserializer(Object.class)));
+        return mapper;
+    }
+
+    static class CanSerializer extends StdSerializer<Can<?>> {
+        private static final long serialVersionUID = 1L;
+        protected CanSerializer() { super(Can.class, false); }
+        @Override
+        public void serialize(final Can<?> value, final JsonGenerator gen,
+                final SerializerProvider provider) throws IOException {
+            gen.writeObject(value.toList());
+        }
+    }
+    /** add support for writing Can<T> */
+    public ObjectMapper writingCanSupport(final ObjectMapper mapper) {
+        mapper.registerModule(new SimpleModule().addSerializer(new 
CanSerializer()));
+        return mapper;
+    }
+
     // -- MAPPER FACTORY
 
     private ObjectMapper createJacksonReader(
             final JsonUtils.JacksonCustomizer ... customizers) {
         var mapper = new ObjectMapper();
         mapper = readingJavaTimeSupport(mapper);
+        mapper = readingCanSupport(mapper);
         for(JsonUtils.JacksonCustomizer customizer : customizers) {
             mapper = Optional.ofNullable(customizer.apply(mapper))
                     .orElse(mapper);
@@ -186,6 +248,7 @@ public class JsonUtils {
             final JsonUtils.JacksonCustomizer ... customizers) {
         var mapper = new ObjectMapper();
         mapper = writingJavaTimeSupport(mapper);
+        mapper = writingCanSupport(mapper);
         for(JsonUtils.JacksonCustomizer customizer : customizers) {
             mapper = Optional.ofNullable(customizer.apply(mapper))
                     .orElse(mapper);
diff --git 
a/commons/src/main/java/org/apache/causeway/commons/io/YamlUtils.java 
b/commons/src/main/java/org/apache/causeway/commons/io/YamlUtils.java
index 4599b19ddd..a3c4a09c92 100644
--- a/commons/src/main/java/org/apache/causeway/commons/io/YamlUtils.java
+++ b/commons/src/main/java/org/apache/causeway/commons/io/YamlUtils.java
@@ -146,6 +146,7 @@ public class YamlUtils {
             final JsonUtils.JacksonCustomizer ... customizers) {
         var mapper = new ObjectMapper(new YAMLFactory());
         mapper = JsonUtils.readingJavaTimeSupport(mapper);
+        mapper = JsonUtils.readingCanSupport(mapper);
         for(JsonUtils.JacksonCustomizer customizer : customizers) {
             mapper = Optional.ofNullable(customizer.apply(mapper))
                     .orElse(mapper);
@@ -161,6 +162,7 @@ public class YamlUtils {
         var mapper = new ObjectMapper(new YAMLFactory()
                 .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER));
         mapper = JsonUtils.writingJavaTimeSupport(mapper);
+        mapper = JsonUtils.writingCanSupport(mapper);
         for(JsonUtils.JacksonCustomizer customizer : customizers) {
             mapper = Optional.ofNullable(customizer.apply(mapper))
                     .orElse(mapper);
diff --git 
a/commons/src/test/java/org/apache/causeway/commons/io/JsonUtilsTest.java 
b/commons/src/test/java/org/apache/causeway/commons/io/JsonUtilsTest.java
index 66c45e9784..28049048d6 100644
--- a/commons/src/test/java/org/apache/causeway/commons/io/JsonUtilsTest.java
+++ b/commons/src/test/java/org/apache/causeway/commons/io/JsonUtilsTest.java
@@ -60,7 +60,14 @@ class JsonUtilsTest {
                     "address": {
                         "zip":1234,
                         "street":"backerstreet"
-                    }
+                    },
+                    "additionalAddresses" : [ {
+                        "zip" : 23,
+                        "street" : "brownstreet"
+                    }, {
+                        "zip" : 34,
+                        "street" : "bluestreet"
+                    } ]
                 }
                 """;
 
diff --git 
a/commons/src/test/java/org/apache/causeway/commons/io/JsonUtilsTest.toStringUtf8_indentedOutput.approved.txt
 
b/commons/src/test/java/org/apache/causeway/commons/io/JsonUtilsTest.toStringUtf8_indentedOutput.approved.txt
index f572fe9b5e..4514ff5d4a 100644
--- 
a/commons/src/test/java/org/apache/causeway/commons/io/JsonUtilsTest.toStringUtf8_indentedOutput.approved.txt
+++ 
b/commons/src/test/java/org/apache/causeway/commons/io/JsonUtilsTest.toStringUtf8_indentedOutput.approved.txt
@@ -4,6 +4,13 @@
     "zip" : 1234,
     "street" : "backerstreet"
   },
+  "additionalAddresses" : [ {
+    "zip" : 23,
+    "street" : "brownstreet"
+  }, {
+    "zip" : 34,
+    "street" : "bluestreet"
+  } ],
   "java8Time" : {
     "localTime" : "17:33:45",
     "localDate" : "2007-11-21",
diff --git 
a/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.java 
b/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.java
index 6e609d299b..66966a580e 100644
--- a/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.java
+++ b/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.java
@@ -48,6 +48,11 @@ class YamlUtilsTest {
         var yamlTemplate = """
                 name: sven
                 address: {street: backerstreet, zip: 1234}
+                additionalAddresses:
+                - zip: 23
+                  street: "brownstreet"
+                - zip: 34
+                  street: "bluestreet"
                 java8Time:
                   localTime: ${localTime}
                   localDate: ${localDate}
diff --git 
a/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8.approved.txt
 
b/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8.approved.txt
index db3bcc524a..db6037f6be 100644
--- 
a/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8.approved.txt
+++ 
b/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8.approved.txt
@@ -2,6 +2,11 @@ name: "sven"
 address:
   zip: 1234
   street: "backerstreet"
+additionalAddresses:
+- zip: 23
+  street: "brownstreet"
+- zip: 34
+  street: "bluestreet"
 java8Time:
   localTime: "17:33:45"
   localDate: "2007-11-21"
diff --git 
a/commons/src/test/java/org/apache/causeway/commons/io/_TestDomain.java 
b/commons/src/test/java/org/apache/causeway/commons/io/_TestDomain.java
index bf3fe7039a..43f2540354 100644
--- a/commons/src/test/java/org/apache/causeway/commons/io/_TestDomain.java
+++ b/commons/src/test/java/org/apache/causeway/commons/io/_TestDomain.java
@@ -30,6 +30,7 @@ import java.time.format.DateTimeFormatter;
 import java.util.Map;
 import java.util.Objects;
 
+import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.internal.base._StringInterpolation;
 
 import lombok.experimental.UtilityClass;
@@ -40,6 +41,7 @@ class _TestDomain {
     public static record Person(
             String name,
             Address address,
+            Can<Address> additionalAddresses,
             Java8Time java8Time) {
     }
 
@@ -88,6 +90,8 @@ class _TestDomain {
 
     Person samplePerson() {
         return new Person("sven", new Address(1234, "backerstreet"),
+                Can.of(new Address(23, "brownstreet"),
+                        new Address(34, "bluestreet")),
                 new Java8Time(
                         LocalTime.of(17, 33, 45),
                         LocalDate.of(2007, 11, 21),

Reply via email to