diff --git a/spring-integration-reference/src/core-api.xml b/spring-integration-reference/src/core-api.xml
index a3c557f755..6d795a8f38 100644
--- a/spring-integration-reference/src/core-api.xml
+++ b/spring-integration-reference/src/core-api.xml
@@ -7,82 +7,141 @@
Message
The Spring Integration Message is a generic container for data. Any object can
- be provided as the payload, and each Message also includes a header containing
+ be provided as the payload, and each Message also includes headers containing
user-extensible properties as key-value pairs. Here is the definition of the
Message interface:
public interface Message<T> {
- Object getId();
- MessageHeader getHeader();
+
T getPayload();
- void setPayload(T payload);
- boolean isExpired();
- void copyHeader(MessageHeader header, boolean overwriteExistingValues);
+
+ MessageHeaders getHeaders();
+
}
- And the header provides the following properties:
+ And the following headers are pre-defined:
+
+ Many source and target adapter implementations will also provide and/or expect certain headers, and additional
+ user-defined headers can also be configured.
+
The base implementation of the Message interface is
- GenericMessage<T>, and it provides three constructors:
- new GenericMessage<T>(Object id, T payload);
-new GenericMessage<T>(T payload);
-new GenericMessage<T>(T payload, MessageHeader headerToCopy)
- When no id is provided, a random unique id will be generated. The constructor that accepts a
- MessageHeader will copy properties and attributes as well as the
- 'returnAddress', 'sequenceNumber', and 'sequenceSize' properties from the provided header.
- There are also two convenient subclasses available currently:
- StringMessage and ErrorMessage. The latter accepts any
+ GenericMessage<T>, and it provides two constructors:
+ new GenericMessage<T>(T payload);
+new GenericMessage<T>(T payload, Map<String, Object> headers)
+ When a Message is created, a random unique id will be generated. The constructor that accepts a Map of headers
+ will copy the provided headers to the newly created Message. There are also two convenient subclasses available
+ currently: StringMessage and ErrorMessage. The latter accepts any
Throwable object as its payload.
+
+ You may notice that the Message interface defines retrieval methods for its payload and headers but no setters.
+ This is fully intentional so that each Message is unmodifiable after creation. Therefore, when a Message
+ instance is sent to multiple consumers (e.g. through a Publish Subscribe Channel), if one of those consumers
+ needs to send a reply with a different payload type, it will need to create a new Message. As a result, the
+ other consumers are not affected by those changes. Keep in mind, that multiple consumers may access the same
+ payload instance or header value, and whether such an instance is itself immutable is a decision left to the
+ developer. In other words, the contract for Messages is similar to that of an
+ unmodifiable Collection, and the MessageHeaders' map further exemplifies that; even though
+ the MessageHeaders class implements java.util.Map, any attempt to invoke a
+ put operation on the MessageHeaders will result in an
+ UnsupportedOperationException.
+
+
+ Rather than requiring the creation and population of a Map to pass into the GenericMessage constructor, Spring
+ Integration does provide a far more convenient way to construct Messages: MessageBuilder.
+ The MessageBuilder provides two factory methods for creating Messages from either an existing Message or a
+ payload Object. When building from an existing Message, the headers and payload of that
+ Message will be copied to the new Message:
+ Message<String> message1 = MessageBuilder.fromPayload("test")
+ .setHeader("foo", "bar")
+ .build();
+
+Message<String> message2 = MessageBuilder.fromMessage(message1).build();
+
+assertEquals("test", message2.getPayload());
+assertEquals("bar", message2.getHeaders().get("foo"));
+
+
+ If you need to create a Message with a new payload but still want to copy the
+ headers from an existing Message, you can use one of the 'copy' methods.
+ Message<String> message3 = MessageBuilder.fromPayload("test3")
+ .copyHeaders(message1.getHeaders())
+ .build();
+
+Message<String> message4 = MessageBuilder.fromPayload("test4")
+ .setHeader("foo", 123)
+ .copyHeadersIfAbsent(message1.getHeaders())
+ .build();
+
+assertEquals("bar", message3.getHeaders().get("foo"));
+assertEquals(123, message4.getHeaders().get("foo"));
+ Notice that the copyHeadersIfAbsent does not overwrite existing values. Also, in the
+ second example above, you can see how to set any user-defined header with setHeader.
+ Finally, there are set methods available for the predefined headers as well as a non-destructive method for
+ setting any header (MessageHeaders also defines constants for the pre-defined header names).
+ Message<Integer> importantMessage = MessageBuilder.fromPayload(99)
+ .setPriority(MessagePriority.HIGHEST)
+ .build();
+
+assertEquals(MessagePriority.HIGHEST, importantMessage.getHeaders().getPriority());
+
+Message<Integer> anotherMessage = MessageBuilder.fromMessage(importantMessage)
+ .setHeaderIfAbsent(MessageHeaders.PRIORITY, MessagePriority.LOW)
+ .build();
+
+assertEquals(MessagePriority.HIGHEST, anotherMessage.getHeaders().getPriority());
+
+
The MessagePriority is only considered when using a PriorityChannel
(as described in the next section). It is defined as an enum with five possible values:
@@ -100,8 +159,7 @@ new GenericMessage<T>(T payload, MessageHeader headerToCopy)does require access to information about the Message, such
- metadata can typically be stored to and retrieved from the metadata in the header (the 'properties' and
- 'attributes').
+ metadata can typically be stored to and retrieved from the metadata in the Message Headers.