-
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
base: main
Are you sure you want to change the base?
Conversation
03d1f51 to
02a1329
Compare
artembilan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some at a glance review.
Thank you!
...src/main/java/org/springframework/integration/cloudevents/v1/CloudEventMessageConverter.java
Outdated
Show resolved
Hide resolved
...src/main/java/org/springframework/integration/cloudevents/v1/CloudEventMessageConverter.java
Outdated
Show resolved
Hide resolved
...src/main/java/org/springframework/integration/cloudevents/v1/CloudEventMessageConverter.java
Outdated
Show resolved
Hide resolved
...g/springframework/integration/cloudevents/v1/transformer/CloudEventMessageConverterTest.java
Outdated
Show resolved
Hide resolved
artembilan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for a lengthy review and some doubts I've expressed.
I addition, what are your thoughts about content of this package in Spring Cloud Function: https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/cloudevent ?
I mean transformer does the trick indeed, but only from an integration flow context.
How about the way to be able to construct CloudEvent programmatically?
Or just existing SDK API is enough to deal with?
...ts/src/main/java/org/springframework/integration/cloudevents/CloudEventMessageConverter.java
Outdated
Show resolved
Hide resolved
...ation/cloudevents/transformer/strategies/cloudeventconverter/CloudEventMessageConverter.java
Outdated
Show resolved
Hide resolved
...ation/cloudevents/transformer/strategies/cloudeventconverter/MessageBinaryMessageReader.java
Outdated
Show resolved
Hide resolved
...pringframework/integration/cloudevents/v1/transformer/ToCloudEventTransformerExtensions.java
Outdated
Show resolved
Hide resolved
...a/org/springframework/integration/cloudevents/v1/transformer/utils/HeaderPatternMatcher.java
Outdated
Show resolved
Hide resolved
...java/org/springframework/integration/cloudevents/v1/transformer/ToCloudEventTransformer.java
Outdated
Show resolved
Hide resolved
...java/org/springframework/integration/cloudevents/v1/transformer/ToCloudEventTransformer.java
Outdated
Show resolved
Hide resolved
.../main/java/org/springframework/integration/cloudevents/transformer/CloudEventProperties.java
Outdated
Show resolved
Hide resolved
...loudevents/src/main/java/org/springframework/integration/cloudevents/CloudEventsHeaders.java
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
cabc5e5 to
d14c5f8
Compare
...ts/src/main/java/org/springframework/integration/cloudevents/CloudEventMessageConverter.java
Outdated
Show resolved
Hide resolved
...loudevents/src/main/java/org/springframework/integration/cloudevents/CloudEventsHeaders.java
Outdated
Show resolved
Hide resolved
...ts/src/main/java/org/springframework/integration/cloudevents/MessageBinaryMessageReader.java
Outdated
Show resolved
Hide resolved
...ts/src/main/java/org/springframework/integration/cloudevents/MessageBinaryMessageReader.java
Outdated
Show resolved
Hide resolved
...s/src/main/java/org/springframework/integration/cloudevents/MessageBuilderMessageWriter.java
Outdated
Show resolved
Hide resolved
...s/src/main/java/org/springframework/integration/cloudevents/MessageBuilderMessageWriter.java
Outdated
Show resolved
Hide resolved
...g/springframework/integration/cloudevents/transformer/ToCloudEventTransformerExtensions.java
Outdated
Show resolved
Hide resolved
...g/springframework/integration/cloudevents/transformer/ToCloudEventTransformerExtensions.java
Outdated
Show resolved
Hide resolved
.../java/org/springframework/integration/cloudevents/transformer/strategies/FormatStrategy.java
Outdated
Show resolved
Hide resolved
...t/java/org/springframework/integration/cloudevents/transformer/CloudEventPropertiesTest.java
Outdated
Show resolved
Hide resolved
|
For now hold off on a review. I'm writing up some questions for some guidance on some of the issues you raised in the last 2 reviews. |
.../java/org/springframework/integration/cloudevents/transformer/strategies/FormatStrategy.java
Outdated
Show resolved
Hide resolved
...s/src/main/java/org/springframework/integration/cloudevents/MessageBuilderMessageWriter.java
Outdated
Show resolved
Hide resolved
...loudevents/src/main/java/org/springframework/integration/cloudevents/CloudEventsHeaders.java
Outdated
Show resolved
Hide resolved
d14c5f8 to
d8989f9
Compare
d8989f9 to
be0fa17
Compare
...in/java/org/springframework/integration/cloudevents/transformer/ToCloudEventTransformer.java
Outdated
Show resolved
Hide resolved
...in/java/org/springframework/integration/cloudevents/transformer/ToCloudEventTransformer.java
Outdated
Show resolved
Hide resolved
...in/java/org/springframework/integration/cloudevents/transformer/ToCloudEventTransformer.java
Outdated
Show resolved
Hide resolved
...va/org/springframework/integration/cloudevents/transformer/ToCloudEventTransformerTests.java
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
src/reference/antora/modules/ROOT/pages/cloudevents-transform.adoc
Outdated
Show resolved
Hide resolved
...va/org/springframework/integration/cloudevents/transformer/ToCloudEventTransformerTests.java
Outdated
Show resolved
Hide resolved
...va/org/springframework/integration/cloudevents/transformer/ToCloudEventTransformerTests.java
Outdated
Show resolved
Hide resolved
be0fa17 to
d115df2
Compare
Introduces Cloud Events v1.0 specification support including message converters, transformers, and utilities. Key components added: - CloudEventMessageConverter for message format conversion - ToCloudEventTransformer for transforming messages to Cloud Events - MessageBinaryMessageReader/Writer for binary format handling - CloudEventProperties for configuration management - Header pattern matching utilities for flexible event mapping - Add reference docs and what's-new paragraph
Remove v1 subpackage and flatten the CloudEvents package hierarchy. Introduce strategy pattern for format conversion to replace enum-based approach, improving extensibility and reduce dependencies. Key changes: - Move all classes from cloudevents.v1 to cloudevents base package - Remove optional format dependencies (JSON, XML, Avro) from build - Replace `ConversionType` enum with `FormatStrategy` interface - Add `CloudEventMessageFormatStrategy` as default implementation - Inline `HeaderPatternMatcher` logic into `ToCloudEventTransformerExtensions` - Add `@NullMarked` package annotations and `@Nullable` throughout - Document `targetClass` parameter behavior in `CloudEventMessageConverter` - Split transformer tests for better organization and coverage - Update component type identifier to "ce:to-cloudevents-transformer" - Remove unnecessary docs from package-info
- Simplify the CloudEvent transformer by consolidating configuration directly into ToCloudEventTransformer class rather than using separate configuration objects - Remove CloudEventProperties and ToCloudEventTransformerExtensions classes to reduce abstraction layers and improve maintainability - Make MessageBinaryMessageReader package-private and convert CloudEventMessageConverter methods to static where possible - Move extension filtering logic into a private inner class within the transformer - Remove CloudEventsHeaders class and CE_PREFIX constant as the prefix is no longer used as a configurable value
Replace custom CloudEvent converter infrastructure with direct CloudEvents SDK format implementations. Key changes: - Replace `FormatStrategy` pattern-based approach with direct `EventFormatProvider` integration from CloudEvents SDK - Remove custom converter classes (`CloudEventMessageConverter`, `MessageBinaryMessageReader`, `MessageBuilderMessageWriter`) - Simplify transformer to use Expression-based configuration for all CloudEvent attributes (id, source, type, dataSchema, subject) - Add validation for required CloudEvent attributes with clear error messages when expressions evaluate to null or empty values - Update documentation to reflect Expression-based API and byte[] payload requirement - Consolidate tests by removing coverage for deleted converter infrastructure
The previous extension extraction mechanism using `Expression` arrays and a separate `ExtensionsExtractor` interface was overly complex for the simple use case of pattern matching header names. This change simplifies the API by: - Removing the `ExtensionsExtractor` interface and implementations - Replacing `Expression`-based extension configuration with simple String pattern matching in the transformer constructor - Updating all javadocs to use imperative voice per Spring conventions (e.g., "Converts messages" instead of "A transformer that converts messages") - Making default value descriptions more concise (e.g., "Defaults to null" instead of "Default Expression evaluates to a null") - Add extensionPattern match logic
Enable CloudEvents to be sent with headers instead of requiring structured format serialization. This provides flexibility when integrating with systems that don't support CloudEvents structured formats. Introduce `CloudEventMessageConverter` to handle CloudEvent to Message conversion, utilizing the CloudEvents SDK's `MessageWriter` abstraction. Add `noFormat` configuration option to `ToCloudEventsTransformer`. When enabled and no `EventFormat` is available for the content type, CloudEvent attributes are written to message headers with configurable prefix (defaults to "ce-"). Add `cloudEventPrefix` property to customize the header prefix when `noFormat` is set to true, supporting different integration scenarios. Add test coverage for binary content mode including extension handling, custom prefixes, and validation that original headers are preserved alongside CloudEvent headers.
Update javadoc comments in `CloudEventMessageConverter` and `ToCloudEventsTransformer` to improve clarity and readability. Enhance the CloudEvents reference documentation to better explain how extensions are populated using pattern matching instead of SpEL expressions. Changes include: - Clarify `CloudEventMessageConverter` class-level javadoc - Improve `isNoFormat()` and `setNoFormat()` method documentation - Update reference docs to reflect extension patterns approach - Fix minor formatting issues (double spaces)
d115df2 to
23379aa
Compare
artembilan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for lengthy review: too many concerns.
Please, consider to rebase your branch to the latest main.
And take into account that it is already 7.1.
Thanks
| testImplementation "io.cloudevents:cloudevents-json-jackson:$cloudEventsVersion" | ||
|
|
||
| testImplementation("io.cloudevents:cloudevents-avro-compact:$cloudEventsVersion") { | ||
| exclude group: 'org.apache.avro', module: 'avro' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we care what kind of Avro comes transitively from Cloud Events since it is a test dependency?
On the other hand: do we really have tests with Avro to worry ab out this dependency at all?
Similar question for all other formats: if we don't have respective tests, then we don't need that dependency.
We might need to have just one for Jackson to be sure that our format-related logic is correct.
The rest, out-of--use, deps should be dropped altogether.
| @Override | ||
| public Message<?> toMessage(Object payload, @Nullable MessageHeaders headers) { | ||
| if (payload instanceof CloudEvent event) { | ||
| return CloudEventUtils.toReader(event).read(new MessageBuilderMessageWriter(this.cloudEventPrefix, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this class is internal and has a logic only delegate to the MessageBuilderMessageWriter, I wonder if we need this class at all and really just use that MessageBuilderMessageWriter in the transformer.
| * @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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need custom specVersionKey and dataContentTypeKey?
Why would one use something which is not a standard and may not be compatible with consumers of the event?
| @SuppressWarnings("NullAway.Init") | ||
| private EvaluationContext evaluationContext; | ||
|
|
||
| private final EventFormatProvider eventFormatProvider = EventFormatProvider.getInstance(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, fix properties order.
The final have to go firsts. Right, after static, but still not here and not in between.
| * to the CloudEvent | ||
| */ | ||
| public ToCloudEventsTransformer(String ... extensionPatterns) { | ||
| this.extensionPatterns = extensionPatterns; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You cannot do this. External object mutation problem.
So, we have to copy an input array to the output one.
Also: why those ellipses are not stick to the String type?
| The transformer follows the process below: | ||
|
|
||
| 1. **CloudEvent Building**: Build CloudEvent attributes | ||
| 2. **Extension Extraction**: Build the CloudEvent extensions using the array of extensionExpressions passed into the constructor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is no extensionExpressions any more.
Please, revise this text.
| ===== EventFormats | ||
|
|
||
| The `ToCloudEventsTransformer` uses `EventFormat` s to serialize the CloudEvent into the message's payload. | ||
| The `EventFormat` s used by the `ToCloudEventsTransformer` are obtained from the classpath of the project. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot assume that formats are always just by classpath scanning.
I think we can add some manually at runtime.
Either way, it is out of our scope to claim how EventFormat works.
|
|
||
| [[jsonformat]] | ||
| ====== JsonFormat | ||
| The following dependency can be used to include this `JsonFormat` in your project. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No sticking to the title, please.
And that is, of course, if we move on with "may sub-titles" approach 😄
| ---- | ||
| compile "io.cloudevents:cloudevents-json-jackson:$cloudEventsVersion" | ||
| ---- | ||
| ====== |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that we need to be so fine-grained.
Just mention in the text that we need an io.cloudevents:cloudevents-json-jackson dependency and that's it. It should be obvious from there that it depends on your build system.
Plus you made a mistake in the Maven sample.
Has to be ${cloudEventsVersion}, not a Gradle style 😉
| This is a breaking change, and direct references to components of the JCIFS library will need to be updated. | ||
| See xref:smb.adoc[] for more information. | ||
|
|
||
| [[x7.0-cloudevents]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would have to be fixed for 7.1.
Introduces Cloud Events v1.0 specification support including message converters, transformers, and utilities.
Key components added: