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: - Properties of the MessageHeader + Pre-defined Message Headers - Property Name - Property Type + Header Name + Header Type - timestamp - java.util.Date - - - expiration - java.util.Date - - - correlationId + ID java.lang.Object - returnAddress - java.lang.Object (can be a String or MessageChannel) + TIMESTAMP + java.lang.Long - sequenceNumber - int + EXPIRATION_DATE + java.util.Date - sequenceSize - int + CORRELATION_ID + java.lang.Object - priority + NEXT_TARGET + java.lang.Object (can be a String or MessageTarget) + + + RETURN_ADDRESS + java.lang.Object (can be a String or MessageTarget) + + + SEQUENCE_NUMBER + java.lang.Integer + + + SEQUENCE_SIZE + java.lang.Integer + + + PRIORITY MessagePriority (an enum) - - properties - java.util.Properties - - - attributes - Map<String,Object> -
+ + 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.