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/06/19 06:47:32 UTC
(causeway) 01/11: CAUSEWAY-4024: updates the timestamp properly within the DTO
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch CAUSEWAY-4039
in repository https://gitbox.apache.org/repos/asf/causeway.git
commit 8908b5a0fd21b41770d01004a451ffc7cee2969b
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Thu Jun 18 17:22:04 2026 +0100
CAUSEWAY-4024: updates the timestamp properly within the DTO
---
.../applib/util/schema/CommandDtoUtils.java | 29 +++++++++++
.../schema/CommandDtoUtils_copy_Approval_Test.java | 59 ++++++++++++++++++++++
...pproval_Test.marshals_command_copy.approved.txt | 14 +++++
..._Approval_Test.marshals_command_copy.input.yaml | 32 ++++++++++++
.../CommandExportManagerMovementSupport.java | 9 +++-
5 files changed, 141 insertions(+), 2 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 7a426769837..6ee9d70f70d 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,12 +19,18 @@
package org.apache.causeway.applib.util.schema;
import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
@@ -285,6 +291,29 @@ private JsonUtils.JacksonCustomizer yamlCommandDtoCustomizer() {
};
}
+ public static CommandDto copy(final CommandDto commandDto) {
+ if (commandDto == null) {
+ return null;
+ }
+ try {
+ final JAXBContext jaxbContext = JaxbUtils.jaxbContextFor(CommandDto.class);
+
+ // create marshaller and unmarshaller per-call (they are NOT thread-safe)
+ final Marshaller marshaller = jaxbContext.createMarshaller();
+ final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ final StringWriter sw = new StringWriter();
+ marshaller.marshal(commandDto, sw);
+
+ final String xml = sw.toString();
+ try (final StringReader sr = new StringReader(xml)) {
+ return (CommandDto) unmarshaller.unmarshal(sr);
+ }
+ } catch (JAXBException e) {
+ throw new RuntimeException("Failed to deep-copy CommandDto", e);
+ }
+ }
+
public static class ImportedCommandDto {
private CommandDto command;
diff --git a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.java b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.java
new file mode 100644
index 00000000000..28a08c34c64
--- /dev/null
+++ b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.causeway.applib.util.schema;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.approvaltests.Approvals;
+import org.approvaltests.core.Options;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.util.StreamUtils;
+
+import org.apache.causeway.commons.io.DataSource;
+import org.apache.causeway.schema.cmd.v2.CommandDto;
+
+class CommandDtoUtils_copy_Approval_Test {
+
+ @Test
+ void marshals_command_copy() throws IOException {
+ // read YAML sample from classpath (existing test resource)
+ final String path = "CommandDtoUtils_copy_Approval_Test.marshals_command_copy.input.yaml";
+ try (InputStream is = getClass().getResourceAsStream(path)) {
+ final String yaml = StreamUtils.copyToString(is, StandardCharsets.UTF_8);
+
+ final List<CommandDto> commands = CommandDtoUtils.fromYaml(DataSource.ofStringUtf8(yaml));
+ Assertions.assertThat(commands).isNotEmpty();
+
+ final CommandDto original = commands.get(0);
+ final CommandDto copy = CommandDtoUtils.copy(original);
+
+ // ensure we actually created a different instance
+ Assertions.assertThat(copy).isNotSameAs(original);
+
+ // marshal the copy to its XML representation and approve
+ final String xml = CommandDtoUtils.dtoMapper().toString(copy);
+ Approvals.verify(xml);
+ }
+ }
+}
+
diff --git a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.marshals_command_copy.approved.txt b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.marshals_command_copy.approved.txt
new file mode 100644
index 00000000000..2d6411d2eb2
--- /dev/null
+++ b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.marshals_command_copy.approved.txt
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<cmd:commandDto xmlns:com="https://causeway.apache.org/schema/common" xmlns:cmd="https://causeway.apache.org/schema/cmd">
+ <cmd:majorVersion>2</cmd:majorVersion>
+ <cmd:minorVersion>0</cmd:minorVersion>
+ <cmd:interactionId>08c210e1-55c0-4c45-83db-491f6581e621</cmd:interactionId>
+ <cmd:timestamp>2026-04-21T09:43:58.169Z</cmd:timestamp>
+ <cmd:username>estatio-admin</cmd:username>
+ <cmd:targets>
+ <com:oid type="outgoing.invoiceforlease.InvoiceForLease" id="419264"/>
+ </cmd:targets>
+ <cmd:member xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="cmd:actionDto" interactionType="action_invocation">
+ <cmd:logicalMemberIdentifier>outgoing.invoiceforlease.InvoiceForLease#approve</cmd:logicalMemberIdentifier>
+ </cmd:member>
+</cmd:commandDto>
diff --git a/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.marshals_command_copy.input.yaml b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.marshals_command_copy.input.yaml
new file mode 100644
index 00000000000..81222d72ad7
--- /dev/null
+++ b/api/applib/src/test/java/org/apache/causeway/applib/util/schema/CommandDtoUtils_copy_Approval_Test.marshals_command_copy.input.yaml
@@ -0,0 +1,32 @@
+- 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/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandExportManagerMovementSupport.java b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandExportManagerMovementSupport.java
index 5b46a5c656d..cecafcc5296 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandExportManagerMovementSupport.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandExportManagerMovementSupport.java
@@ -28,8 +28,10 @@
import java.util.stream.Collectors;
import org.apache.causeway.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
+import org.apache.causeway.applib.util.schema.CommandDtoUtils;
import org.apache.causeway.core.config.CausewayConfiguration;
import org.apache.causeway.extensions.commandlog.applib.dom.CommandLogEntry;
+import org.apache.causeway.schema.cmd.v2.CommandDto;
class CommandExportManagerMovementSupport {
@@ -184,8 +186,11 @@ private static void setTimestamp(
private static void updateCommandDtoTimestamp(
final CommandLogEntry entry,
final Timestamp timestamp) {
- if (entry.getCommandDto() != null) {
- entry.getCommandDto().setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(timestamp));
+ final var commandDto = entry.getCommandDto();
+ if (commandDto != null) {
+ var commandDtoCopy = CommandDtoUtils.copy(commandDto);
+ commandDtoCopy.setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(timestamp));
+ entry.setCommandDto(commandDtoCopy);
}
}