From 13552f624b855954c16e2fb7e4a3b992b35e01c3 Mon Sep 17 00:00:00 2001 From: Soby Chacko Date: Thu, 21 Dec 2023 17:18:52 -0500 Subject: [PATCH] GH-2794: AMCB ObjectMaper serialization issues Fixes https://github.com/spring-cloud/spring-cloud-stream/issues/2794 The custom ObjectMapper used in AMCB is unable to serialize java.time.Duration values. To fix this, the ObjectMapper needs to register the JavaTimeModule from the jackson-datatype-jsr310 libarary. Adding a test to verify the fix. --- core/spring-cloud-stream/pom.xml | 4 + .../binder/AbstractMessageChannelBinder.java | 3 +- .../AbstractMessageChannelBinderTests.java | 75 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 core/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinderTests.java diff --git a/core/spring-cloud-stream/pom.xml b/core/spring-cloud-stream/pom.xml index 2cfbb10bd..c573abe70 100644 --- a/core/spring-cloud-stream/pom.xml +++ b/core/spring-cloud-stream/pom.xml @@ -84,6 +84,10 @@ org.jetbrains.kotlin kotlin-stdlib-jdk8 + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + diff --git a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinder.java b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinder.java index f9daf5c0c..6b966fd75 100644 --- a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinder.java +++ b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/AbstractMessageChannelBinder.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.apache.commons.logging.Log; import org.springframework.beans.factory.BeanFactoryAware; @@ -147,7 +148,7 @@ public abstract class AbstractMessageChannelBinder binder = new AbstractMessageChannelBinder<>(null, null) { + @Override + protected MessageHandler createProducerMessageHandler(ProducerDestination destination, ProducerProperties producerProperties, MessageChannel errorChannel) { + return null; + } + + @Override + protected MessageProducer createConsumerEndpoint(ConsumerDestination destination, String group, ConsumerProperties properties) { + return null; + } + }; + final GenericApplicationContext applicationContext = new GenericApplicationContext(); + applicationContext.refresh(); + binder.setApplicationContext(applicationContext); + binder.onInit(); + + Field objectMapperField = ReflectionUtils.findField(AbstractMessageChannelBinder.class, "objectMapper"); + assertThat(objectMapperField).isNotNull(); + ReflectionUtils.makeAccessible(objectMapperField); + final ObjectMapper objectMapper = (ObjectMapper) ReflectionUtils.getField(objectMapperField, binder); + assertThat(objectMapper).isNotNull(); + + Duration duration = Duration.ofHours(1); + Map properties = Map.of("foo", duration); + final Map convertedMap = objectMapper.convertValue(properties, Map.class); + + assertThat(convertedMap).isNotEmpty(); + } +}