|
This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Integration 7.0.3! |
CloudEvents Support
Spring Integration provides support for the CloudEvents specification.
Add the following dependency to your project:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-cloudevents</artifactId>
<version>7.1.0-SNAPSHOT</version>
</dependency>
implementation "org.springframework.integration:spring-integration-cloudevents:7.1.0-SNAPSHOT"
ToCloudEventTransformer
Use the ToCloudEventTransformer to convert Spring Integration messages into CloudEvents-compliant messages.
This transformer supports the CloudEvents specification v1.0 and serializes CloudEvents if an EventFormat or eventFormatContentTypeExpression is specified.
When you specify an EventFormat or eventFormatContentTypeExpression, the transformer uses the EventFormat to generate the CloudEvent in the payload.
If neither is specified, the transformer writes the event data message payload as-is and adds attributes as well as extensions to the message headers.
The transformer supports defining attributes using expressions and identifies extensions in the message headers via patterns.
Attribute Expressions
Set the CloudEvents' attributes of id, source, type, dataSchema, and subject through SpEL expressions.
The transformer sets the time attribute to the time when it creates the CloudEvent instance.
|
The following table lists the attribute names and the values the default expressions return.
| Attribute Name | Default Value |
|---|---|
|
The id of the message. |
|
A prefix of "/spring/" followed by the appName, a period, and then the transformer’s bean name, e.g., |
|
"spring.message" |
|
The contentType of the message, defaults to |
|
The URI to the specified schema.
The default for |
|
Identify the subject of the event in the context of the event producer.
The default for |
|
The time the CloudEvent message is created. Set internally to the current time. Note that you cannot configure this value. |
Extension Patterns
Use the extensionPatterns constructor parameter (a vararg of strings) to specify pattern matching with wildcards (*).
The transformer includes message headers with keys matching any pattern as CloudEvent extensions.
Use a ! prefix to explicitly exclude headers through negation.
Note that the first matching pattern wins (whether positive or negative).
For example, configure the patterns "trace*", "span-id", "user-id" to:
- Include headers starting with trace (e.g., trace-id, traceparent) - Include headers with exact keys span-id and user-id
- Add all matching headers as extensions to the CloudEvent
To exclude specific headers, use negated patterns: "custom-*", "!custom-internal" includes all headers starting with custom- except custom-internal.
Configuration with DSL
Use the CloudEvents factory to add the ToCloudEventTransformer to flows using the Java DSL.
@Bean
public ToCloudEventTransformer cloudEventTransformer() {
return new ToCloudEventTransformer("trace*", "correlation-id");
}
@Bean
public IntegrationFlow cloudEventTransformFlow(ToCloudEventTransformer toCloudEventTransformer) {
return IntegrationFlows
.from("inputChannel")
.transform(CloudEvents.toCloudEventTransformer().get())
.channel("outputChannel")
.get();
}
CloudEvent Transformer Process
Understand the transformation process:
-
CloudEvent Building - Build the CloudEvent attributes.
-
Extension Extraction - Build the CloudEvent extensions using the array of extensionPatterns passed into the constructor.
-
Format Conversion - Apply the specified
EventFormator, if not set, handle the conversion via Binary Format Mode.
A basic transformation may have the following pattern:
// Input message with headers
Message<byte[]> inputMessage = MessageBuilder
.withPayload("Hello CloudEvents".getBytes(StandardCharsets.UTF_8))
.withHeader(MessageHeaders.CONTENT_TYPE, "text/plain")
.build();
ToCloudEventTransformer transformer = new ToCloudEventTransformer();
// Transform to CloudEvent
Object cloudEventMessage = transformer.transform(inputMessage);
EventFormats
The ToCloudEventTransformer uses formatting to serialize the CloudEvent into the message’s payload when the EventFormat is available, or uses Binary Format Mode otherwise.
Set the EventFormat in one of two ways:
-
Set the desired
EventFormat. -
Set the
eventFormatContentTypeExpressionwith an expression that resolves to a content type thatEventFormatProvidercan use to provide the requiredEventFormat. When theeventFormatContentTypeExpressionis set and theEventFormatProviderreturns null because it cannot find theEventFormatfor the content type, the transformer throws aMessageTransformationException. Examples of content types that theeventFormatContentTypeExpressioncan resolve to that are accepted by theEventFormatProviderare:-
application/cloudevents+json -
application/cloudevents+xml
-
If the EventFormat and the eventFormatContentTypeExpression are not set, the transformer adds cloud event attributes and extensions to the message headers with the cloud event prefix (default is ce-) and leaves the payload unchanged (Binary Format Mode).
To utilize a specific EventFormat, add the associated dependency.
For example, to add the XML EventFormat, add the following dependency: io.cloudevents:cloudevents-xml.
See the CloudEvents Java Reference Documentation for information on the event formats that are available.
Ensure messages to be transformed to CloudEvents have a payload of type byte[].
The transformer throws an IllegalArgumentException if the payload is not a byte array.
|
FromCloudEventTransformer
Use the FromCloudEventTransformer to convert CloudEvents into Spring Integration messages.
This transformer supports the CloudEvents specification v1.0 and processes CloudEvents from two payload types: CloudEvent objects or serialized CloudEvent byte arrays.
The transformer extracts CloudEvent data from the message payload and maps CloudEvent attributes along with CloudEvent extensions to message headers with a ce- prefix.
Supported Payload Types
The transformer accepts messages with the following payload types:
CloudEvent Object Type
When the message payload is a CloudEvent instance, the transformer:
-
Extracts the CloudEvent data and uses it as the message payload.
-
Maps CloudEvent attributes (
id,source,type,time,subject,datacontenttype,dataschema) to message headers with ace-prefix. -
Maps all CloudEvent extensions to message headers with the
ce-prefix. -
Preserves all original message headers unless a header key matches a
CloudEventattribute or extension, in which case the original value is overwritten.
Example:
String orderJson = ...
CloudEvent cloudEvent = CloudEventBuilder.v1()
.withId("event-123")
.withSource(URI.create("/myapp/orders"))
.withType("order.created")
.withData("application/json", orderJson.getBytes())
.withExtension("traceid", "trace-abc")
.build();
Message<CloudEvent> inputMessage = MessageBuilder
.withPayload(cloudEvent)
.build();
FromCloudEventTransformer transformer = new FromCloudEventTransformer();
Message<?> outputMessage = transformer.transform(inputMessage);
The outputMessage from the example above produces output similar to the following:
GenericMessage [
payload = byte[13],
headers = {
ce-source = /myapp/orders,
ce-datacontenttype = application/json,
ce-type = order.created,
ce-id = event-123,
ce-traceid = trace-abc,
id = 2df76f27-d139-424c-19b6-80b64e4a33b0,
contentType = application/json,
timestamp = 1770667476433
}
]
Serialized CloudEvent Type
When the message payload is a byte[] containing a serialized CloudEvent, the transformer:
-
Uses the
content-typeheader to resolve the appropriateEventFormatviaEventFormatProvider. -
Deserializes the payload to a
CloudEventobject using the resolved format. -
Follows the same steps enumerated in the CloudEvent Object Type section.
Information on supported content types is discussed in the EventFormats section.
FromCloudEventTransformer allows the user to set an EventFormat that will be used when the EventFormatProvider fails to find an EventFormat for the contentType header or if the message does not contain a contentType header.
If not set and an EventFormat is not found by the EventFormatProvider, a MessageTransformationException will be thrown.
|
Example:
byte[] serializedCloudEvent = """
{
"specversion": "1.0",
"id": "316b0cf3-0c4d-5858-6bd2-863a2042f442",
"source": "/spring/testapp.jsonTransformerWithExtensions",
"type": "spring.message",
"subject": "test.subject",
"datacontenttype": "text/plain",
"time": "2026-01-30T08:53:06.099486-05:00",
"traceid": "trace-123",
"data": "Hello, World!"
}
""";
Message<byte[]> inputMessage = MessageBuilder
.withPayload(serializedCloudEvent)
.setHeader(MessageHeaders.CONTENT_TYPE, "application/cloudevents+json")
.build();
FromCloudEventTransformer transformer = new FromCloudEventTransformer();
Message<?> outputMessage = transformer.transform(inputMessage);
The outputMessage from the example above produces output similar to the following:
GenericMessage [
payload = byte[13],
headers = {
ce-source = /spring/testapp.jsonTransformerWithExtensions,
ce-datacontenttype = text/plain,
ce-subject = test.subject,
ce-type = spring.message,
ce-id = 316b0cf3-0c4d-5858-6bd2-863a2042f442,
ce-traceid = trace-123,
ce-time = 2026-01-30T08:53:06.099486-05:00,
id = 463c0878-a9cb-7269-a503-b4224088cd42,
contentType = text/plain,
timestamp = 1770392214225
}
]
CloudEvent Attribute Mapping
The transformer maps CloudEvent attributes to message headers using the following CloudEventHeaders constants:
| CloudEvent Attribute | Message Header Key | Required |
|---|---|---|
|
|
Yes |
|
|
Yes |
|
|
Yes |
|
|
No |
|
|
No |
|
|
No |
|
|
No |
extensions |
|
No |
The contentType header in the output message is always set to the CloudEvent’s datacontenttype value.
|
Configuration with DSL
Use the CloudEvents factory to add the FromCloudEventTransformer to flows using the Java DSL.
@Bean
public FromCloudEventTransformer fromCloudEventTransformer() {
return new FromCloudEventTransformer();
}
@Bean
public IntegrationFlow fromCloudEventFlow(FromCloudEventTransformer fromCloudEventTransformer) {
return IntegrationFlows
.from("cloudEventInputChannel")
.transform(CloudEvents.fromCloudEventTransformer())
.channel("messageOutputChannel")
.get();
}