Description
In what version(s) of Spring Integration are you seeing this issue?
v6.2.7
Describe the bug
When MutableMessageHeaders is serialized using Spring Cores DefaultSerializer with a header that is not serializable it can result in the 'headers' property on the class being serialized as the superclass (MessageHeaders) instead of a HashMap. When deserialized this causes the 'headers' property to be an instance of MessageHeaders which prevents callers from adding properties to the MutableMessageHeaders class (When they should be able to). The following error is observed
Exception in thread "main" java.lang.UnsupportedOperationException: MessageHeaders is immutable
at org.springframework.messaging.MessageHeaders.put(MessageHeaders.java:274)
at org.springframework.messaging.MessageHeaders.put(MessageHeaders.java:73)
at org.springframework.integration.support.MutableMessageHeaders.put(MutableMessageHeaders.java:63)
This looks to be related to the writeObject
on the MessageHeaders class which will instantiate a new instance of the MessageHeaders class if there is a non-serializable object in the headers. Its likely that similar functionality needs to be overridden in the MutableMessageHeaders class in order to serialize it correctly. (See https://github.com/spring-projects/spring-framework/blob/main/spring-messaging/src/main/java/org/springframework/messaging/MessageHeaders.java#L307)
If there is no non-serializable objects in the headers then the MutableMessageHeaders works as expected when deserialized, this is because it just writes the object directly in the writeObject
method rather than creating a new instance of MessageHeaders
This issue was originally observed when using the RedisMessageStore with an aggregator which under the hood makes use of the DefaultSerializer class, when I enabled observations it attempted to add the traceparent to the message header after it had been deserialized which then resulted in a failure.
To Reproduce
- Create a MutableMessageHeaders instance with a header value containing a non-serializable instance
- Serialize the class using the SerializingConverter
- Deserialize the class using the DeserializingConverter using the output from step 2
- Attempt to put a header into the deserialized MutableMessageHeaders instance
Expected behavior
Its expected that when MutableMessageHeaders is deserialized back into the object that it should be able to behave as normal and allow headers to be added using the classes 'put' method.
Sample
Link to sample showing bug: https://github.com/mitchmcd18/spring-messageheader-bug
Related links
https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/serializer/support/SerializingConverter.java
https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/serializer/support/DeserializingConverter.java
https://github.com/spring-projects/spring-integration/blob/main/spring-integration-core/src/main/java/org/springframework/integration/support/MutableMessageHeaders.java