From 4ebeab0e0ff8d0c507c47b32dd7ec2da95dc87cb Mon Sep 17 00:00:00 2001 From: skepticoitusInteruptus <97033958+skepticoitusInteruptus@users.noreply.github.com> Date: Fri, 21 Apr 2023 08:41:10 +0000 Subject: [PATCH] Refactor to Facilitate Decoupling from Concrete Implementations of EventFormat (#539) - Introduce ContentType enum - Resolve formats by using the ContentType enum Signed-off-by: Randi Sheaffer-Klass <97033958+skepticoitusInteruptus@users.noreply.github.com> --- .../cloudevents/core/format/ContentType.java | 68 +++++++++++++++++++ .../core/provider/EventFormatProvider.java | 11 +++ docs/json-jackson.md | 4 +- docs/protobuf.md | 4 +- docs/xml.md | 4 +- .../io/cloudevents/jackson/JsonFormat.java | 1 + .../cloudevents/jackson/JsonFormatTest.java | 9 ++- .../cloudevents/protobuf/ProtobufFormat.java | 1 + .../java/io/cloudevents/xml/XMLFormat.java | 1 + 9 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 core/src/main/java/io/cloudevents/core/format/ContentType.java diff --git a/core/src/main/java/io/cloudevents/core/format/ContentType.java b/core/src/main/java/io/cloudevents/core/format/ContentType.java new file mode 100644 index 000000000..1d8656393 --- /dev/null +++ b/core/src/main/java/io/cloudevents/core/format/ContentType.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018-Present The CloudEvents 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 + *

+ * http://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 io.cloudevents.core.format; + +import io.cloudevents.CloudEvent; +import io.cloudevents.CloudEventData; +import io.cloudevents.rw.CloudEventDataMapper; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Collections; +import java.util.Set; + +/** + *

A construct that aggregates a two-part identifier of file formats and format contents transmitted on the Internet. + * + *

The two parts of a {@code ContentType} are its type and a subtype; separated by a forward slash ({@code /}). + * + *

The constants enumerated by {@code ContentType} correspond only to the specialized formats supported by the Java™ SDK for CloudEvents. + * + * @see io.cloudevents.core.format.EventFormat + */ +@ParametersAreNonnullByDefault +public enum ContentType { + + /** + * Content type associated with the JSON event format + */ + JSON("application/cloudevents+json"), + /** + * The content type for transports sending cloudevents in the protocol buffer format. + */ + PROTO("application/cloudevents+protobuf"), + /** + * The content type for transports sending cloudevents in XML format. + */ + XML("application/cloudevents+xml"); + + private String value; + + private ContentType(String value) { this.value = value; } + + /** + * Return a string consisting of the slash-delimited ({@code /}) two-part identifier for this {@code enum} constant. + */ + public String value() { return value; } + + /** + * Return a string consisting of the slash-delimited ({@code /}) two-part identifier for this {@code enum} constant. + */ + @Override + public String toString() { return value(); } + +} diff --git a/core/src/main/java/io/cloudevents/core/provider/EventFormatProvider.java b/core/src/main/java/io/cloudevents/core/provider/EventFormatProvider.java index 96f3ad678..d961d2f85 100644 --- a/core/src/main/java/io/cloudevents/core/provider/EventFormatProvider.java +++ b/core/src/main/java/io/cloudevents/core/provider/EventFormatProvider.java @@ -25,6 +25,7 @@ import javax.annotation.ParametersAreNonnullByDefault; +import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventFormat; import io.cloudevents.lang.Nullable; @@ -98,4 +99,14 @@ public EventFormat resolveFormat(String contentType) { return this.formats.get(contentType); } + /** + * Resolve an event format starting from the content type. + * + * @param contentType the content type to resolve the event format + * @return null if no format was found for the provided content type + */ + @Nullable + public EventFormat resolveFormat(ContentType contentType) { + return this.formats.get(contentType.value()); + } } diff --git a/docs/json-jackson.md b/docs/json-jackson.md index 6bb2a7c6a..823436f02 100644 --- a/docs/json-jackson.md +++ b/docs/json-jackson.md @@ -28,9 +28,9 @@ adding the dependency to your project: ```java import io.cloudevents.CloudEvent; +import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventFormatProvider; import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.jackson.JsonFormat; CloudEvent event = CloudEventBuilder.v1() .withId("hello") @@ -40,7 +40,7 @@ CloudEvent event = CloudEventBuilder.v1() byte[]serialized = EventFormatProvider .getInstance() - .resolveFormat(JsonFormat.CONTENT_TYPE) + .resolveFormat(ContentType.JSON) .serialize(event); ``` diff --git a/docs/protobuf.md b/docs/protobuf.md index d67a0d708..6a49ec86b 100644 --- a/docs/protobuf.md +++ b/docs/protobuf.md @@ -30,9 +30,9 @@ No further configuration is required is use the module. ```java import io.cloudevents.CloudEvent; +import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventFormatProvider; import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.protobuf.ProtobufFormat; CloudEvent event = CloudEventBuilder.v1() .withId("hello") @@ -42,7 +42,7 @@ CloudEvent event = CloudEventBuilder.v1() byte[]serialized = EventFormatProvider .getInstance() - .resolveFormat(ProtobufFormat.CONTENT_TYPE) + .resolveFormat(ContentType.PROTO) .serialize(event); ``` diff --git a/docs/xml.md b/docs/xml.md index 6d0640157..8e365ac1f 100644 --- a/docs/xml.md +++ b/docs/xml.md @@ -29,9 +29,9 @@ adding the dependency to your project: ```java import io.cloudevents.CloudEvent; +import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventFormatProvider; import io.cloudevents.core.builder.CloudEventBuilder; -import io.cloudevents.xml.XMLFormat; CloudEvent event = CloudEventBuilder.v1() .withId("hello") @@ -41,7 +41,7 @@ CloudEvent event = CloudEventBuilder.v1() byte[] serialized = EventFormatProvider .getInstance() - .resolveFormat(XMLFormat.CONTENT_TYPE) + .resolveFormat(ContentType.XML) .serialize(event); ``` diff --git a/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java b/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java index 542405894..d73edbdf9 100644 --- a/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java +++ b/formats/json-jackson/src/main/java/io/cloudevents/jackson/JsonFormat.java @@ -22,6 +22,7 @@ import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventDeserializationException; import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.format.EventSerializationException; diff --git a/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java b/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java index f82d25926..59c2d70c0 100644 --- a/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java +++ b/formats/json-jackson/src/test/java/io/cloudevents/jackson/JsonFormatTest.java @@ -24,6 +24,7 @@ import io.cloudevents.CloudEvent; import io.cloudevents.SpecVersion; import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventDeserializationException; import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.rw.CloudEventRWException; @@ -40,6 +41,7 @@ import java.util.Objects; import java.util.stream.Stream; +import static io.cloudevents.core.format.ContentType.*; import static io.cloudevents.core.test.Data.*; import static org.assertj.core.api.Assertions.*; @@ -185,7 +187,10 @@ static Stream jsonContentTypes() { //https://www.rfc-editor.org/rfc/rfc2045#section-5.1 // any us-ascii char can be part of parameters (except CTRLs and tspecials) Arguments.of("text/json; char-set = $!#$%&'*+.^_`|"), - Arguments.of((Object) null) + Arguments.of((Object) null), + Arguments.of(JSON + ""), + Arguments.of(JSON.value()), + Arguments.of(JSON.toString()) ); } @@ -307,7 +312,7 @@ public static Stream badJsonContent() { } private JsonFormat getFormat() { - return (JsonFormat) EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE); + return (JsonFormat) EventFormatProvider.getInstance().resolveFormat(JSON); } private static byte[] loadFile(String input) { diff --git a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtobufFormat.java b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtobufFormat.java index 0d3b65d4e..170d92f20 100644 --- a/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtobufFormat.java +++ b/formats/protobuf/src/main/java/io/cloudevents/protobuf/ProtobufFormat.java @@ -20,6 +20,7 @@ import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventDeserializationException; import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.format.EventSerializationException; diff --git a/formats/xml/src/main/java/io/cloudevents/xml/XMLFormat.java b/formats/xml/src/main/java/io/cloudevents/xml/XMLFormat.java index 996f07cf3..d0e4c0bc7 100644 --- a/formats/xml/src/main/java/io/cloudevents/xml/XMLFormat.java +++ b/formats/xml/src/main/java/io/cloudevents/xml/XMLFormat.java @@ -19,6 +19,7 @@ import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.core.format.ContentType; import io.cloudevents.core.format.EventDeserializationException; import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.format.EventSerializationException;