From 0e4ef158d8e0a1c4aec1d0c90dd925d8a5e24a5e Mon Sep 17 00:00:00 2001 From: Chad Retz Date: Tue, 5 Mar 2024 09:21:22 -0600 Subject: [PATCH] Support newer JSON history format (#2001) --- .../common/WorkflowExecutionHistory.java | 3 ++- .../internal/common/HistoryJsonUtils.java | 10 ++++++- .../common/WorkflowExecutionHistory.java | 21 ++++++++++++--- .../common/WorkflowExecutionHistoryTest.java | 27 ++++++++++++++++--- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/temporal-sdk/src/main/java/io/temporal/common/WorkflowExecutionHistory.java b/temporal-sdk/src/main/java/io/temporal/common/WorkflowExecutionHistory.java index 7d205788b..0576c753a 100644 --- a/temporal-sdk/src/main/java/io/temporal/common/WorkflowExecutionHistory.java +++ b/temporal-sdk/src/main/java/io/temporal/common/WorkflowExecutionHistory.java @@ -83,7 +83,8 @@ public static WorkflowExecutionHistory fromJson(String serialized, String workfl } /** - * @return full json that can be used for replay and which is compatible with tctl + * @param prettyPrint Whether to pretty print the JSON. + * @return Full json that can be used for replay. */ public String toJson(boolean prettyPrint) { return super.toJson(prettyPrint); diff --git a/temporal-sdk/src/main/java/io/temporal/internal/common/HistoryJsonUtils.java b/temporal-sdk/src/main/java/io/temporal/internal/common/HistoryJsonUtils.java index 0710a1595..68a41da49 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/common/HistoryJsonUtils.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/common/HistoryJsonUtils.java @@ -65,7 +65,15 @@ public static String protoJsonToHistoryFormatJson(String protoJson) { } public static String historyFormatJsonToProtoJson(String historyFormatJson) { - return convertEnumValues(historyFormatJson, ProtoEnumNameUtils::simplifiedToUniqueName); + return convertEnumValues( + historyFormatJson, + (enumName, prefix) -> { + // Only convert if the enum name isn't already converted + if (enumName.indexOf('_') >= 0) { + return enumName; + } + return ProtoEnumNameUtils.simplifiedToUniqueName(enumName, prefix); + }); } private static String convertEnumValues( diff --git a/temporal-sdk/src/main/java/io/temporal/internal/common/WorkflowExecutionHistory.java b/temporal-sdk/src/main/java/io/temporal/internal/common/WorkflowExecutionHistory.java index c95c979ae..7c98c4212 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/common/WorkflowExecutionHistory.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/common/WorkflowExecutionHistory.java @@ -84,20 +84,33 @@ private static void checkHistory(History history) { } /** - * @return full json that can be used for replay and which is compatible with tctl + * @param prettyPrint Whether to pretty print the JSON. + * @return Full json that can be used for replay. */ public String toJson(boolean prettyPrint) { + return toJson(prettyPrint, false); + } + + /** + * @param prettyPrint Whether to pretty print the JSON. + * @param legacyFormat If true, will use the older-style protobuf enum formatting as done by + * Temporal tooling in the past. This is not recommended. + * @return Full JSON that can be used for replay. + */ + public String toJson(boolean prettyPrint, boolean legacyFormat) { JsonFormat.Printer printer = JsonFormat.printer(); try { String protoJson = printer.print(history); - String historyFormatJson = HistoryJsonUtils.protoJsonToHistoryFormatJson(protoJson); + if (legacyFormat) { + protoJson = HistoryJsonUtils.protoJsonToHistoryFormatJson(protoJson); + } if (prettyPrint) { @SuppressWarnings("deprecation") - JsonElement je = GSON_PARSER.parse(historyFormatJson); + JsonElement je = GSON_PARSER.parse(protoJson); return GSON_PRETTY_PRINTER.toJson(je); } else { - return historyFormatJson; + return protoJson; } } catch (InvalidProtocolBufferException e) { throw new DataConverterException(e); diff --git a/temporal-sdk/src/test/java/io/temporal/internal/common/WorkflowExecutionHistoryTest.java b/temporal-sdk/src/test/java/io/temporal/internal/common/WorkflowExecutionHistoryTest.java index e7b7796e4..fa7c61774 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/common/WorkflowExecutionHistoryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/common/WorkflowExecutionHistoryTest.java @@ -21,7 +21,7 @@ package io.temporal.internal.common; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import com.google.common.io.CharStreams; import io.temporal.common.WorkflowExecutionHistory; @@ -62,6 +62,7 @@ public void deserializeAndSerializeBackComplexHistory() throws IOException { } public void deserializeAndSerializeBack(String resourceName) throws IOException { + // Load legacy-format history ClassLoader classLoader = WorkflowExecutionUtils.class.getClassLoader(); URL resource = classLoader.getResource(resourceName); String historyUrl = resource.getFile(); @@ -70,10 +71,30 @@ public void deserializeAndSerializeBack(String resourceName) throws IOException try (Reader reader = Files.newBufferedReader(historyFile.toPath(), UTF_8)) { originalSerializedJsonHistory = CharStreams.toString(reader); } + originalSerializedJsonHistory = originalSerializedJsonHistory.replace("\r\n", "\n"); + + // Confirm original history is legacy format + assertTrue( + originalSerializedJsonHistory.contains("\"eventType\": \"WorkflowExecutionStarted\"")); + assertFalse( + originalSerializedJsonHistory.contains( + "\"eventType\": \"EVENT_TYPE_WORKFLOW_EXECUTION_STARTED\"")); WorkflowExecutionHistory history = WorkflowHistoryLoader.readHistoryFromResource(resourceName); - String serializedHistory = history.toJson(true); - assertEquals(originalSerializedJsonHistory, serializedHistory); + // Confirm serialized to old matches char-for-char + assertEquals(originalSerializedJsonHistory, history.toJson(true, true)); + + // Confirm can convert to new-format + String newFormatSerializedHistory = history.toJson(true); + assertFalse(newFormatSerializedHistory.contains("\"eventType\": \"WorkflowExecutionStarted\"")); + assertTrue( + newFormatSerializedHistory.contains( + "\"eventType\": \"EVENT_TYPE_WORKFLOW_EXECUTION_STARTED\"")); + + // And that new format is parsed correctly + WorkflowExecutionHistory newFormatHistory = + WorkflowExecutionHistory.fromJson(newFormatSerializedHistory); + assertEquals(history.getHistory(), newFormatHistory.getHistory()); } }