Javadoc'ed + Cleanup of the api module (#267)
* Javadoc'ed more and more the api module Cleanup the CloudEventRWException More tests on the API module Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Use parseTime Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Better docs on the Extensions Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
This commit is contained in:
parent
62fe155604
commit
c1ff628511
|
@ -19,11 +19,17 @@ package io.cloudevents;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that defines a wrapper for CloudEvent data.
|
* Interface that defines a wrapper for CloudEvent data.
|
||||||
|
* <p>
|
||||||
|
* This interface can be overridden to include any type of data inside a {@link CloudEvent}, given it has a method to convert back to bytes.
|
||||||
*/
|
*/
|
||||||
public interface CloudEventData {
|
public interface CloudEventData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return this CloudEventData, represented as bytes. Note: this operation may be expensive, depending on the internal representation of data
|
* Returns the bytes representation of this data instance.
|
||||||
|
* <p>
|
||||||
|
* Note: depending on the implementation, this operation may be expensive.
|
||||||
|
*
|
||||||
|
* @return this data, represented as bytes.
|
||||||
*/
|
*/
|
||||||
byte[] toBytes();
|
byte[] toBytes();
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The event extensions
|
* The event extensions.
|
||||||
* <p>
|
* <p>
|
||||||
* Extensions values could be String/Number/Boolean
|
* Extensions values could be String/Number/Boolean
|
||||||
*/
|
*/
|
||||||
|
@ -34,7 +34,7 @@ public interface CloudEventExtensions {
|
||||||
* Get the extension attribute named {@code extensionName}
|
* Get the extension attribute named {@code extensionName}
|
||||||
*
|
*
|
||||||
* @param extensionName the extension name
|
* @param extensionName the extension name
|
||||||
* @return the extension value or null if this instance doesn't contain such extension
|
* @return the extension value in one of the valid types String/Number/Boolean or null if this instance doesn't contain such extension
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Object getExtension(String extensionName);
|
Object getExtension(String extensionName);
|
||||||
|
|
|
@ -29,17 +29,17 @@ import java.util.Set;
|
||||||
public interface Extension {
|
public interface Extension {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill this materialized extension with values from a {@link CloudEventExtensions} implementation
|
* Fill this materialized extension with values from a {@link CloudEventExtensions} implementation.
|
||||||
*
|
*
|
||||||
* @param extensions
|
* @param extensions the extensions where to read from
|
||||||
*/
|
*/
|
||||||
void readFrom(CloudEventExtensions extensions);
|
void readFrom(CloudEventExtensions extensions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the attribute of extension named {@code key}
|
* Get the attribute of extension named {@code key}.
|
||||||
*
|
*
|
||||||
* @param key the name of the extension attribute
|
* @param key the name of the extension attribute
|
||||||
* @return the extension value
|
* @return the extension value in one of the valid types String/Number/Boolean
|
||||||
* @throws IllegalArgumentException if the key is unknown to this extension
|
* @throws IllegalArgumentException if the key is unknown to this extension
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package io.cloudevents;
|
package io.cloudevents;
|
||||||
|
|
||||||
|
import io.cloudevents.rw.CloudEventRWException;
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -62,7 +64,7 @@ public enum SpecVersion {
|
||||||
*
|
*
|
||||||
* @param sv String representing the spec version
|
* @param sv String representing the spec version
|
||||||
* @return The parsed spec version
|
* @return The parsed spec version
|
||||||
* @throws IllegalArgumentException When the spec version string is unrecognized
|
* @throws CloudEventRWException When the spec version string is unrecognized
|
||||||
*/
|
*/
|
||||||
public static SpecVersion parse(String sv) {
|
public static SpecVersion parse(String sv) {
|
||||||
switch (sv) {
|
switch (sv) {
|
||||||
|
@ -71,7 +73,7 @@ public enum SpecVersion {
|
||||||
case "1.0":
|
case "1.0":
|
||||||
return SpecVersion.V1;
|
return SpecVersion.V1;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unrecognized SpecVersion " + sv);
|
throw CloudEventRWException.newInvalidSpecVersion(sv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,18 +32,20 @@ public interface CloudEventAttributesWriter {
|
||||||
* Set attribute with type {@link String}. This setter should not be invoked for specversion, because the built Visitor already
|
* Set attribute with type {@link String}. This setter should not be invoked for specversion, because the built Visitor already
|
||||||
* has the information through the {@link CloudEventWriterFactory}.
|
* has the information through the {@link CloudEventWriterFactory}.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name name of the attribute
|
||||||
* @param value
|
* @param value value of the attribute
|
||||||
* @throws CloudEventRWException
|
* @return self
|
||||||
|
* @throws CloudEventRWException if anything goes wrong while writing this attribute.
|
||||||
*/
|
*/
|
||||||
CloudEventAttributesWriter withAttribute(String name, @Nullable String value) throws CloudEventRWException;
|
CloudEventAttributesWriter withAttribute(String name, @Nullable String value) throws CloudEventRWException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set attribute with type {@link URI}.
|
* Set attribute with type {@link URI}.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name name of the attribute
|
||||||
* @param value
|
* @param value value of the attribute
|
||||||
* @throws CloudEventRWException
|
* @throws CloudEventRWException if anything goes wrong while writing this attribute.
|
||||||
|
* @return self
|
||||||
*/
|
*/
|
||||||
default CloudEventAttributesWriter withAttribute(String name, @Nullable URI value) throws CloudEventRWException {
|
default CloudEventAttributesWriter withAttribute(String name, @Nullable URI value) throws CloudEventRWException {
|
||||||
return withAttribute(name, value == null ? null : value.toString());
|
return withAttribute(name, value == null ? null : value.toString());
|
||||||
|
@ -52,12 +54,13 @@ public interface CloudEventAttributesWriter {
|
||||||
/**
|
/**
|
||||||
* Set attribute with type {@link OffsetDateTime} attribute.
|
* Set attribute with type {@link OffsetDateTime} attribute.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name name of the attribute
|
||||||
* @param value
|
* @param value value of the attribute
|
||||||
* @throws CloudEventRWException
|
* @throws CloudEventRWException if anything goes wrong while writing this attribute.
|
||||||
|
* @return self
|
||||||
*/
|
*/
|
||||||
default CloudEventAttributesWriter withAttribute(String name, @Nullable OffsetDateTime value) throws CloudEventRWException {
|
default CloudEventAttributesWriter withAttribute(String name, @Nullable OffsetDateTime value) throws CloudEventRWException {
|
||||||
return withAttribute(name, value == null ? null : Time.writeTime(value));
|
return withAttribute(name, value == null ? null : Time.writeTime(name, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,18 +29,20 @@ public interface CloudEventExtensionsWriter {
|
||||||
/**
|
/**
|
||||||
* Set an extension with type {@link String}.
|
* Set an extension with type {@link String}.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name name of the extension
|
||||||
* @param value
|
* @param value value of the extension
|
||||||
* @throws CloudEventRWException
|
* @return self
|
||||||
|
* @throws CloudEventRWException if anything goes wrong while writing this extension.
|
||||||
*/
|
*/
|
||||||
CloudEventExtensionsWriter withExtension(String name, @Nullable String value) throws CloudEventRWException;
|
CloudEventExtensionsWriter withExtension(String name, @Nullable String value) throws CloudEventRWException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set attribute with type {@link URI}.
|
* Set attribute with type {@link URI}.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name name of the extension
|
||||||
* @param value
|
* @param value value of the extension
|
||||||
* @throws CloudEventRWException
|
* @throws CloudEventRWException if anything goes wrong while writing this extension.
|
||||||
|
* @return self
|
||||||
*/
|
*/
|
||||||
default CloudEventExtensionsWriter withExtension(String name, @Nullable Number value) throws CloudEventRWException {
|
default CloudEventExtensionsWriter withExtension(String name, @Nullable Number value) throws CloudEventRWException {
|
||||||
return withExtension(name, value == null ? null : value.toString());
|
return withExtension(name, value == null ? null : value.toString());
|
||||||
|
@ -49,9 +51,10 @@ public interface CloudEventExtensionsWriter {
|
||||||
/**
|
/**
|
||||||
* Set attribute with type {@link Boolean} attribute.
|
* Set attribute with type {@link Boolean} attribute.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name name of the extension
|
||||||
* @param value
|
* @param value value of the extension
|
||||||
* @throws CloudEventRWException
|
* @throws CloudEventRWException if anything goes wrong while writing this extension.
|
||||||
|
* @return self
|
||||||
*/
|
*/
|
||||||
default CloudEventExtensionsWriter withExtension(String name, @Nullable Boolean value) throws CloudEventRWException {
|
default CloudEventExtensionsWriter withExtension(String name, @Nullable Boolean value) throws CloudEventRWException {
|
||||||
return withExtension(name, value == null ? null : value.toString());
|
return withExtension(name, value == null ? null : value.toString());
|
||||||
|
|
|
@ -17,31 +17,64 @@
|
||||||
|
|
||||||
package io.cloudevents.rw;
|
package io.cloudevents.rw;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is the exception Protocol Binding and Event Format implementers can use to signal errors while serializing/deserializing CloudEvent.
|
||||||
|
*/
|
||||||
public class CloudEventRWException extends RuntimeException {
|
public class CloudEventRWException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The kind of error that happened while serializing/deserializing
|
||||||
|
*/
|
||||||
public enum CloudEventRWExceptionKind {
|
public enum CloudEventRWExceptionKind {
|
||||||
|
/**
|
||||||
|
* Spec version string is not recognized by this particular SDK version.
|
||||||
|
*/
|
||||||
INVALID_SPEC_VERSION,
|
INVALID_SPEC_VERSION,
|
||||||
|
/**
|
||||||
|
* The attribute name is not a valid/known context attribute.
|
||||||
|
*/
|
||||||
INVALID_ATTRIBUTE_NAME,
|
INVALID_ATTRIBUTE_NAME,
|
||||||
|
/**
|
||||||
|
* The extension name is not valid,
|
||||||
|
* because it doesn't follow the <a href="https://github.com/cloudevents/spec/blob/v1.0/spec.md#attribute-naming-convention">naming convention</a>
|
||||||
|
* enforced by the CloudEvents spec.
|
||||||
|
*/
|
||||||
|
INVALID_EXTENSION_NAME,
|
||||||
|
/**
|
||||||
|
* The attribute/extension type is not valid.
|
||||||
|
*/
|
||||||
INVALID_ATTRIBUTE_TYPE,
|
INVALID_ATTRIBUTE_TYPE,
|
||||||
|
/**
|
||||||
|
* The attribute/extension value is not valid.
|
||||||
|
*/
|
||||||
INVALID_ATTRIBUTE_VALUE,
|
INVALID_ATTRIBUTE_VALUE,
|
||||||
INVALID_EXTENSION_TYPE,
|
/**
|
||||||
|
* The data type is not valid.
|
||||||
|
*/
|
||||||
|
INVALID_DATA_TYPE,
|
||||||
|
/**
|
||||||
|
* Error while converting CloudEventData.
|
||||||
|
*/
|
||||||
DATA_CONVERSION,
|
DATA_CONVERSION,
|
||||||
|
/**
|
||||||
|
* Other error.
|
||||||
|
*/
|
||||||
OTHER
|
OTHER
|
||||||
}
|
}
|
||||||
|
|
||||||
private final CloudEventRWExceptionKind kind;
|
private final CloudEventRWExceptionKind kind;
|
||||||
|
|
||||||
public CloudEventRWException(CloudEventRWExceptionKind kind, Throwable cause) {
|
private CloudEventRWException(CloudEventRWExceptionKind kind, Throwable cause) {
|
||||||
super(cause);
|
super(cause);
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CloudEventRWException(CloudEventRWExceptionKind kind, String message) {
|
private CloudEventRWException(CloudEventRWExceptionKind kind, String message) {
|
||||||
super(message);
|
super(message);
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CloudEventRWException(CloudEventRWExceptionKind kind, String message, Throwable cause) {
|
private CloudEventRWException(CloudEventRWExceptionKind kind, String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +85,7 @@ public class CloudEventRWException extends RuntimeException {
|
||||||
|
|
||||||
public static CloudEventRWException newInvalidSpecVersion(String specVersion) {
|
public static CloudEventRWException newInvalidSpecVersion(String specVersion) {
|
||||||
return new CloudEventRWException(
|
return new CloudEventRWException(
|
||||||
CloudEventRWExceptionKind.INVALID_ATTRIBUTE_TYPE,
|
CloudEventRWExceptionKind.INVALID_SPEC_VERSION,
|
||||||
"Invalid specversion: " + specVersion
|
"Invalid specversion: " + specVersion
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -64,32 +97,45 @@ public class CloudEventRWException extends RuntimeException {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CloudEventRWException newInvalidExtensionName(String extensionName) {
|
||||||
|
return new CloudEventRWException(
|
||||||
|
CloudEventRWExceptionKind.INVALID_EXTENSION_NAME,
|
||||||
|
"Invalid extensions name: " + extensionName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static CloudEventRWException newInvalidAttributeType(String attributeName, Class<?> clazz) {
|
public static CloudEventRWException newInvalidAttributeType(String attributeName, Class<?> clazz) {
|
||||||
return new CloudEventRWException(
|
return new CloudEventRWException(
|
||||||
CloudEventRWExceptionKind.INVALID_ATTRIBUTE_TYPE,
|
CloudEventRWExceptionKind.INVALID_ATTRIBUTE_TYPE,
|
||||||
"Invalid attribute type for \"" + attributeName + "\": " + clazz.getCanonicalName()
|
"Invalid attribute/extension type for \"" + attributeName + "\": " + clazz.getCanonicalName()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CloudEventRWException newInvalidAttributeValue(String attributeName, Object value, Throwable cause) {
|
public static CloudEventRWException newInvalidAttributeValue(String attributeName, Object value, Throwable cause) {
|
||||||
return new CloudEventRWException(
|
return new CloudEventRWException(
|
||||||
CloudEventRWExceptionKind.INVALID_ATTRIBUTE_VALUE,
|
CloudEventRWExceptionKind.INVALID_ATTRIBUTE_VALUE,
|
||||||
"Invalid attribute value for \"" + attributeName + "\": " + value,
|
"Invalid attribute/extension value for \"" + attributeName + "\": " + value,
|
||||||
cause
|
cause
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CloudEventRWException newInvalidExtensionType(String extensionName, Class<?> clazz) {
|
public static CloudEventRWException newInvalidDataType(String actual, String... allowed) {
|
||||||
|
String message;
|
||||||
|
if (allowed.length == 0) {
|
||||||
|
message = "Invalid data type: " + actual;
|
||||||
|
} else {
|
||||||
|
message = "Invalid data type: " + actual + ". Allowed: " + String.join(", ", allowed);
|
||||||
|
}
|
||||||
return new CloudEventRWException(
|
return new CloudEventRWException(
|
||||||
CloudEventRWExceptionKind.INVALID_EXTENSION_TYPE,
|
CloudEventRWExceptionKind.INVALID_DATA_TYPE,
|
||||||
"Invalid extension type for \"" + extensionName + "\": " + clazz.getCanonicalName()
|
message
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CloudEventRWException newDataConversion(Throwable cause, String to) {
|
public static CloudEventRWException newDataConversion(Throwable cause, String from, String to) {
|
||||||
return new CloudEventRWException(
|
return new CloudEventRWException(
|
||||||
CloudEventRWExceptionKind.DATA_CONVERSION,
|
CloudEventRWExceptionKind.DATA_CONVERSION,
|
||||||
"Error while trying to convert data to " + to,
|
"Error while trying to convert data from " + from + " to " + to,
|
||||||
cause
|
cause
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ public interface CloudEventReader {
|
||||||
* Visit self using the provided visitor factory
|
* Visit self using the provided visitor factory
|
||||||
*
|
*
|
||||||
* @param writerFactory a factory that generates a visitor starting from the SpecVersion of the event
|
* @param writerFactory a factory that generates a visitor starting from the SpecVersion of the event
|
||||||
* @throws CloudEventRWException if something went wrong during the visit.
|
* @throws CloudEventRWException if something went wrong during the read.
|
||||||
*/
|
*/
|
||||||
default <V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> writerFactory) throws CloudEventRWException {
|
default <V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> writerFactory) throws CloudEventRWException {
|
||||||
return read(writerFactory, null);
|
return read(writerFactory, null);
|
||||||
|
|
|
@ -31,6 +31,7 @@ public interface CloudEventWriter<R> extends CloudEventAttributesWriter, CloudEv
|
||||||
* End the visit with a data field
|
* End the visit with a data field
|
||||||
*
|
*
|
||||||
* @return an eventual return value
|
* @return an eventual return value
|
||||||
|
* @throws CloudEventRWException if the message writer cannot be ended.
|
||||||
*/
|
*/
|
||||||
R end(CloudEventData data) throws CloudEventRWException;
|
R end(CloudEventData data) throws CloudEventRWException;
|
||||||
|
|
||||||
|
@ -38,7 +39,8 @@ public interface CloudEventWriter<R> extends CloudEventAttributesWriter, CloudEv
|
||||||
* End the visit
|
* End the visit
|
||||||
*
|
*
|
||||||
* @return an eventual return value
|
* @return an eventual return value
|
||||||
|
* @throws CloudEventRWException if the message writer cannot be ended.
|
||||||
*/
|
*/
|
||||||
R end();
|
R end() throws CloudEventRWException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,9 @@ public interface CloudEventWriterFactory<V extends CloudEventWriter<R>, R> {
|
||||||
/**
|
/**
|
||||||
* Create a {@link CloudEventWriter} starting from the provided {@link SpecVersion}
|
* Create a {@link CloudEventWriter} starting from the provided {@link SpecVersion}
|
||||||
*
|
*
|
||||||
* @param version
|
* @param version the spec version to create the writer
|
||||||
* @return
|
* @return the new writer
|
||||||
|
* @throws CloudEventRWException if the spec version is invalid or the writer cannot be instantiated.
|
||||||
*/
|
*/
|
||||||
V create(SpecVersion version);
|
V create(SpecVersion version) throws CloudEventRWException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
package io.cloudevents.types;
|
package io.cloudevents.types;
|
||||||
|
|
||||||
|
import io.cloudevents.rw.CloudEventRWException;
|
||||||
|
|
||||||
|
import java.time.DateTimeException;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
|
|
||||||
|
@ -31,16 +34,56 @@ public final class Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a {@link String} RFC3339 compliant as {@link OffsetDateTime}
|
* Parse a {@link String} RFC3339 compliant as {@link OffsetDateTime}.
|
||||||
|
*
|
||||||
|
* @param time the value to parse as time
|
||||||
|
* @return the parsed {@link OffsetDateTime}
|
||||||
|
* @throws DateTimeParseException if something went wrong when parsing the provided time.
|
||||||
*/
|
*/
|
||||||
public static OffsetDateTime parseTime(String time) throws DateTimeParseException {
|
public static OffsetDateTime parseTime(String time) throws DateTimeParseException {
|
||||||
return OffsetDateTime.parse(time);
|
return OffsetDateTime.parse(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a {@link OffsetDateTime} to a RFC3339 compliant {@link String}
|
* Parse an attribute/extension with RFC3339 compliant {@link String} value as {@link OffsetDateTime}.
|
||||||
|
*
|
||||||
|
* @param attributeName the attribute/extension name
|
||||||
|
* @param time the value to parse as time
|
||||||
|
* @return the parsed {@link OffsetDateTime}
|
||||||
|
* @throws CloudEventRWException if something went wrong when parsing the attribute/extension.
|
||||||
*/
|
*/
|
||||||
public static String writeTime(OffsetDateTime time) throws DateTimeParseException {
|
public static OffsetDateTime parseTime(String attributeName, String time) throws CloudEventRWException {
|
||||||
|
try {
|
||||||
|
return parseTime(time);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
throw CloudEventRWException.newInvalidAttributeValue(attributeName, time, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a {@link OffsetDateTime} to a RFC3339 compliant {@link String}.
|
||||||
|
*
|
||||||
|
* @param time the time to write as {@link String}
|
||||||
|
* @return the serialized time
|
||||||
|
* @throws DateTimeException if something went wrong when serializing the provided time.
|
||||||
|
*/
|
||||||
|
public static String writeTime(OffsetDateTime time) throws DateTimeException {
|
||||||
return ISO_OFFSET_DATE_TIME.format(time);
|
return ISO_OFFSET_DATE_TIME.format(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an attribute/extension {@link OffsetDateTime} to a RFC3339 compliant {@link String}.
|
||||||
|
*
|
||||||
|
* @param attributeName the attribute/extension name
|
||||||
|
* @param time the time to write as {@link String}
|
||||||
|
* @return the serialized time
|
||||||
|
* @throws CloudEventRWException if something went wrong when serializing the attribute/extension.
|
||||||
|
*/
|
||||||
|
public static String writeTime(String attributeName, OffsetDateTime time) throws DateTimeException {
|
||||||
|
try {
|
||||||
|
return writeTime(time);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
throw CloudEventRWException.newInvalidAttributeValue(attributeName, time, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package io.cloudevents;
|
||||||
|
|
||||||
|
import io.cloudevents.rw.CloudEventRWException;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||||
|
|
||||||
|
class SpecVersionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parse() {
|
||||||
|
assertAll(
|
||||||
|
() -> assertThat(SpecVersion.parse("1.0")).isEqualTo(SpecVersion.V1),
|
||||||
|
() -> assertThat(SpecVersion.parse("0.3")).isEqualTo(SpecVersion.V03),
|
||||||
|
() -> assertThatCode(() -> SpecVersion.parse("9000.1"))
|
||||||
|
.hasMessage(CloudEventRWException.newInvalidSpecVersion("9000.1").getMessage())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
package io.cloudevents.types;
|
package io.cloudevents.types;
|
||||||
|
|
||||||
|
|
||||||
|
import io.cloudevents.rw.CloudEventRWException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
@ -28,6 +29,7 @@ import java.time.ZoneOffset;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||||
|
|
||||||
public class TimeTest {
|
public class TimeTest {
|
||||||
|
|
||||||
|
@ -44,6 +46,13 @@ public class TimeTest {
|
||||||
.isEqualTo("1937-01-01T12:00:27.87Z");
|
.isEqualTo("1937-01-01T12:00:27.87Z");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseTimeException() {
|
||||||
|
assertThatCode(() -> Time.parseTime("time", "01-01T12:20:27.87+00:20"))
|
||||||
|
.isInstanceOf(CloudEventRWException.class)
|
||||||
|
.hasMessage(CloudEventRWException.newInvalidAttributeValue("time", "01-01T12:20:27.87+00:20", null).getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSerializeDateOffset() {
|
void testSerializeDateOffset() {
|
||||||
assertThat(Time.writeTime(OffsetDateTime.of(
|
assertThat(Time.writeTime(OffsetDateTime.of(
|
||||||
|
|
|
@ -62,15 +62,15 @@ public abstract class BaseCloudEvent implements CloudEvent, CloudEventReader, Cl
|
||||||
return visitor.end();
|
return visitor.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readExtensions(CloudEventExtensionsWriter visitor) throws CloudEventRWException {
|
public void readExtensions(CloudEventExtensionsWriter writer) throws CloudEventRWException {
|
||||||
// TODO to be improved
|
// TODO to be improved
|
||||||
for (Map.Entry<String, Object> entry : this.extensions.entrySet()) {
|
for (Map.Entry<String, Object> entry : this.extensions.entrySet()) {
|
||||||
if (entry.getValue() instanceof String) {
|
if (entry.getValue() instanceof String) {
|
||||||
visitor.withExtension(entry.getKey(), (String) entry.getValue());
|
writer.withExtension(entry.getKey(), (String) entry.getValue());
|
||||||
} else if (entry.getValue() instanceof Number) {
|
} else if (entry.getValue() instanceof Number) {
|
||||||
visitor.withExtension(entry.getKey(), (Number) entry.getValue());
|
writer.withExtension(entry.getKey(), (Number) entry.getValue());
|
||||||
} else if (entry.getValue() instanceof Boolean) {
|
} else if (entry.getValue() instanceof Boolean) {
|
||||||
visitor.withExtension(entry.getKey(), (Boolean) entry.getValue());
|
writer.withExtension(entry.getKey(), (Boolean) entry.getValue());
|
||||||
} else {
|
} else {
|
||||||
// This should never happen because we build that map only through our builders
|
// This should never happen because we build that map only through our builders
|
||||||
throw new IllegalStateException("Illegal value inside extensions map: " + entry);
|
throw new IllegalStateException("Illegal value inside extensions map: " + entry);
|
||||||
|
|
|
@ -61,15 +61,15 @@ public class CloudEventReaderAdapter implements CloudEventReader, CloudEventCont
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readExtensions(CloudEventExtensionsWriter visitor) throws RuntimeException {
|
public void readExtensions(CloudEventExtensionsWriter writer) throws RuntimeException {
|
||||||
for (String key : event.getExtensionNames()) {
|
for (String key : event.getExtensionNames()) {
|
||||||
Object value = event.getExtension(key);
|
Object value = event.getExtension(key);
|
||||||
if (value instanceof String) {
|
if (value instanceof String) {
|
||||||
visitor.withExtension(key, (String) value);
|
writer.withExtension(key, (String) value);
|
||||||
} else if (value instanceof Number) {
|
} else if (value instanceof Number) {
|
||||||
visitor.withExtension(key, (Number) value);
|
writer.withExtension(key, (Number) value);
|
||||||
} else if (value instanceof Boolean) {
|
} else if (value instanceof Boolean) {
|
||||||
visitor.withExtension(key, (Boolean) value);
|
writer.withExtension(key, (Boolean) value);
|
||||||
} else {
|
} else {
|
||||||
// This should never happen because we build that map only through our builders
|
// This should never happen because we build that map only through our builders
|
||||||
throw new IllegalStateException("Illegal value inside extensions map: " + key + " " + value);
|
throw new IllegalStateException("Illegal value inside extensions map: " + key + " " + value);
|
||||||
|
|
|
@ -25,7 +25,6 @@ import io.cloudevents.types.Time;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.format.DateTimeParseException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CloudEvent V0.3 builder.
|
* CloudEvent V0.3 builder.
|
||||||
|
@ -167,11 +166,7 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder<CloudEventBui
|
||||||
withSubject(value);
|
withSubject(value);
|
||||||
return this;
|
return this;
|
||||||
case "time":
|
case "time":
|
||||||
try {
|
withTime(Time.parseTime("time", value));
|
||||||
withTime(Time.parseTime(value));
|
|
||||||
} catch (DateTimeParseException e) {
|
|
||||||
throw CloudEventRWException.newInvalidAttributeValue("time", value, e);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
throw CloudEventRWException.newInvalidAttributeName(name);
|
throw CloudEventRWException.newInvalidAttributeName(name);
|
||||||
|
|
|
@ -24,7 +24,6 @@ import io.cloudevents.types.Time;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.format.DateTimeParseException;
|
|
||||||
|
|
||||||
class V1ToV03AttributesConverter implements CloudEventAttributesWriter {
|
class V1ToV03AttributesConverter implements CloudEventAttributesWriter {
|
||||||
|
|
||||||
|
@ -64,11 +63,7 @@ class V1ToV03AttributesConverter implements CloudEventAttributesWriter {
|
||||||
builder.withSubject(value);
|
builder.withSubject(value);
|
||||||
return this;
|
return this;
|
||||||
case "time":
|
case "time":
|
||||||
try {
|
builder.withTime(Time.parseTime("time", value));
|
||||||
builder.withTime(Time.parseTime(value));
|
|
||||||
} catch (DateTimeParseException e) {
|
|
||||||
throw CloudEventRWException.newInvalidAttributeValue("time", value, e);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
throw CloudEventRWException.newInvalidAttributeName(name);
|
throw CloudEventRWException.newInvalidAttributeName(name);
|
||||||
|
|
|
@ -27,7 +27,6 @@ import io.cloudevents.types.Time;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.format.DateTimeParseException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CloudEvent V1.0 builder.
|
* CloudEvent V1.0 builder.
|
||||||
|
@ -161,11 +160,7 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder<CloudEventBui
|
||||||
withSubject(value);
|
withSubject(value);
|
||||||
return this;
|
return this;
|
||||||
case "time":
|
case "time":
|
||||||
try {
|
withTime(Time.parseTime("time", value));
|
||||||
withTime(Time.parseTime(value));
|
|
||||||
} catch (DateTimeParseException e) {
|
|
||||||
throw CloudEventRWException.newInvalidAttributeValue("time", value, e);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
throw CloudEventRWException.newInvalidAttributeName(name);
|
throw CloudEventRWException.newInvalidAttributeName(name);
|
||||||
|
|
|
@ -24,7 +24,6 @@ import io.cloudevents.types.Time;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.format.DateTimeParseException;
|
|
||||||
|
|
||||||
class V03ToV1AttributesConverter implements CloudEventAttributesWriter {
|
class V03ToV1AttributesConverter implements CloudEventAttributesWriter {
|
||||||
|
|
||||||
|
@ -64,11 +63,7 @@ class V03ToV1AttributesConverter implements CloudEventAttributesWriter {
|
||||||
builder.withSubject(value);
|
builder.withSubject(value);
|
||||||
return this;
|
return this;
|
||||||
case "time":
|
case "time":
|
||||||
try {
|
builder.withTime(Time.parseTime("time", value));
|
||||||
builder.withTime(Time.parseTime(value));
|
|
||||||
} catch (DateTimeParseException e) {
|
|
||||||
throw CloudEventRWException.newInvalidAttributeValue("time", value, e);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
throw CloudEventRWException.newInvalidAttributeName(name);
|
throw CloudEventRWException.newInvalidAttributeName(name);
|
||||||
|
|
|
@ -95,14 +95,14 @@ public class MockBinaryMessageWriter extends BaseBinaryMessageReader implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readExtensions(CloudEventExtensionsWriter visitor) throws CloudEventRWException, IllegalStateException {
|
public void readExtensions(CloudEventExtensionsWriter writer) throws CloudEventRWException, IllegalStateException {
|
||||||
for (Map.Entry<String, Object> entry : this.extensions.entrySet()) {
|
for (Map.Entry<String, Object> entry : this.extensions.entrySet()) {
|
||||||
if (entry.getValue() instanceof String) {
|
if (entry.getValue() instanceof String) {
|
||||||
visitor.withExtension(entry.getKey(), (String) entry.getValue());
|
writer.withExtension(entry.getKey(), (String) entry.getValue());
|
||||||
} else if (entry.getValue() instanceof Number) {
|
} else if (entry.getValue() instanceof Number) {
|
||||||
visitor.withExtension(entry.getKey(), (Number) entry.getValue());
|
writer.withExtension(entry.getKey(), (Number) entry.getValue());
|
||||||
} else if (entry.getValue() instanceof Boolean) {
|
} else if (entry.getValue() instanceof Boolean) {
|
||||||
visitor.withExtension(entry.getKey(), (Boolean) entry.getValue());
|
writer.withExtension(entry.getKey(), (Boolean) entry.getValue());
|
||||||
} else {
|
} else {
|
||||||
// This should never happen because we build that map only through our builders
|
// This should never happen because we build that map only through our builders
|
||||||
throw new IllegalStateException("Illegal value inside extensions map: " + entry);
|
throw new IllegalStateException("Illegal value inside extensions map: " + entry);
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class PojoCloudEventData<T> implements CloudEventData {
|
||||||
try {
|
try {
|
||||||
this.memoizedValue = mapper.writeValueAsBytes(value);
|
this.memoizedValue = mapper.writeValueAsBytes(value);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw CloudEventRWException.newDataConversion(e, "byte[]");
|
throw CloudEventRWException.newDataConversion(e, value.getClass().toString(), "byte[]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.memoizedValue;
|
return this.memoizedValue;
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class PojoCloudEventDataMapper<T> implements CloudEventDataMapper<PojoClo
|
||||||
try {
|
try {
|
||||||
value = this.mapper.convertValue(node, target);
|
value = this.mapper.convertValue(node, target);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw CloudEventRWException.newDataConversion(e, target.getTypeName());
|
throw CloudEventRWException.newDataConversion(e, JsonNode.class.toString(), target.getTypeName());
|
||||||
}
|
}
|
||||||
return new PojoCloudEventData<>(mapper, value);
|
return new PojoCloudEventData<>(mapper, value);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public class PojoCloudEventDataMapper<T> implements CloudEventDataMapper<PojoClo
|
||||||
try {
|
try {
|
||||||
value = this.mapper.readValue(bytes, this.target);
|
value = this.mapper.readValue(bytes, this.target);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw CloudEventRWException.newDataConversion(e, target.getTypeName());
|
throw CloudEventRWException.newDataConversion(e, byte[].class.toString(), target.getTypeName());
|
||||||
}
|
}
|
||||||
return new PojoCloudEventData<>(mapper, value, bytes);
|
return new PojoCloudEventData<>(mapper, value, bytes);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue