Spring Integration 5 – Cloning Messages

By | November 21, 2017

This is an article in a series of articles introducing Spring Integration 5. I imagine most of the examples can be applied to earlier versions of Spring Integration as well, it just happens that I started out with Spring Integration 5 and I have little reason to investigate compatibility with previous versions.

The articles assume no previous experience of Spring Integration apart from any earlier articles in the series.

Previous Articles

This is a list of the previous articles in this series in chronological order:

Examples Repository

All the examples in this series of articles are taken from my Spring Integration Scrutinized repository which is available on GitHub.

Cloning Spring Integration Messages

As with message creation, there are two ways of cloning a Spring Integration message; either using the Java new operator or using a message builder. I first thought that the different alternatives were equal with regard to the end result but this is not the case.
I have used the word cloning in a less strict fashion in this article. In the code examples an exact clone is sometimes indeed the result but this is not the most common case.

Immutable Messages

As in the previous article, immutable messages are the message type to be preferred. As we will see, this is also true regarding cloning immutable messages. The message builder type to be used with immutable messages is named MessageBuilder and can be found in the package org.springframework.integration.support. The class implementing the behaviour of immutable messages is the GenericMessage class that is found in the package org.springframework.messaging.support.

Cloning Using MessageBuilder

I assumed that I would include an example showing cloning of immutable messages just for completeness sake but after having written the example, I realized that it did teach me one important thing: Cloning an immutable message using the MessageBuilder does not create a copy of the message but returns a reference to the original message.

Cloning an immutable message using MessageBuilder returns a reference to the original message.

Cloning an immutable message using MessageBuilder returns a reference to the original message.

The example code from the class GenericMessageTests:

Note that:

  • The original message is just cloned with no modifications using the MessageBuilder.fromMessage method.
  • The cloned message and the original message are one and the same instance.
    The consequence of this is that the message ids and timestamps are identical on the message.

Cloning Using MessageBuilder and Adding a Header

Having cloned an immutable message above noting that the clone is really one and the same message instance I became curious what would happen if a message is created from one message, as with cloning, and a new message header added in the process, still using the MessageBuilder.

Cloning an immutable message and adding a message header using MessageBuilder.

Cloning an immutable message and adding a message header using MessageBuilder.

From GenericMessageTests:

Note that:

  • The original message is again cloned using MessageBuilder.fromMessage.
    However, before invoking the build method on the message builder, the setHeader method is used to add a new message header to the new message.
  • The original message and new message are no longer one and the same instance.
  • The payloads of the first and second messages are equal.
  • The header from the first message is present in the second message with the same value.
  • The message id and timestamp headers are different in the two messages.

Cloning Using a Constructor

Immutable messages can also be cloned, in the word’s proper meaning, using a constructor of the GenericMessage class:

Note that:

  • The first, original, message is created as usual using the message builder.
  • The second message is created using the GenericMessage constructor that takes two parameters.
    The first parameter is what is to become the message payload, the second is a map that contains what will become the message headers.
  • The payloads of the original and clone messages are expected to be equal.
  • All the message headers, including the id and timestamp headers, are expected to be equal.

Mutable Messages

The message builder type to be used with mutable messages is named MutableMessageBuilder and can be found in the package org.springframework.integration.support. The class implementing the behaviour of mutable messages is the MutableMessage class that is found in the package org.springframework.messaging.support.

When it comes to cloning mutable Spring Integration messages, things are no longer as obvious as with immutable messages.

Pitfall: Cloning Mutable Messages Using a Message Builder

The following test shows a pitfall of the MutableMessageBuilder which manifest itself when cloning a message. Since, by design, the message builder creates a message that shares one and the same MessageHeaders object with the original message any modifications to headers in either of the messages will affect the headers of the other message.

Cloning a mutable message using MutableMessageBuilder and modifying a message header.

Cloning a mutable message using MutableMessageBuilder and modifying a message header.

The example test is taken from the MutableMessageTests class:

Note that:

  • The first message is created using the MutableMessageBuilder in the same manner as we have seen in a previous example.
    A message header is set on the message.
  • A second message is created using the MutableMessageBuilder.
    In this case, the fromMessage
    method is used which takes a message parameter. The expected behaviour is that the first message should be cloned – at least this is what I was expecting.
  • The value of the message header is verified to contain the same value in the first and second messages.
  • The value of the message header is modified in the second message.
    Note also that this is only possible in mutable messages.
  • Finally, an attempt to verify that the message header values differ in the first and second messages is made.

After having contacted one of the authors of the MutableMessageBuilder the response that I received was that the MutableMessageBuilder class is purposely designed this way and is not intended for general use.

Cloning Using a Constructor

Now that I have told about how not to clone mutable messages, I feel obliged to give a better alternative.

Cloning a mutable message using a constructor and modifying a message header.

Cloning a mutable message using a constructor and modifying a message header.

The following example from the MutableMessageTests class examines the behaviour of cloning mutable messages using a constructor of the MutableMessage class:

Note that:

  • The first message is created in the same way as in the previous test, using the MutableMessageBuilder.
  • The second message is created using a constructor of the MutableMessage class.
    This constructor takes two parameters; the payload and the headers of the new message. In this example these are the payload and headers of the first message.
  • As in the previous test, the message header value of the second message is modified.
  • Unlike the previous test, modification of the message headers in the second message does not affect the message headers of the first message.
  • The timestamp and id message headers are identical in the two messages.
    The last assertion in the test verifies this.

Using the above method of creating a new message from an existing message indeed clones the message, including the id and timestamp message headers. Yet the cloned message is a message that is independent of the original message and can be modified as desired, without affecting the original message.

I suggest some caution: Here you actually have two different messages that have the same message id. If the original message is no longer used after having created a clone of it, then fine. If you continue to use both the messages in your application, you may cause some confusion and even errors.

A Better Way to Clone a Mutable Message Using a Message Builder

The MutableMessageBuilder is not useless, as far as cloning messages is concerned. There is a better way to use it that will produce a clone of a message that does have its own set of independent message headers, as can be seen in the following example from MutableMessageTests. The figure showing the end result of the message cloning is identical with that of the previous example:

Cloning a mutable message using MutableMessageBuilder in two steps and modifying a message header.

Cloning a mutable message using MutableMessageBuilder in two steps and modifying a message header.



Note that:

  • The original message is created as we have seen earlier using the MutableMessageBuilder.
  • The second message is also created using the MutableMessageBuilder.
    However, instead of using the fromMessage method the two methods withPayload and copyHeaders are used.
  • Both message are examined as to make sure they both contain the message header with the name “myHeaderName”.
  • After having modified the message header named “myHeaderName” in the second, cloned, message we verify that the value of this message header in the original, first, message is not the same as that in the second message.
  • Finally the timestamp and id message headers are verified to be equal in both the messages.

Summary on Cloning Messages

I feel that I need to summarize to reduce the risk of confusion – if nothing else, then to reduce the risk of confusing myself.

Cloning Immutable Messages

When cloning immutable messages, I would use the MessageBuilder without reservations.
If you want an exact copy of an immutable message, you will get another reference to the original message back. The message is immutable so nothing can go wrong.
If you want to clone an immutable message and, in the process, alter it so that it differs from the original message then the MessageBuilder will manage that as well and create a new message with a new message id and timestamp for you.

Cloning Mutable Messages

Cloning mutable messages is not as straightforward as cloning immutable messages.
There are two things to observe when cloning mutable messages:

  1. Stay away from the MutableMessageBuilder.fromMessage method.
    It will create a new message but reuse the MessageHeaders object from the original message meaning that any manipulation of message headers will affect both messages.
  2. Create a new message id for your cloned message unless you are absolutely sure that you want to use the original message id.

Stay tuned for next part in this series.

Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *

Enter Captcha Here : *

Reload Image