You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2026/04/24 10:56:15 UTC

(causeway) branch CAUSEWAY-3989 updated (187f9ca14e6 -> b28d78d1b48)

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

danhaywood pushed a change to branch CAUSEWAY-3989
in repository https://gitbox.apache.org/repos/asf/causeway.git


    from 187f9ca14e6 CAUSEWAY-3989: [v2] adds test to demo bug
     add 1f4cd23be37 Merge pull request #3517 from apache/CAUSEWAY-3989
     new b29b16aea96 CAUSEWAY-3989: enhances YAML command DTO processing with multi-document support and adds corresponding tests
     new 5f2e6f44bd6 CAUSEWAY-3989: adds test case for handling trailing empty documents in YAML command DTO
     new 7f3ba4ec54a CAUSEWAY-3989: adds support for converting lists to UTF8 encoded YAML with specified marshalling modes
     new 9ec212d71fd CAUSEWAY-3989: refactors YAML tests to use Approvals for verification and adds approved YAML outputs
     new b28d78d1b48 CAUSEWAY-3989: refactors YAML processing in CommandDtoUtils to use multidoc format.

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 api/applib/src/main/java/module-info.java          |  4 +-
 .../applib/util/schema/CommandDtoUtils.java        | 83 +++++++++++++++++-----
 ...calar-params-multi-document-trailing-empty.yaml | 35 +++++++++
 ...commands-with-scalar-params-multi-document.yaml | 34 +++++++++
 .../util/schema/CommandDtoUtils_fromYaml_Test.java | 19 +++++
 .../org/apache/causeway/commons/io/YamlUtils.java  | 40 +++++++++++
 .../apache/causeway/commons/io/YamlUtilsTest.java  | 24 +++++++
 ...sTest.toStringUtf8ForList_multiDoc.approved.txt | 39 ++++++++++
 ...sTest.toStringUtf8ForList_yamlList.approved.txt | 38 ++++++++++
 .../applib/dom/replay/CommandReplayManager.java    |  8 +--
 10 files changed, 299 insertions(+), 25 deletions(-)
 create mode 100644 api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.commands-with-scalar-params-multi-document-trailing-empty.yaml
 create mode 100644 api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.commands-with-scalar-params-multi-document.yaml
 create mode 100644 commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8ForList_multiDoc.approved.txt
 create mode 100644 commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8ForList_yamlList.approved.txt


(causeway) 04/05: CAUSEWAY-3989: refactors YAML tests to use Approvals for verification and adds approved YAML outputs

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-3989
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit 9ec212d71fd5e10d7e7f809dd187eada4efa6305
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 24 11:49:19 2026 +0100

    CAUSEWAY-3989: refactors YAML tests to use Approvals for verification and adds approved YAML outputs
---
 .../apache/causeway/commons/io/YamlUtilsTest.java  | 22 ++----------
 ...sTest.toStringUtf8ForList_multiDoc.approved.txt | 39 ++++++++++++++++++++++
 ...sTest.toStringUtf8ForList_yamlList.approved.txt | 38 +++++++++++++++++++++
 3 files changed, 79 insertions(+), 20 deletions(-)

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 9abd229a8e2..ac215027090 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
@@ -19,14 +19,12 @@
 package org.apache.causeway.commons.io;
 
 import java.util.List;
-import java.util.stream.Collectors;
 
 import org.approvaltests.Approvals;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import org.apache.causeway.commons.io._TestDomain.Person;
 
@@ -55,13 +53,7 @@ void toStringUtf8ForList_yamlList() {
         val yaml = YamlUtils.toStringUtf8ForList(
                 List.of(person, person2),
                 YamlUtils.Marshalling.YAML_LIST);
-        assertNotNull(yaml);
-
-        val roundTrip = YamlUtils.tryReadAsList(Person.class, DataSource.ofStringUtf8(yaml))
-                .valueAsNonNullElseFail();
-
-        assertEquals(List.of("sven", "fred"),
-                roundTrip.stream().map(Person::getName).collect(Collectors.toList()));
+        Approvals.verify(yaml);
     }
 
     @Test
@@ -72,17 +64,7 @@ void toStringUtf8ForList_multiDoc() {
         val yaml = YamlUtils.toStringUtf8ForList(
                 List.of(person, person2),
                 YamlUtils.Marshalling.MULTI_DOC);
-        assertNotNull(yaml);
-
-        val docs = yaml.split("(?m)^---\\s*$");
-
-        val first = YamlUtils.tryRead(Person.class, docs[0])
-                .valueAsNonNullElseFail();
-        val second = YamlUtils.tryRead(Person.class, docs[1])
-                .valueAsNonNullElseFail();
-
-        assertEquals("sven", first.getName());
-        assertEquals("fred", second.getName());
+        Approvals.verify(yaml);
     }
 
     @Test
diff --git a/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8ForList_multiDoc.approved.txt b/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8ForList_multiDoc.approved.txt
new file mode 100644
index 00000000000..3cac21f215c
--- /dev/null
+++ b/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8ForList_multiDoc.approved.txt
@@ -0,0 +1,39 @@
+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"
+  localDateTime: "2007-11-21T17:33:45"
+  offsetTime: "17:33:45-02:00"
+  offsetDateTime: "2007-11-21T17:33:45-02:00"
+  zonedDateTime: "2007-11-21T17:33:45+01:00"
+phone:
+  home: "+99 1234"
+  work: null
+---
+name: "fred"
+address:
+  zip: 1234
+  street: "backerstreet"
+additionalAddresses:
+- zip: 23
+  street: "brownstreet"
+- zip: 34
+  street: "bluestreet"
+java8Time:
+  localTime: "17:33:45"
+  localDate: "2007-11-21"
+  localDateTime: "2007-11-21T17:33:45"
+  offsetTime: "17:33:45-02:00"
+  offsetDateTime: "2007-11-21T17:33:45-02:00"
+  zonedDateTime: "2007-11-21T17:33:45+01:00"
+phone:
+  home: "+99 1234"
+  work: null
diff --git a/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8ForList_yamlList.approved.txt b/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8ForList_yamlList.approved.txt
new file mode 100644
index 00000000000..935533db17e
--- /dev/null
+++ b/commons/src/test/java/org/apache/causeway/commons/io/YamlUtilsTest.toStringUtf8ForList_yamlList.approved.txt
@@ -0,0 +1,38 @@
+- 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"
+    localDateTime: "2007-11-21T17:33:45"
+    offsetTime: "17:33:45-02:00"
+    offsetDateTime: "2007-11-21T17:33:45-02:00"
+    zonedDateTime: "2007-11-21T17:33:45+01:00"
+  phone:
+    home: "+99 1234"
+    work: null
+- name: "fred"
+  address:
+    zip: 1234
+    street: "backerstreet"
+  additionalAddresses:
+  - zip: 23
+    street: "brownstreet"
+  - zip: 34
+    street: "bluestreet"
+  java8Time:
+    localTime: "17:33:45"
+    localDate: "2007-11-21"
+    localDateTime: "2007-11-21T17:33:45"
+    offsetTime: "17:33:45-02:00"
+    offsetDateTime: "2007-11-21T17:33:45-02:00"
+    zonedDateTime: "2007-11-21T17:33:45+01:00"
+  phone:
+    home: "+99 1234"
+    work: null


(causeway) 02/05: CAUSEWAY-3989: adds test case for handling trailing empty documents in YAML command DTO

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-3989
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit 5f2e6f44bd6c636f11df00ceb4211fa641d1841c
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 24 11:30:26 2026 +0100

    CAUSEWAY-3989: adds test case for handling trailing empty documents in YAML command DTO
---
 ...calar-params-multi-document-trailing-empty.yaml | 35 ++++++++++++++++++++++
 .../util/schema/CommandDtoUtils_fromYaml_Test.java |  7 +++++
 2 files changed, 42 insertions(+)

diff --git a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.commands-with-scalar-params-multi-document-trailing-empty.yaml b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.commands-with-scalar-params-multi-document-trailing-empty.yaml
new file mode 100644
index 00000000000..94149c9eaf6
--- /dev/null
+++ b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.commands-with-scalar-params-multi-document-trailing-empty.yaml
@@ -0,0 +1,35 @@
+majorVersion: "2"
+minorVersion: "0"
+interactionId: "08c210e1-55c0-4c45-83db-491f6581e621"
+timestamp: "2026-04-21T09:43:58.169+00:00"
+username: "estatio-admin"
+targets:
+  oid:
+    - type: "outgoing.invoiceforlease.InvoiceForLease"
+      id: "419264"
+member: !<ACT>
+  logicalMemberIdentifier: "outgoing.invoiceforlease.InvoiceForLease#approve"
+  interactionType: "action_invocation"
+---
+majorVersion: "2"
+minorVersion: "0"
+interactionId: "0e2ad15e-c1d8-48c5-8b63-b8cdde673715"
+timestamp: "2026-04-21T09:45:07.409+00:00"
+username: "estatio-admin"
+targets:
+  oid:
+    - type: "outgoing.invoiceforlease.InvoiceForLease"
+      id: "419264"
+member: !<ACT>
+  parameters:
+    parameter:
+      - localDate: "2026-04-20"
+        type: "localDate"
+        name: "Invoice Date"
+      - boolean: false
+        type: "boolean"
+        name: "Allow Invoice Date In Future"
+  logicalMemberIdentifier: "outgoing.invoiceforlease.InvoiceForLease#invoice"
+  interactionType: "action_invocation"
+---
+
diff --git a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.java b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.java
index 27767f4e37f..b4d9a80e3f7 100644
--- a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.java
+++ b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.java
@@ -51,6 +51,13 @@ public void scalarValuesAsMultiDocument() throws IOException {
         assertScalarCommands(commandDtos);
     }
 
+    @Test
+    public void scalarValuesAsMultiDocumentWithTrailingEmptyDocument() throws IOException {
+        var commandDtos = loadCommands("commands-with-scalar-params-multi-document-trailing-empty.yaml");
+
+        assertScalarCommands(commandDtos);
+    }
+
     private static void assertScalarCommands(final List<CommandDto> commandDtos) {
 
         Assertions.assertThat(commandDtos).hasSize(2);


(causeway) 03/05: CAUSEWAY-3989: adds support for converting lists to UTF8 encoded YAML with specified marshalling modes

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-3989
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit 7f3ba4ec54a0f137588c2312b00a69b7fdaff30c
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 24 11:41:14 2026 +0100

    CAUSEWAY-3989: adds support for converting lists to UTF8 encoded YAML with specified marshalling modes
---
 .../org/apache/causeway/commons/io/YamlUtils.java  | 40 +++++++++++++++++++++
 .../apache/causeway/commons/io/YamlUtilsTest.java  | 42 ++++++++++++++++++++++
 2 files changed, 82 insertions(+)

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 c8bc8ac187e..4333bba8429 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
@@ -19,6 +19,7 @@
 package org.apache.causeway.commons.io;
 
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 
@@ -42,6 +43,11 @@
 @UtilityClass
 public class YamlUtils {
 
+    public enum Marshalling {
+        YAML_LIST,
+        MULTI_DOC
+    }
+
     // -- READING
 
     /**
@@ -111,6 +117,40 @@ public static String toStringUtf8(
                 ? createJacksonWriter(customizers).writeValueAsString(pojo)
                 : null;
     }
+
+    /**
+     * Converts given list to UTF8 encoded YAML using the requested marshalling mode.
+     * @return <code>null</code> if list is <code>null</code>
+     */
+    @SneakyThrows
+    @Nullable
+    public static String toStringUtf8ForList(
+            final @Nullable List<?> list,
+            final @NonNull Marshalling marshalling,
+            final JsonUtils.JacksonCustomizer ... customizers) {
+        if (list == null) {
+            return null;
+        }
+        if (marshalling == Marshalling.YAML_LIST) {
+            return toStringUtf8(list, customizers);
+        }
+        return toStringUtf8AsMultiDocument(list, customizers);
+    }
+
+    @SneakyThrows
+    private static String toStringUtf8AsMultiDocument(
+            final List<?> list,
+            final JsonUtils.JacksonCustomizer ... customizers) {
+        if (list.isEmpty()) {
+            return "";
+        }
+        final var mapper = createJacksonWriter(customizers);
+        final List<String> serializedDocuments = new ArrayList<>();
+        for (Object element : list) {
+            serializedDocuments.add(mapper.writeValueAsString(element));
+        }
+        return String.join("---\n", serializedDocuments);
+    }
     // -- CUSTOMIZERS
 
     /**
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 0ea013848d5..9abd229a8e2 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
@@ -18,11 +18,15 @@
  */
 package org.apache.causeway.commons.io;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 import org.approvaltests.Approvals;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import org.apache.causeway.commons.io._TestDomain.Person;
 
@@ -43,6 +47,44 @@ void toStringUtf8() {
         Approvals.verify(yaml);
     }
 
+    @Test
+    void toStringUtf8ForList_yamlList() {
+        val person2 = _TestDomain.samplePerson();
+        person2.setName("fred");
+
+        val yaml = YamlUtils.toStringUtf8ForList(
+                List.of(person, person2),
+                YamlUtils.Marshalling.YAML_LIST);
+        assertNotNull(yaml);
+
+        val roundTrip = YamlUtils.tryReadAsList(Person.class, DataSource.ofStringUtf8(yaml))
+                .valueAsNonNullElseFail();
+
+        assertEquals(List.of("sven", "fred"),
+                roundTrip.stream().map(Person::getName).collect(Collectors.toList()));
+    }
+
+    @Test
+    void toStringUtf8ForList_multiDoc() {
+        val person2 = _TestDomain.samplePerson();
+        person2.setName("fred");
+
+        val yaml = YamlUtils.toStringUtf8ForList(
+                List.of(person, person2),
+                YamlUtils.Marshalling.MULTI_DOC);
+        assertNotNull(yaml);
+
+        val docs = yaml.split("(?m)^---\\s*$");
+
+        val first = YamlUtils.tryRead(Person.class, docs[0])
+                .valueAsNonNullElseFail();
+        val second = YamlUtils.tryRead(Person.class, docs[1])
+                .valueAsNonNullElseFail();
+
+        assertEquals("sven", first.getName());
+        assertEquals("fred", second.getName());
+    }
+
     @Test
     void parseRecord() {
         var yamlTemplate = ""


(causeway) 01/05: CAUSEWAY-3989: enhances YAML command DTO processing with multi-document support and adds corresponding tests

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-3989
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit b29b16aea96ba92873a020162065ab9a9c5adce0
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 24 11:28:25 2026 +0100

    CAUSEWAY-3989: enhances YAML command DTO processing with multi-document support and adds corresponding tests
---
 .../applib/util/schema/CommandDtoUtils.java        | 71 ++++++++++++++++++----
 ...commands-with-scalar-params-multi-document.yaml | 34 +++++++++++
 .../util/schema/CommandDtoUtils_fromYaml_Test.java | 12 ++++
 .../applib/dom/replay/CommandReplayManager.java    |  8 +--
 4 files changed, 108 insertions(+), 17 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/causeway/applib/util/schema/CommandDtoUtils.java b/api/applib/src/main/java/org/apache/causeway/applib/util/schema/CommandDtoUtils.java
index 997a100625a..356a835934c 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/util/schema/CommandDtoUtils.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/util/schema/CommandDtoUtils.java
@@ -19,8 +19,10 @@
 package org.apache.causeway.applib.util.schema;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 import javax.xml.datatype.DatatypeConstants;
@@ -37,6 +39,7 @@
 import org.apache.causeway.commons.io.JsonUtils;
 import org.apache.causeway.commons.io.JsonUtils.JacksonCustomizer;
 import org.apache.causeway.commons.io.YamlUtils;
+import org.apache.causeway.commons.functional.Try;
 import org.apache.causeway.schema.cmd.v2.ActionDto;
 import org.apache.causeway.schema.cmd.v2.CommandDto;
 import org.apache.causeway.schema.cmd.v2.MapDto;
@@ -59,6 +62,7 @@
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.jsontype.NamedType;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 
 import lombok.experimental.UtilityClass;
 
@@ -167,19 +171,60 @@ public ObjectMapper apply(ObjectMapper mapper) {
     }
 
     public List<CommandDto> fromYaml(final DataSource commandDtosYaml) {
-    	final JsonUtils.JacksonCustomizer customizer = new JacksonCustomizer() {
-			@Override
-			public ObjectMapper apply(ObjectMapper mapper) {
-				JsonUtils.jaxbAnnotationSupport(mapper);
-				CommandDtoUtils.memberDtoSupport(mapper);
-				CommandDtoUtils.valueDtoSupport(mapper);
-				return mapper;
-			}
-		};
-        return YamlUtils.tryReadAsList(CommandDto.class, commandDtosYaml, customizer)
-            .ifFailureFail()
-            .getValue()
-            .orElseGet(Collections::emptyList);
+	    final JsonUtils.JacksonCustomizer customizer = yamlCommandDtoCustomizer();
+
+        final Try<List<CommandDto>> asList = YamlUtils.tryReadAsList(CommandDto.class, commandDtosYaml, customizer);
+        if (asList.isSuccess()) {
+            return asList.getValue().orElseGet(Collections::emptyList);
+        }
+
+        final Try<List<CommandDto>> asMultiDocument = tryReadAsMultiDocument(CommandDto.class, commandDtosYaml, customizer);
+        asMultiDocument.getFailure().ifPresent(multiDocFailure ->
+            asList.getFailure().ifPresent(multiDocFailure::addSuppressed));
+
+        return asMultiDocument
+                .ifFailureFail()
+                .getValue()
+                .orElseGet(Collections::emptyList);
+    }
+
+    private JsonUtils.JacksonCustomizer yamlCommandDtoCustomizer() {
+        return mapper -> {
+            JsonUtils.jaxbAnnotationSupport(mapper);
+            CommandDtoUtils.memberDtoSupport(mapper);
+            CommandDtoUtils.valueDtoSupport(mapper);
+            return mapper;
+        };
+    }
+
+    private <T> Try<List<T>> tryReadAsMultiDocument(
+            final Class<T> elementType,
+            final DataSource source,
+            final JsonUtils.JacksonCustomizer ... customizers) {
+        return source.tryReadAll(is -> Try.call(() -> {
+            final ObjectMapper mapper = createYamlReader(customizers);
+            final var documentReader = mapper.readerFor(elementType).readValues(is);
+            final List<T> elements = new ArrayList<>();
+            while (documentReader.hasNextValue()) {
+                final T next = documentReader.nextValue();
+                if (next != null) {
+                    elements.add(next);
+                }
+            }
+            return elements;
+        }));
+    }
+
+    private ObjectMapper createYamlReader(final JsonUtils.JacksonCustomizer ... customizers) {
+        var mapper = new ObjectMapper(new YAMLFactory());
+        mapper = JsonUtils.jdk8Support(mapper);
+        mapper = JsonUtils.readingJavaTimeSupport(mapper);
+        mapper = JsonUtils.readingCanSupport(mapper);
+        for (JsonUtils.JacksonCustomizer customizer : customizers) {
+            mapper = Optional.ofNullable(customizer.apply(mapper))
+                    .orElse(mapper);
+        }
+        return mapper;
     }
 
     // Mix-in to add type metadata to MemberDto
diff --git a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.commands-with-scalar-params-multi-document.yaml b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.commands-with-scalar-params-multi-document.yaml
new file mode 100644
index 00000000000..8ad1657ae59
--- /dev/null
+++ b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.commands-with-scalar-params-multi-document.yaml
@@ -0,0 +1,34 @@
+majorVersion: "2"
+minorVersion: "0"
+interactionId: "08c210e1-55c0-4c45-83db-491f6581e621"
+timestamp: "2026-04-21T09:43:58.169+00:00"
+username: "estatio-admin"
+targets:
+  oid:
+    - type: "outgoing.invoiceforlease.InvoiceForLease"
+      id: "419264"
+member: !<ACT>
+  logicalMemberIdentifier: "outgoing.invoiceforlease.InvoiceForLease#approve"
+  interactionType: "action_invocation"
+---
+majorVersion: "2"
+minorVersion: "0"
+interactionId: "0e2ad15e-c1d8-48c5-8b63-b8cdde673715"
+timestamp: "2026-04-21T09:45:07.409+00:00"
+username: "estatio-admin"
+targets:
+  oid:
+    - type: "outgoing.invoiceforlease.InvoiceForLease"
+      id: "419264"
+member: !<ACT>
+  parameters:
+    parameter:
+      - localDate: "2026-04-20"
+        type: "localDate"
+        name: "Invoice Date"
+      - boolean: false
+        type: "boolean"
+        name: "Allow Invoice Date In Future"
+  logicalMemberIdentifier: "outgoing.invoiceforlease.InvoiceForLease#invoice"
+  interactionType: "action_invocation"
+
diff --git a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.java b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.java
index bf46b304166..27767f4e37f 100644
--- a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.java
+++ b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_fromYaml_Test.java
@@ -41,6 +41,18 @@ public class CommandDtoUtils_fromYaml_Test {
     public void scalarValues() throws IOException {
         var commandDtos = loadCommands("commands-with-scalar-params.yaml");
 
+        assertScalarCommands(commandDtos);
+    }
+
+    @Test
+    public void scalarValuesAsMultiDocument() throws IOException {
+        var commandDtos = loadCommands("commands-with-scalar-params-multi-document.yaml");
+
+        assertScalarCommands(commandDtos);
+    }
+
+    private static void assertScalarCommands(final List<CommandDto> commandDtos) {
+
         Assertions.assertThat(commandDtos).hasSize(2);
 
         ActionDto firstAction = (ActionDto) commandDtos.get(0).getMember();
diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.java b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.java
index b326e4c4be2..b6f5e9d6aad 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.java
@@ -43,6 +43,7 @@
 import org.apache.causeway.applib.annotation.SemanticsOf;
 import org.apache.causeway.applib.util.schema.CommandDtoUtils;
 import org.apache.causeway.applib.value.Blob;
+import org.apache.causeway.applib.value.Clob;
 import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
 import org.apache.causeway.extensions.commandlog.applib.CausewayModuleExtCommandLogApplib;
 import org.apache.causeway.extensions.commandlog.applib.dom.CommandLogEntryRepository;
@@ -169,10 +170,9 @@ private static Timestamp addSeconds(Timestamp since, int secondsToAdd) {
     public class importCommands {
         public class DomainEvent extends ActionDomainEvent<importCommands> { }
         public CommandReplayManager act(
-                @Parameter(fileAccept = ".zip")
-                final Blob zippedCommandsYaml) {
-
-            var yamlDs = zippedCommandsYaml.unZip(CommonMimeType.YAML).asDataSource();
+                @Parameter(fileAccept = ".yml")
+                final Blob commandsYaml) {
+            var yamlDs = commandsYaml.asDataSource();
 
             final List<CommandDto> commandDtos = CommandDtoUtils.fromYaml(yamlDs);
             commandDtos.forEach(commandLogEntryRepository()::saveForReplay);


(causeway) 05/05: CAUSEWAY-3989: refactors YAML processing in CommandDtoUtils to use multidoc format.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-3989
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit b28d78d1b48444d1e6387048cae23ef8fdd4060e
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 24 11:54:59 2026 +0100

    CAUSEWAY-3989: refactors YAML processing in CommandDtoUtils to use multidoc format.
---
 api/applib/src/main/java/module-info.java            |  4 +---
 .../causeway/applib/util/schema/CommandDtoUtils.java | 20 +++++++++++---------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/api/applib/src/main/java/module-info.java b/api/applib/src/main/java/module-info.java
index 4131e569bcf..9e3bfdcf8c9 100644
--- a/api/applib/src/main/java/module-info.java
+++ b/api/applib/src/main/java/module-info.java
@@ -124,8 +124,6 @@
     exports org.apache.causeway.applib.value;
     exports org.apache.causeway.applib.value.semantics;
 
-    requires com.fasterxml.jackson.core;
-    requires com.fasterxml.jackson.databind;
     requires transitive jakarta.activation;
     requires transitive java.annotation;
     requires transitive java.desktop;
@@ -146,7 +144,7 @@
     requires transitive spring.core;
     requires spring.tx;
     requires org.apache.logging.log4j.core;
-	requires com.fasterxml.jackson.annotation;
+    requires com.fasterxml.jackson.dataformat.yaml;
 
     // JAXB viewmodels
     opens org.apache.causeway.applib.annotation;
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/util/schema/CommandDtoUtils.java b/api/applib/src/main/java/org/apache/causeway/applib/util/schema/CommandDtoUtils.java
index 356a835934c..0a8cfd4dcdd 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/util/schema/CommandDtoUtils.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/util/schema/CommandDtoUtils.java
@@ -57,6 +57,7 @@
 import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.MappingIterator;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializerProvider;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -154,7 +155,7 @@ private MapDto userDataFor(final CommandDto commandDto) {
     // -- YAML SUPPORT
 
     public String toYaml(final Iterable<CommandDto> commandDtos) {
-    	final JsonUtils.JacksonCustomizer customizer = new JacksonCustomizer() {
+    	final var customizer = new JacksonCustomizer() {
 			@Override
 			public ObjectMapper apply(ObjectMapper mapper) {
 				JsonUtils.jaxbAnnotationSupport(mapper);
@@ -164,14 +165,15 @@ public ObjectMapper apply(ObjectMapper mapper) {
 				return mapper;
 			}
 		};
-        return YamlUtils.toStringUtf8(
-            _NullSafe.stream(commandDtos)
-                .collect(Collectors.toList()),
-            customizer);
+        final var commandDtoList = _NullSafe.stream(commandDtos)
+                .collect(Collectors.toList());
+        return YamlUtils.toStringUtf8ForList(
+                commandDtoList, YamlUtils.Marshalling.MULTI_DOC,
+                customizer);
     }
 
     public List<CommandDto> fromYaml(final DataSource commandDtosYaml) {
-	    final JsonUtils.JacksonCustomizer customizer = yamlCommandDtoCustomizer();
+	    final var customizer = yamlCommandDtoCustomizer();
 
         final Try<List<CommandDto>> asList = YamlUtils.tryReadAsList(CommandDto.class, commandDtosYaml, customizer);
         if (asList.isSuccess()) {
@@ -202,8 +204,8 @@ private <T> Try<List<T>> tryReadAsMultiDocument(
             final DataSource source,
             final JsonUtils.JacksonCustomizer ... customizers) {
         return source.tryReadAll(is -> Try.call(() -> {
-            final ObjectMapper mapper = createYamlReader(customizers);
-            final var documentReader = mapper.readerFor(elementType).readValues(is);
+            final var mapper = createYamlReader(customizers);
+            final MappingIterator<T> documentReader = mapper.readerFor(elementType).readValues(is);
             final List<T> elements = new ArrayList<>();
             while (documentReader.hasNextValue()) {
                 final T next = documentReader.nextValue();
@@ -220,7 +222,7 @@ private ObjectMapper createYamlReader(final JsonUtils.JacksonCustomizer ... cust
         mapper = JsonUtils.jdk8Support(mapper);
         mapper = JsonUtils.readingJavaTimeSupport(mapper);
         mapper = JsonUtils.readingCanSupport(mapper);
-        for (JsonUtils.JacksonCustomizer customizer : customizers) {
+        for (final var customizer : customizers) {
             mapper = Optional.ofNullable(customizer.apply(mapper))
                     .orElse(mapper);
         }