diff --git a/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/JacksonCloudEventUtils.java b/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/JacksonCloudEventUtils.java index 0ad2409ef..d5c037d22 100644 --- a/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/JacksonCloudEventUtils.java +++ b/impl/json-utils/src/main/java/io/serverlessworkflow/impl/jackson/JacksonCloudEventUtils.java @@ -15,14 +15,13 @@ */ package io.serverlessworkflow.impl.jackson; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.POJONode; import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; -import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.jackson.JsonCloudEventData; -import io.cloudevents.jackson.JsonFormat; import java.io.IOException; import java.io.UncheckedIOException; import java.time.OffsetDateTime; @@ -35,14 +34,11 @@ public static JsonNode toJsonNode(CloudEvent event) { if (event == null) { return NullNode.instance; } - // Delegate entirely to the official CloudEvents SDK - byte[] serialized = - EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE).serialize(event); - try { - return JsonUtils.mapper().readTree(serialized); - } catch (IOException e) { - throw new UncheckedIOException(e); + ObjectNode node = JsonUtils.mapper().convertValue(event, ObjectNode.class); + if (node.get("data") instanceof POJONode) { + node.set("data", toJsonNode(event.getData())); } + return node; } public static OffsetDateTime toOffset(Date date) { @@ -66,14 +62,7 @@ public static CloudEvent toCloudEvent(JsonNode node) { if (node == null || node.isNull()) { return null; } - try { - byte[] ceBytes = JsonUtils.mapper().writeValueAsBytes(node); - return EventFormatProvider.getInstance() - .resolveFormat(JsonFormat.CONTENT_TYPE) - .deserialize(ceBytes); - } catch (JsonProcessingException e) { - throw new IllegalArgumentException("Failed to deserialize JsonNode to CloudEvent", e); - } + return JsonUtils.mapper().convertValue(node, CloudEvent.class); } public static CloudEventData toCloudEventData(JsonNode node) { diff --git a/impl/json-utils/src/test/java/io/serverlessworkflow/impl/jackson/JacksonCloudEventUtilsTest.java b/impl/json-utils/src/test/java/io/serverlessworkflow/impl/jackson/JacksonCloudEventUtilsTest.java index 672be8aab..5f433e0f7 100644 --- a/impl/json-utils/src/test/java/io/serverlessworkflow/impl/jackson/JacksonCloudEventUtilsTest.java +++ b/impl/json-utils/src/test/java/io/serverlessworkflow/impl/jackson/JacksonCloudEventUtilsTest.java @@ -25,6 +25,7 @@ import io.cloudevents.CloudEventData; import io.cloudevents.core.builder.CloudEventBuilder; import io.cloudevents.core.data.BytesCloudEventData; +import io.cloudevents.jackson.JsonCloudEventData; import java.net.URI; import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Test; @@ -32,14 +33,36 @@ public class JacksonCloudEventUtilsTest { private CloudEvent createSampleEvent() { + return createEventBuilder() + .withData("{\"status\":\"NEEDS_REVISION\"}".getBytes(StandardCharsets.UTF_8)) + .build(); + } + + private CloudEventBuilder createEventBuilder() { return CloudEventBuilder.v1() .withId("5dc4698e-5f98-470e-bb76-04218fe2dd0f") .withSource(URI.create("api:/newsletter")) .withType("org.acme.newsletter.review.done") .withDataContentType("application/json") - .withExtension("flowinstanceid", "01KMRBFA19GZYW3XY895Z4SNCK") - .withData("{\"status\":\"NEEDS_REVISION\"}".getBytes(StandardCharsets.UTF_8)) - .build(); + .withExtension("flowinstanceid", "01KMRBFA19GZYW3XY895Z4SNCK"); + } + + @Test + public void testCloudEventSerializationNullData() { + CloudEvent event = createEventBuilder().build(); + + JsonNode node = JacksonCloudEventUtils.toJsonNode(event); + + assertNotNull(node); + assertTrue(node.has("specversion"), "Missing mandatory specversion attribute"); + assertEquals("1.0", node.get("specversion").asText()); + + assertFalse(node.has("specVersion"), "Jackson POJO serializer mangled the envelope!"); + + assertEquals("5dc4698e-5f98-470e-bb76-04218fe2dd0f", node.get("id").asText()); + assertEquals("01KMRBFA19GZYW3XY895Z4SNCK", node.get("flowinstanceid").asText()); + + assertFalse(node.has("data")); } @Test @@ -61,6 +84,30 @@ public void testCloudEventSerialization() { assertEquals("NEEDS_REVISION", node.get("data").get("status").asText()); } + @Test + public void testCloudEventSerializationJson() { + CloudEvent event = + createEventBuilder() + .withData( + JsonCloudEventData.wrap( + JsonUtils.mapper().createObjectNode().put("status", "NEEDS_REVISION"))) + .build(); + + JsonNode node = JacksonCloudEventUtils.toJsonNode(event); + + assertNotNull(node); + assertTrue(node.has("specversion"), "Missing mandatory specversion attribute"); + assertEquals("1.0", node.get("specversion").asText()); + + assertFalse(node.has("specVersion"), "Jackson POJO serializer mangled the envelope!"); + + assertEquals("5dc4698e-5f98-470e-bb76-04218fe2dd0f", node.get("id").asText()); + assertEquals("01KMRBFA19GZYW3XY895Z4SNCK", node.get("flowinstanceid").asText()); + + assertTrue(node.has("data")); + assertEquals("NEEDS_REVISION", node.get("data").get("status").asText()); + } + @Test public void testCloudEventDeserialization() { CloudEvent originalEvent = createSampleEvent();