Tuesday, August 14, 2012

Good Camel message is the immutable one

A good way to introduce a problem into your Camel-based messaging solution, is to keep mutable data in the messages you exchange.

Whenever you read that Camel creates a copy of the message (for example during the Multicast), keep in mind that we're talking about the shallow copy. Creation of the deep copy of the object in Java is complex due to the performance and logical issues. Due to these issues, Camel copies only references to the body and headers of the original messages.

// Given - multicast will copy incoming message.

// When - messages has been copied
sendBody("direct:xero", "Copy me!");
Object copy1 = getMockEndpoint("mock:copy1").getExchanges().get(0).getIn();
Object copy2 = getMockEndpoint("mock:copy2").getExchanges().get(0).getIn();

// Then - messages are not the same
assertNotSame(copy1, copy2);
// But bodies of the messages are.
assertSame(copy1.getBody(), copy2.getBody());

It is easy then to create the copy of the message that logically is not a copy, since it reference the same mutable structure as the original message from which it was created.

In messaging systems payloads should be unaware of the JVM they live in. Shared Java references introduce implicit knowledge about the JVM memory model to the messages. Camel tip for today is - stick to the immutable messages whenever you can.


  1. Thanks,
    I am putting a hashmap as the body of the message.
    I want to mark one of the entries in the hashmap as immutable.
    how to do that?

    -thanks much

  2. Actually Java HashMap is mutable so using it as a body would make whole message mutable as well. And unfortunately you cannot make only selected HashMap entries immutable.

    You might be tempted to use Collections.unmodifiableMap utility to create immutable map, but keep in mind that the latter method creates solely immutable view wrapper over mutable map.

    If you really want to send immutable map over Camel consider using ImmutableMap from Google Guava [1]. Guava's ImmutableMaps are truly immutable.

    Map body = ImmutableMap.of("stringKey", "value", "dateKey", new Date());


    [1] https://code.google.com/p/guava-libraries