-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add Cloud Events support to Spring Integration #10448
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
cppwfs
wants to merge
6
commits into
spring-projects:main
Choose a base branch
from
cppwfs:SI-cloud-events
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
ac74115
Add Cloud Events support to Spring Integration
cppwfs fdcd99b
Refactor CloudEvents package structure
cppwfs 19b057a
Consolidate CloudEvent transformer configuration
cppwfs 93a82b7
Simplify CloudEvent formatting with SDK strategies
cppwfs 075b280
Refactor CloudEvent extensions and update javadocs
cppwfs d115df2
Enable CloudEvents to be sent with headers
cppwfs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
...n-cloudevents/src/main/java/org/springframework/integration/cloudevents/package-info.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
|
|
||
| @org.jspecify.annotations.NullMarked | ||
| package org.springframework.integration.cloudevents; |
76 changes: 76 additions & 0 deletions
76
...a/org/springframework/integration/cloudevents/transformer/CloudEventMessageConverter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| /* | ||
| * Copyright 2025-present the original author or authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * https://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.springframework.integration.cloudevents.transformer; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| import io.cloudevents.CloudEvent; | ||
| import io.cloudevents.core.CloudEventUtils; | ||
| import org.jspecify.annotations.Nullable; | ||
|
|
||
| import org.springframework.integration.transformer.MessageTransformationException; | ||
| import org.springframework.messaging.Message; | ||
| import org.springframework.messaging.MessageHeaders; | ||
| import org.springframework.messaging.converter.MessageConverter; | ||
|
|
||
| /** | ||
| * Convert Spring Integration {@link Message}s to CloudEvents. | ||
| * | ||
| * @author Glenn Renfro | ||
| * | ||
| * @since 7.0 | ||
| */ | ||
| class CloudEventMessageConverter implements MessageConverter { | ||
|
|
||
| private final String cloudEventPrefix; | ||
|
|
||
| private final String specVersionKey; | ||
|
|
||
| private final String dataContentTypeKey; | ||
|
|
||
| /** | ||
| * Construct a CloudEventMessageConverter with the specified configuration. | ||
| * @param cloudEventPrefix the prefix for CloudEvent headers in binary content mode | ||
| * @param specVersionKey the header name for the specification version | ||
| * @param dataContentTypeKey the header name for the data content type | ||
| */ | ||
| CloudEventMessageConverter(String cloudEventPrefix, String specVersionKey, String dataContentTypeKey) { | ||
| this.cloudEventPrefix = cloudEventPrefix; | ||
| this.specVersionKey = specVersionKey; | ||
| this.dataContentTypeKey = dataContentTypeKey; | ||
| } | ||
|
|
||
| /** | ||
| * This converter only supports CloudEvent to Message conversion. | ||
| * @throws UnsupportedOperationException always, as this operation is not supported | ||
| */ | ||
| @Override | ||
| public @Nullable Object fromMessage(Message<?> message, Class<?> targetClass) { | ||
| throw new UnsupportedOperationException("CloudEventMessageConverter does not support fromMessage method"); | ||
| } | ||
|
|
||
| @Override | ||
| public Message<?> toMessage(Object payload, @Nullable MessageHeaders headers) { | ||
| if (payload instanceof CloudEvent event) { | ||
| return CloudEventUtils.toReader(event).read(new MessageBuilderMessageWriter(this.cloudEventPrefix, | ||
| this.specVersionKey, this.dataContentTypeKey, Objects.requireNonNull(headers))); | ||
| } | ||
| throw new MessageTransformationException("Unsupported payload type. Should be CloudEvent but was: " + | ||
| payload.getClass()); | ||
| } | ||
|
|
||
| } |
137 changes: 137 additions & 0 deletions
137
.../org/springframework/integration/cloudevents/transformer/MessageBuilderMessageWriter.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| /* | ||
| * Copyright 2025-present the original author or authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * https://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.springframework.integration.cloudevents.transformer; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| import io.cloudevents.CloudEventData; | ||
| import io.cloudevents.SpecVersion; | ||
| import io.cloudevents.core.format.EventFormat; | ||
| import io.cloudevents.core.message.MessageWriter; | ||
| import io.cloudevents.rw.CloudEventContextWriter; | ||
| import io.cloudevents.rw.CloudEventRWException; | ||
| import io.cloudevents.rw.CloudEventWriter; | ||
|
|
||
| import org.springframework.integration.support.MessageBuilder; | ||
| import org.springframework.messaging.Message; | ||
|
|
||
| /** | ||
| * Adapt CloudEvents to Spring Integration {@link Message}s using the CloudEvents SDK | ||
| * {@link MessageWriter} abstraction. | ||
| * Write CloudEvent attributes as message headers with a configurable prefix for | ||
| * binary content mode serialization. Used internally by {@link CloudEventMessageConverter} | ||
| * to convert CloudEvent objects into Spring Integration messages. | ||
| * | ||
| * @author Glenn Renfro | ||
| * | ||
| * @since 7.0 | ||
| * | ||
| * @see CloudEventMessageConverter | ||
| */ | ||
| class MessageBuilderMessageWriter | ||
| implements CloudEventWriter<Message<byte[]>>, MessageWriter<MessageBuilderMessageWriter, Message<byte[]>> { | ||
|
|
||
| private final String cloudEventPrefix; | ||
|
|
||
| private final String specVersionKey; | ||
|
|
||
| private final String dataContentTypeKey; | ||
|
|
||
| private final Map<String, Object> headers = new HashMap<>(); | ||
|
|
||
| /** | ||
| * Construct a MessageBuilderMessageWriter with the specified configuration. | ||
| * @param cloudEventPrefix the prefix to prepend to CloudEvent attribute names in message headers | ||
| * @param specVersionKey the header name for the CloudEvent specification version | ||
| * @param dataContentTypeKey the header name for the data content type | ||
| * @param headers the base message headers to include in the output message | ||
| */ | ||
| MessageBuilderMessageWriter(String cloudEventPrefix, String specVersionKey, String dataContentTypeKey, Map<String, Object> headers) { | ||
| this.headers.putAll(headers); | ||
| this.cloudEventPrefix = cloudEventPrefix; | ||
| this.specVersionKey = specVersionKey; | ||
| this.dataContentTypeKey = dataContentTypeKey; | ||
| } | ||
|
|
||
| /** | ||
| * Set the event in structured content mode. | ||
| * Create a message with the serialized CloudEvent as the payload and set the | ||
| * data content type header to the format's serialized content type. | ||
| * @param format the event format used to serialize the CloudEvent | ||
| * @param value the serialized CloudEvent bytes | ||
| * @return the Spring Integration message containing the serialized CloudEvent | ||
| * @throws CloudEventRWException if an error occurs during message creation | ||
| */ | ||
| @Override | ||
| public Message<byte[]> setEvent(EventFormat format, byte[] value) throws CloudEventRWException { | ||
| this.headers.put(this.dataContentTypeKey, format.serializedContentType()); | ||
| return MessageBuilder.withPayload(value).copyHeaders(this.headers).build(); | ||
| } | ||
|
|
||
| /** | ||
| * Complete the message creation with CloudEvent data. | ||
| * Create a message with the CloudEvent data as the payload. CloudEvent attributes | ||
| * are already set as headers via {@link #withContextAttribute(String, String)}. | ||
| * @param value the CloudEvent data to use as the message payload | ||
| * @return the Spring Integration message with CloudEvent data and attributes | ||
| * @throws CloudEventRWException if an error occurs during message creation | ||
| */ | ||
| @Override | ||
| public Message<byte[]> end(CloudEventData value) throws CloudEventRWException { | ||
| return MessageBuilder.withPayload(value.toBytes()).copyHeaders(this.headers).build(); | ||
| } | ||
|
|
||
| /** | ||
| * Complete the message creation without CloudEvent data. | ||
| * Create a message with an empty payload when the CloudEvent contains no data. | ||
| * CloudEvent attributes are set as headers via {@link #withContextAttribute(String, String)}. | ||
| * @return the Spring Integration message with an empty payload and CloudEvent attributes as headers | ||
| */ | ||
| @Override | ||
| public Message<byte[]> end() { | ||
| return MessageBuilder.withPayload(new byte[0]).copyHeaders(this.headers).build(); | ||
| } | ||
|
|
||
| /** | ||
| * Add a CloudEvent context attribute to the message headers. | ||
| * Map the CloudEvent attribute to a message header by prepending the configured prefix | ||
| * to the attribute name (e.g., "id" becomes "ce-id" with default prefix). | ||
| * @param name the CloudEvent attribute name | ||
| * @param value the CloudEvent attribute value | ||
| * @return this writer for method chaining | ||
| * @throws CloudEventRWException if an error occurs while setting the attribute | ||
| */ | ||
| @Override | ||
| public CloudEventContextWriter withContextAttribute(String name, String value) throws CloudEventRWException { | ||
| this.headers.put(this.cloudEventPrefix + name, value); | ||
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Initialize the writer with the CloudEvent specification version. | ||
| * Set the specification version as a message header using the configured version key. | ||
| * @param version the CloudEvent specification version | ||
| * @return this writer for method chaining | ||
| */ | ||
| @Override | ||
| public MessageBuilderMessageWriter create(SpecVersion version) { | ||
| this.headers.put(this.specVersionKey, version.toString()); | ||
| return this; | ||
| } | ||
|
|
||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.