Merge pull request #73 from ruromero/validator
Allow using an existing Validator instance
This commit is contained in:
commit
dfd71734d0
|
|
@ -56,8 +56,8 @@
|
|||
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>javax.el</artifactId>
|
||||
<version>${javax.el.version}</version>
|
||||
<artifactId>jakarta.el</artifactId>
|
||||
<version>${jakarta.el.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
<properties>
|
||||
<jackson.version>2.10.0.pr3</jackson.version>
|
||||
<hibernate-validator.version>6.0.17.Final</hibernate-validator.version>
|
||||
<javax.el.version>3.0.1-b11</javax.el.version>
|
||||
<jakarta.el.version>3.0.3</jakarta.el.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -15,8 +15,12 @@
|
|||
*/
|
||||
package io.cloudevents;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
|
|
@ -27,6 +31,30 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
|||
*/
|
||||
public interface Attributes {
|
||||
|
||||
/**
|
||||
* @return Identifies the event. Producers MUST ensure that source + id is unique for each distinct event
|
||||
*/
|
||||
@NotBlank
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* @return A value describing the type of event related to the originating occurrence.
|
||||
*/
|
||||
@NotBlank
|
||||
String getType();
|
||||
|
||||
/**
|
||||
* @return The context in which an event happened.
|
||||
*/
|
||||
@NotNull
|
||||
URI getSource();
|
||||
|
||||
/**
|
||||
* @return The version of the CloudEvents specification which the event uses
|
||||
*/
|
||||
@NotBlank
|
||||
String getSpecversion();
|
||||
|
||||
/**
|
||||
* A common way to get the media type of CloudEvents 'data';
|
||||
* @return If has a value, it MUST follows the <a href="https://tools.ietf.org/html/rfc2046">RFC2046</a>
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public interface ExtensionFormat {
|
|||
*/
|
||||
Map<String, String> transport();
|
||||
|
||||
public static ExtensionFormat of(final InMemoryFormat inMemory,
|
||||
static ExtensionFormat of(final InMemoryFormat inMemory,
|
||||
final String key, final String value) {
|
||||
|
||||
final Map<String, String> transport = new HashMap<>();
|
||||
|
|
@ -62,7 +62,7 @@ public interface ExtensionFormat {
|
|||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static ExtensionFormat of(final InMemoryFormat inMemory,
|
||||
static ExtensionFormat of(final InMemoryFormat inMemory,
|
||||
Entry<String, String> ... transport){
|
||||
Objects.requireNonNull(inMemory);
|
||||
Objects.requireNonNull(transport);
|
||||
|
|
@ -89,7 +89,7 @@ public interface ExtensionFormat {
|
|||
* @param extensions
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, String> marshal(Collection<ExtensionFormat>
|
||||
static Map<String, String> marshal(Collection<ExtensionFormat>
|
||||
extensions) {
|
||||
|
||||
return extensions.stream()
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public final class BinaryMarshaller {
|
|||
return new Builder<A, T, P, H>();
|
||||
}
|
||||
|
||||
public static interface AttributeMarshalStep<A extends Attributes, T, P, H> {
|
||||
public interface AttributeMarshalStep<A extends Attributes, T, P, H> {
|
||||
/**
|
||||
* Marshals the {@link Attributes} instance into a
|
||||
* {@code Map<String, String>}
|
||||
|
|
@ -63,7 +63,7 @@ public final class BinaryMarshaller {
|
|||
ExtensionsAccessorStep<A, T, P, H> map(AttributeMarshaller<A> marshaller);
|
||||
}
|
||||
|
||||
public static interface ExtensionsAccessorStep<A extends Attributes, T, P, H> {
|
||||
public interface ExtensionsAccessorStep<A extends Attributes, T, P, H> {
|
||||
|
||||
/**
|
||||
* To get access of internal collection of {@link ExtensionFormat}
|
||||
|
|
@ -74,7 +74,7 @@ public final class BinaryMarshaller {
|
|||
|
||||
}
|
||||
|
||||
public static interface ExtensionsStep<A extends Attributes, T, P, H> {
|
||||
public interface ExtensionsStep<A extends Attributes, T, P, H> {
|
||||
/**
|
||||
* Marshals the collection of {@link ExtensionFormat} into a
|
||||
* {@code Map<String, String>}
|
||||
|
|
@ -84,7 +84,7 @@ public final class BinaryMarshaller {
|
|||
HeaderMapStep<A, T, P, H> map(ExtensionMarshaller marshaller);
|
||||
}
|
||||
|
||||
public static interface HeaderMapStep<A extends Attributes, T, P, H> {
|
||||
public interface HeaderMapStep<A extends Attributes, T, P, H> {
|
||||
/**
|
||||
* Marshals the map of attributes and extensions into a map of headers
|
||||
* @param mapper
|
||||
|
|
@ -93,7 +93,7 @@ public final class BinaryMarshaller {
|
|||
DataMarshallerStep<A, T, P, H> map(FormatHeaderMapper<H> mapper);
|
||||
}
|
||||
|
||||
public static interface DataMarshallerStep<A extends Attributes, T, P, H> {
|
||||
public interface DataMarshallerStep<A extends Attributes, T, P, H> {
|
||||
/**
|
||||
* Marshals the 'data' into payload
|
||||
* @param marshaller
|
||||
|
|
@ -102,7 +102,7 @@ public final class BinaryMarshaller {
|
|||
BuilderStep<A, T, P, H> map(DataMarshaller<P, T, H> marshaller);
|
||||
}
|
||||
|
||||
public static interface BuilderStep<A extends Attributes, T, P, H> {
|
||||
public interface BuilderStep<A extends Attributes, T, P, H> {
|
||||
/**
|
||||
* Builds the {@link Wire} to use for wire transfer
|
||||
* @param builder
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
|
@ -219,10 +220,8 @@ public final class BinaryUnmarshaller {
|
|||
A attributes = attributeUnmarshaller.unmarshal(attributesMap);
|
||||
|
||||
T data = attributes.getMediaType()
|
||||
.map((mime) -> {
|
||||
return dataUnmarshallers.get(mime);
|
||||
})
|
||||
.filter((un) -> null != un)
|
||||
.map((mime) -> dataUnmarshallers.get(mime))
|
||||
.filter(Objects::nonNull)
|
||||
.map(unmarshaller ->
|
||||
unmarshaller.unmarshal(payload, attributes))
|
||||
.orElse(null);
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public class StructuredMarshaller {
|
|||
return new Builder<>();
|
||||
}
|
||||
|
||||
public static interface MediaTypeStep<A extends Attributes, T, P, H> {
|
||||
public interface MediaTypeStep<A extends Attributes, T, P, H> {
|
||||
/**
|
||||
* Sets the media type of CloudEvents envelope
|
||||
* @param headerName Example {@code Content-Type} for HTTP
|
||||
|
|
@ -60,7 +60,7 @@ public class StructuredMarshaller {
|
|||
EnvelopeMarshallerStep<A, T, P, H> mime(String headerName, H mediaType);
|
||||
}
|
||||
|
||||
public static interface EnvelopeMarshallerStep<A extends Attributes, T, P, H> {
|
||||
public interface EnvelopeMarshallerStep<A extends Attributes, T, P, H> {
|
||||
/**
|
||||
* Sets the marshaller for the CloudEvent
|
||||
* @param marshaller
|
||||
|
|
@ -68,7 +68,7 @@ public class StructuredMarshaller {
|
|||
ExtensionAccessorStep<A, T, P, H> map(EnvelopeMarshaller<A, T, P> marshaller);
|
||||
}
|
||||
|
||||
public static interface ExtensionAccessorStep<A extends Attributes, T, P, H> {
|
||||
public interface ExtensionAccessorStep<A extends Attributes, T, P, H> {
|
||||
/**
|
||||
* To skip the extension special handling
|
||||
*/
|
||||
|
|
@ -76,11 +76,11 @@ public class StructuredMarshaller {
|
|||
ExtensionMarshallerStep<A, T, P, H> map(ExtensionFormatAccessor<A, T> accessor);
|
||||
}
|
||||
|
||||
public static interface ExtensionMarshallerStep<A extends Attributes, T, P, H> {
|
||||
public interface ExtensionMarshallerStep<A extends Attributes, T, P, H> {
|
||||
HeaderMapperStep<A, T, P, H> map(ExtensionMarshaller marshaller);
|
||||
}
|
||||
|
||||
public static interface HeaderMapperStep<A extends Attributes, T, P, H> {
|
||||
public interface HeaderMapperStep<A extends Attributes, T, P, H> {
|
||||
EventStep<A, T, P, H> map(FormatHeaderMapper<H> mapper);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,18 +144,15 @@ public class StructuredUnmarshaller {
|
|||
Optional.ofNullable(extensionMapper)
|
||||
.map(mapper -> mapper.map(headers))
|
||||
.orElse(new HashMap<>());
|
||||
|
||||
CloudEvent<A, T> result =
|
||||
unmarshaller.unmarshal(payload,
|
||||
() ->
|
||||
|
||||
return unmarshaller.unmarshal(payload,
|
||||
() ->
|
||||
extensionUnmarshallers.stream()
|
||||
.map(unmarshaller ->
|
||||
unmarshaller.unmarshal(extensionsMap))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ public class AttributesImpl implements Attributes {
|
|||
|
||||
URI schemaurl =
|
||||
Optional.ofNullable(attributes.get(ContextAttributes.schemaurl.name()))
|
||||
.map(schema -> URI.create(schema))
|
||||
.map(URI::create)
|
||||
.orElse(null);
|
||||
|
||||
String id = attributes.get(ContextAttributes.id.name());
|
||||
|
|
@ -201,19 +201,11 @@ public class AttributesImpl implements Attributes {
|
|||
result.put(ContextAttributes.id.name(),
|
||||
attributes.getId());
|
||||
|
||||
attributes.getTime().ifPresent((value) -> {
|
||||
result.put(ContextAttributes.time.name(),
|
||||
value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
|
||||
});
|
||||
|
||||
attributes.getSchemaurl().ifPresent((schema) -> {
|
||||
result.put(ContextAttributes.schemaurl.name(),
|
||||
schema.toString());
|
||||
});
|
||||
|
||||
attributes.getContenttype().ifPresent((ct) -> {
|
||||
result.put(ContextAttributes.contenttype.name(), ct);
|
||||
});
|
||||
attributes.getTime().ifPresent((value) -> result.put(ContextAttributes.time.name(),
|
||||
value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)));
|
||||
attributes.getSchemaurl().ifPresent((schema) -> result.put(ContextAttributes.schemaurl.name(),
|
||||
schema.toString()));
|
||||
attributes.getContenttype().ifPresent((ct) -> result.put(ContextAttributes.contenttype.name(), ct));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
/**
|
||||
* Copyright 2019 The CloudEvents Authors
|
||||
*
|
||||
* <p>
|
||||
* 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
|
||||
*
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package io.cloudevents.v02;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collection;
|
||||
|
|
@ -35,242 +33,222 @@ import io.cloudevents.CloudEvent;
|
|||
import io.cloudevents.extensions.ExtensionFormat;
|
||||
import io.cloudevents.fun.EventBuilder;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* CloudEvent instances builder
|
||||
*
|
||||
*
|
||||
* @author fabiojose
|
||||
* @version 0.2
|
||||
*/
|
||||
public class CloudEventBuilder<T> implements EventBuilder<T, AttributesImpl>,
|
||||
Builder<AttributesImpl, T> {
|
||||
private CloudEventBuilder() {}
|
||||
|
||||
private static Validator VALIDATOR;
|
||||
|
||||
private static final String SPEC_VERSION = "0.2";
|
||||
private static final String MESSAGE_SEPARATOR = ", ";
|
||||
private static final String MESSAGE = "'%s' %s";
|
||||
private static final String ERR_MESSAGE = "invalid payload: %s";
|
||||
Builder<AttributesImpl, T> {
|
||||
private CloudEventBuilder() {
|
||||
}
|
||||
|
||||
private String type;
|
||||
private String id;
|
||||
private URI source;
|
||||
|
||||
private ZonedDateTime time;
|
||||
private URI schemaurl;
|
||||
private String contenttype;
|
||||
private T data;
|
||||
|
||||
private final Set<ExtensionFormat> extensions = new HashSet<>();
|
||||
|
||||
private static Validator getValidator() {
|
||||
if(null== VALIDATOR) {
|
||||
VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
}
|
||||
return VALIDATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a brand new builder instance
|
||||
* @param <T> The 'data' type
|
||||
*/
|
||||
public static <T> CloudEventBuilder<T> builder() {
|
||||
return new CloudEventBuilder<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
private static Validator VALIDATOR;
|
||||
|
||||
private static final String SPEC_VERSION = "0.2";
|
||||
private static final String MESSAGE_SEPARATOR = ", ";
|
||||
private static final String MESSAGE = "'%s' %s";
|
||||
private static final String ERR_MESSAGE = "invalid payload: %s";
|
||||
|
||||
private String type;
|
||||
private String id;
|
||||
private URI source;
|
||||
|
||||
private ZonedDateTime time;
|
||||
private URI schemaurl;
|
||||
private String contenttype;
|
||||
private T data;
|
||||
|
||||
private final Set<ExtensionFormat> extensions = new HashSet<>();
|
||||
private Validator validator;
|
||||
|
||||
private static Validator getValidator() {
|
||||
if (null == VALIDATOR) {
|
||||
VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
}
|
||||
return VALIDATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a brand new builder instance
|
||||
* @param <T> The 'data' type
|
||||
*/
|
||||
public static <T> CloudEventBuilder<T> builder() {
|
||||
return new CloudEventBuilder<>();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param base A base event to copy {@link CloudEvent#getAttributes()},
|
||||
* {@link CloudEvent#getData()} and {@link CloudEvent#getExtensions()}
|
||||
* @return
|
||||
*/
|
||||
public static <T> CloudEventBuilder<T> builder(
|
||||
final CloudEvent<AttributesImpl, T> base) {
|
||||
Objects.requireNonNull(base);
|
||||
|
||||
CloudEventBuilder<T> result = new CloudEventBuilder<>();
|
||||
|
||||
AttributesImpl attributes = base.getAttributes();
|
||||
|
||||
result
|
||||
.withId(attributes.getId())
|
||||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent((time) -> {
|
||||
result.withTime(time);
|
||||
});
|
||||
|
||||
attributes.getSchemaurl().ifPresent((schema) -> {
|
||||
result.withSchemaurl(schema);
|
||||
});
|
||||
|
||||
attributes.getContenttype().ifPresent(contenttype -> {
|
||||
result.withContenttype(contenttype);
|
||||
});
|
||||
|
||||
Accessor.extensionsOf(base)
|
||||
.forEach(extension -> {
|
||||
result.withExtension(extension);
|
||||
});
|
||||
|
||||
base.getData().ifPresent(data -> {
|
||||
result.withData(data);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> the type of 'data'
|
||||
* @param data the value of data
|
||||
* @param attributes the context attributes
|
||||
* @return An new {@link CloudEventImpl} immutable instance
|
||||
* @throws IllegalStateException When there are specification constraints
|
||||
* violations
|
||||
*/
|
||||
public static <T> CloudEventImpl<T> of(T data, AttributesImpl attributes,
|
||||
Collection<ExtensionFormat> extensions) {
|
||||
CloudEventBuilder<T> builder = new CloudEventBuilder<T>()
|
||||
.withId(attributes.getId())
|
||||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent((time) -> {
|
||||
builder.withTime(time);
|
||||
});
|
||||
|
||||
attributes.getSchemaurl().ifPresent((schema) -> {
|
||||
builder.withSchemaurl(schema);
|
||||
});
|
||||
|
||||
attributes.getContenttype().ifPresent(contenttype -> {
|
||||
builder.withContenttype(contenttype);
|
||||
});
|
||||
|
||||
extensions.stream()
|
||||
.forEach(extension -> {
|
||||
builder.withExtension(extension);
|
||||
});
|
||||
|
||||
return builder.withData(data).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloudEvent<AttributesImpl, T> build(T data, AttributesImpl attributes,
|
||||
Collection<ExtensionFormat> extensions){
|
||||
return CloudEventBuilder.<T>of(data, attributes, extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @return An new {@link CloudEventImpl} immutable instance
|
||||
* @throws IllegalStateException When there are specification constraints
|
||||
* violations
|
||||
*/
|
||||
@Override
|
||||
public CloudEventImpl<T> build() {
|
||||
AttributesImpl attributes = new AttributesImpl(type, SPEC_VERSION,
|
||||
source, id, time, schemaurl, contenttype);
|
||||
|
||||
CloudEventImpl<T> event = new CloudEventImpl<>(attributes, data, extensions);
|
||||
|
||||
Set<ConstraintViolation<Object>> violations =
|
||||
getValidator().validate(event);
|
||||
|
||||
violations.addAll(getValidator().validate(event.getAttributes()));
|
||||
|
||||
final String errs =
|
||||
violations.stream()
|
||||
.map(v -> format(MESSAGE, v.getPropertyPath(), v.getMessage()))
|
||||
.collect(Collectors.joining(MESSAGE_SEPARATOR));
|
||||
|
||||
Optional.ofNullable(
|
||||
"".equals(errs) ? null : errs
|
||||
|
||||
).ifPresent((e) -> {
|
||||
throw new IllegalStateException(format(ERR_MESSAGE, e));
|
||||
});
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withSource(URI source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withTime(ZonedDateTime time) {
|
||||
this.time = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withSchemaurl(URI schemaurl) {
|
||||
this.schemaurl = schemaurl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withContenttype(String contenttype) {
|
||||
this.contenttype = contenttype;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withData(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withExtension(ExtensionFormat extension) {
|
||||
this.extensions.add(extension);
|
||||
return this;
|
||||
}
|
||||
public static <T> CloudEventBuilder<T> builder(
|
||||
CloudEvent<AttributesImpl, T> base) {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public <TT> CloudEvent<AttributesImpl, TT>
|
||||
build(CloudEvent<AttributesImpl, T> base, String id, TT newData) {
|
||||
Objects.requireNonNull(base);
|
||||
|
||||
AttributesImpl attributes = base.getAttributes();
|
||||
|
||||
CloudEventBuilder<TT> builder = new CloudEventBuilder<TT>()
|
||||
.withId(id)
|
||||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent((time) -> {
|
||||
builder.withTime(time);
|
||||
});
|
||||
|
||||
attributes.getSchemaurl().ifPresent((schema) -> {
|
||||
builder.withSchemaurl(schema);
|
||||
});
|
||||
|
||||
attributes.getContenttype().ifPresent(contenttype -> {
|
||||
builder.withContenttype(contenttype);
|
||||
});
|
||||
|
||||
Collection<ExtensionFormat> extensions = Accessor.extensionsOf(base);
|
||||
|
||||
extensions.stream()
|
||||
.forEach(extension -> {
|
||||
builder.withExtension(extension);
|
||||
});
|
||||
|
||||
return builder.withData(newData).build();
|
||||
}
|
||||
Objects.requireNonNull(base);
|
||||
|
||||
CloudEventBuilder<T> result = new CloudEventBuilder<>();
|
||||
|
||||
AttributesImpl attributes = base.getAttributes();
|
||||
|
||||
result
|
||||
.withId(attributes.getId())
|
||||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent(result::withTime);
|
||||
attributes.getSchemaurl().ifPresent(result::withSchemaurl);
|
||||
attributes.getContenttype().ifPresent(result::withContenttype);
|
||||
Accessor.extensionsOf(base).forEach(result::withExtension);
|
||||
base.getData().ifPresent(result::withData);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> the type of 'data'
|
||||
* @param data the value of data
|
||||
* @param attributes the context attributes
|
||||
* @return An new {@link CloudEventImpl} immutable instance
|
||||
* @throws IllegalStateException When there are specification constraints
|
||||
* violations
|
||||
*/
|
||||
public static <T> CloudEventImpl<T> of(T data, AttributesImpl attributes,
|
||||
Collection<ExtensionFormat> extensions, Validator validator) {
|
||||
CloudEventBuilder<T> builder = new CloudEventBuilder<T>()
|
||||
.withId(attributes.getId())
|
||||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent(builder::withTime);
|
||||
attributes.getSchemaurl().ifPresent(builder::withSchemaurl);
|
||||
attributes.getContenttype().ifPresent(builder::withContenttype);
|
||||
extensions.forEach(builder::withExtension);
|
||||
|
||||
return builder
|
||||
.withData(data)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloudEvent<AttributesImpl, T> build(T data, AttributesImpl attributes,
|
||||
Collection<ExtensionFormat> extensions) {
|
||||
return CloudEventBuilder.of(data, attributes, extensions, this.validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @return An new {@link CloudEventImpl} immutable instance
|
||||
* @throws IllegalStateException When there are specification constraints
|
||||
* violations
|
||||
*/
|
||||
@Override
|
||||
public CloudEventImpl<T> build() {
|
||||
AttributesImpl attributes = new AttributesImpl(type, SPEC_VERSION,
|
||||
source, id, time, schemaurl, contenttype);
|
||||
|
||||
CloudEventImpl<T> event = new CloudEventImpl<>(attributes, data, extensions);
|
||||
|
||||
if (validator == null) {
|
||||
validator = getValidator();
|
||||
}
|
||||
Set<ConstraintViolation<Object>> violations =
|
||||
validator.validate(event);
|
||||
|
||||
violations.addAll(validator.validate(event.getAttributes()));
|
||||
|
||||
final String errs =
|
||||
violations.stream()
|
||||
.map(v -> format(MESSAGE, v.getPropertyPath(), v.getMessage()))
|
||||
.collect(Collectors.joining(MESSAGE_SEPARATOR));
|
||||
|
||||
Optional.ofNullable(
|
||||
"".equals(errs) ? null : errs
|
||||
|
||||
).ifPresent((e) -> {
|
||||
throw new IllegalStateException(format(ERR_MESSAGE, e));
|
||||
});
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withSource(URI source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withTime(ZonedDateTime time) {
|
||||
this.time = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withSchemaurl(URI schemaurl) {
|
||||
this.schemaurl = schemaurl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withContenttype(String contenttype) {
|
||||
this.contenttype = contenttype;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withData(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withExtension(ExtensionFormat extension) {
|
||||
this.extensions.add(extension);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <TT> CloudEvent<AttributesImpl, TT>
|
||||
build(CloudEvent<AttributesImpl, T> base, String id, TT newData) {
|
||||
return build(base, id, newData, null);
|
||||
}
|
||||
|
||||
public <TT> CloudEvent<AttributesImpl, TT>
|
||||
build(CloudEvent<AttributesImpl, T> base, String id, TT newData, Validator validator) {
|
||||
Objects.requireNonNull(base);
|
||||
|
||||
AttributesImpl attributes = base.getAttributes();
|
||||
|
||||
CloudEventBuilder<TT> builder = new CloudEventBuilder<TT>()
|
||||
.withId(id)
|
||||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent(builder::withTime);
|
||||
attributes.getSchemaurl().ifPresent(builder::withSchemaurl);
|
||||
attributes.getContenttype().ifPresent(builder::withContenttype);
|
||||
Collection<ExtensionFormat> extensions = Accessor.extensionsOf(base);
|
||||
extensions.forEach(builder::withExtension);
|
||||
|
||||
return builder
|
||||
.withData(newData)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ public class CloudEventImpl<T> implements CloudEvent<AttributesImpl, T> {
|
|||
public static <T> CloudEventImpl<T> build(
|
||||
@JsonProperty("id") String id,
|
||||
@JsonProperty("source") URI source,
|
||||
@JsonProperty("specversion") String specversion,
|
||||
@JsonProperty("type") String type,
|
||||
@JsonProperty("time") ZonedDateTime time,
|
||||
@JsonProperty("schemaurl") URI schemaurl,
|
||||
|
|
|
|||
|
|
@ -36,8 +36,7 @@ public enum ContextAttributes {
|
|||
contenttype;
|
||||
|
||||
public static final List<String> VALUES =
|
||||
Arrays.asList(ContextAttributes.values())
|
||||
.stream()
|
||||
Arrays.stream(ContextAttributes.values())
|
||||
.map(Enum::name)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,7 @@ public class ExtensionMapper {
|
|||
.filter(header -> null!= header.getValue())
|
||||
.map(header -> new SimpleEntry<>(header.getKey()
|
||||
.toLowerCase(Locale.US), header.getValue().toString()))
|
||||
.filter(header -> {
|
||||
return !RESERVED_HEADERS.contains(header.getKey());
|
||||
})
|
||||
.filter(header -> !RESERVED_HEADERS.contains(header.getKey()))
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package io.cloudevents.v02.http;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.Validator;
|
||||
|
||||
import io.cloudevents.extensions.DistributedTracingExtension;
|
||||
import io.cloudevents.format.BinaryUnmarshaller;
|
||||
import io.cloudevents.format.StructuredUnmarshaller;
|
||||
|
|
@ -16,18 +19,33 @@ import io.cloudevents.v02.CloudEventImpl;
|
|||
*/
|
||||
public class Unmarshallers {
|
||||
private Unmarshallers() {}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param type The type reference to use for 'data' unmarshal
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see BinaryUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
binary(Class<T> type) {
|
||||
return binary(type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param type The type reference to use for 'data' unmarshal
|
||||
* @param validator Provide an existing instance of a {@link Validator}
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see BinaryUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
binary(Class<T> type) {
|
||||
binary(Class<T> type, Validator validator) {
|
||||
return
|
||||
BinaryUnmarshaller.<AttributesImpl, T, String>builder()
|
||||
.map(AttributeMapper::map)
|
||||
|
|
@ -37,20 +55,35 @@ public class Unmarshallers {
|
|||
.map(ExtensionMapper::map)
|
||||
.map(DistributedTracingExtension::unmarshall)
|
||||
.next()
|
||||
.builder(CloudEventBuilder.<T>builder()::build);
|
||||
.builder(CloudEventBuilder.<T>builder().withValidator(validator)::build);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param typeOfData The type reference to use for 'data' unmarshal
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see StructuredUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
structured(Class<T> typeOfData) {
|
||||
return structured(typeOfData, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param typeOfData The type reference to use for 'data' unmarshal
|
||||
* @param validator Provided instance of a {@link Validator}
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see StructuredUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
structured(Class<T> typeOfData) {
|
||||
structured(Class<T> typeOfData, Validator validator) {
|
||||
|
||||
return
|
||||
StructuredUnmarshaller.<AttributesImpl, T, String>
|
||||
|
|
@ -69,8 +102,8 @@ public class Unmarshallers {
|
|||
extensions.get().forEach(extension -> {
|
||||
builder.withExtension(extension);
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
|
||||
return builder.withValidator(validator).build();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,27 +168,13 @@ public class AttributesImpl implements Attributes {
|
|||
result.put(ContextAttributes.id.name(),
|
||||
attributes.getId());
|
||||
|
||||
attributes.getTime().ifPresent((value) -> {
|
||||
result.put(ContextAttributes.time.name(),
|
||||
value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
|
||||
});
|
||||
|
||||
attributes.getSchemaurl().ifPresent((schema) -> {
|
||||
result.put(ContextAttributes.schemaurl.name(),
|
||||
schema.toString());
|
||||
});
|
||||
|
||||
attributes.getDatacontenttype().ifPresent((ct) -> {
|
||||
result.put(ContextAttributes.datacontenttype.name(), ct);
|
||||
});
|
||||
|
||||
attributes.getDatacontentencoding().ifPresent(dce -> {
|
||||
result.put(ContextAttributes.datacontentencoding.name(), dce);
|
||||
});
|
||||
|
||||
attributes.getSubject().ifPresent(subject -> {
|
||||
result.put(ContextAttributes.subject.name(), subject);
|
||||
});
|
||||
attributes.getTime().ifPresent((value) -> result.put(ContextAttributes.time.name(),
|
||||
value.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)));
|
||||
attributes.getSchemaurl().ifPresent((schema) -> result.put(ContextAttributes.schemaurl.name(),
|
||||
schema.toString()));
|
||||
attributes.getDatacontenttype().ifPresent((ct) -> result.put(ContextAttributes.datacontenttype.name(), ct));
|
||||
attributes.getDatacontentencoding().ifPresent(dce -> result.put(ContextAttributes.datacontentencoding.name(), dce));
|
||||
attributes.getSubject().ifPresent(subject -> result.put(ContextAttributes.subject.name(), subject));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -210,7 +196,7 @@ public class AttributesImpl implements Attributes {
|
|||
|
||||
URI schemaurl =
|
||||
Optional.ofNullable(attributes.get(ContextAttributes.schemaurl.name()))
|
||||
.map(schema -> URI.create(schema))
|
||||
.map(URI::create)
|
||||
.orElse(null);
|
||||
|
||||
String id = attributes.get(ContextAttributes.id.name());
|
||||
|
|
|
|||
|
|
@ -36,72 +36,58 @@ import io.cloudevents.fun.EventBuilder;
|
|||
|
||||
/**
|
||||
* The event builder.
|
||||
*
|
||||
*
|
||||
* @author fabiojose
|
||||
*
|
||||
*/
|
||||
public final class CloudEventBuilder<T> implements
|
||||
public final class CloudEventBuilder<T> implements
|
||||
EventBuilder<T, AttributesImpl> {
|
||||
|
||||
private CloudEventBuilder(Validator validator) {
|
||||
if(validator == null) {
|
||||
this.validator = getValidator();
|
||||
} else {
|
||||
this.validator = validator;
|
||||
}
|
||||
}
|
||||
private CloudEventBuilder() {}
|
||||
|
||||
private static Validator VALIDATOR;
|
||||
|
||||
|
||||
public static final String SPEC_VERSION = "0.3";
|
||||
private static final String MESSAGE_SEPARATOR = ", ";
|
||||
private static final String MESSAGE = "'%s' %s";
|
||||
private static final String ERR_MESSAGE = "invalid payload: %s";
|
||||
|
||||
|
||||
private String id;
|
||||
private URI source;
|
||||
|
||||
private String type;
|
||||
|
||||
|
||||
private ZonedDateTime time;
|
||||
private URI schemaurl;
|
||||
private String datacontentencoding;
|
||||
private String datacontenttype;
|
||||
private String subject;
|
||||
|
||||
|
||||
private T data;
|
||||
|
||||
|
||||
private final Set<ExtensionFormat> extensions = new HashSet<>();
|
||||
private final Validator validator;
|
||||
|
||||
private Validator validator;
|
||||
|
||||
private static Validator getValidator() {
|
||||
if(null== VALIDATOR) {
|
||||
VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
}
|
||||
return VALIDATOR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a brand new builder instance
|
||||
* @param <T> The 'data' type
|
||||
*/
|
||||
public static <T> CloudEventBuilder<T> builder() {
|
||||
return new CloudEventBuilder<T>(null);
|
||||
return new CloudEventBuilder<>();
|
||||
}
|
||||
|
||||
public static <T> CloudEventBuilder<T> builder(Validator validator) {
|
||||
return new CloudEventBuilder<T>(validator);
|
||||
}
|
||||
public static <T> CloudEventBuilder<T> builder(
|
||||
CloudEvent<AttributesImpl, T> base) {
|
||||
return builder(base, null);
|
||||
}
|
||||
|
||||
public static <T> CloudEventBuilder<T> builder(
|
||||
CloudEvent<AttributesImpl, T> base, Validator validator) {
|
||||
Objects.requireNonNull(base);
|
||||
|
||||
CloudEventBuilder<T> result = new CloudEventBuilder<>(validator);
|
||||
CloudEventBuilder<T> result = new CloudEventBuilder<>();
|
||||
|
||||
AttributesImpl attributes = base.getAttributes();
|
||||
|
||||
|
|
@ -110,34 +96,13 @@ public final class CloudEventBuilder<T> implements
|
|||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent(time -> {
|
||||
result.withTime(time);
|
||||
});
|
||||
|
||||
attributes.getSchemaurl().ifPresent((schema) -> {
|
||||
result.withSchemaurl(schema);
|
||||
});
|
||||
|
||||
attributes.getDatacontenttype().ifPresent(dc -> {
|
||||
result.withDatacontenttype(dc);
|
||||
});
|
||||
|
||||
attributes.getDatacontentencoding().ifPresent(dce -> {
|
||||
result.withDatacontentencoding(dce);
|
||||
});
|
||||
|
||||
attributes.getSubject().ifPresent(subject -> {
|
||||
result.withSubject(subject);
|
||||
});
|
||||
|
||||
Accessor.extensionsOf(base)
|
||||
.forEach(extension -> {
|
||||
result.withExtension(extension);
|
||||
});
|
||||
|
||||
base.getData().ifPresent(data -> {
|
||||
result.withData(data);
|
||||
});
|
||||
attributes.getTime().ifPresent(result::withTime);
|
||||
attributes.getSchemaurl().ifPresent(result::withSchemaurl);
|
||||
attributes.getDatacontenttype().ifPresent(result::withDatacontenttype);
|
||||
attributes.getDatacontentencoding().ifPresent(result::withDatacontentencoding);
|
||||
attributes.getSubject().ifPresent(result::withSubject);
|
||||
Accessor.extensionsOf(base).forEach(result::withExtension);
|
||||
base.getData().ifPresent(result::withData);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -169,132 +134,124 @@ public final class CloudEventBuilder<T> implements
|
|||
*/
|
||||
public static <T> CloudEventImpl<T> of(T data, AttributesImpl attributes,
|
||||
Collection<ExtensionFormat> extensions, Validator validator) {
|
||||
CloudEventBuilder<T> builder = CloudEventBuilder.<T>builder(validator)
|
||||
CloudEventBuilder<T> builder = CloudEventBuilder.<T>builder()
|
||||
.withId(attributes.getId())
|
||||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent((time) -> {
|
||||
builder.withTime(time);
|
||||
});
|
||||
|
||||
attributes.getSchemaurl().ifPresent((schemaurl) -> {
|
||||
builder.withSchemaurl(schemaurl);
|
||||
});
|
||||
|
||||
attributes.getDatacontentencoding().ifPresent((dce) -> {
|
||||
builder.withDatacontentencoding(dce);
|
||||
});
|
||||
|
||||
attributes.getDatacontenttype().ifPresent((dct) -> {
|
||||
builder.withDatacontenttype(dct);
|
||||
});
|
||||
|
||||
attributes.getSubject().ifPresent((subject) -> {
|
||||
builder.withSubject(subject);
|
||||
});
|
||||
|
||||
extensions.stream()
|
||||
.forEach(extension -> {
|
||||
builder.withExtension(extension);
|
||||
});
|
||||
|
||||
builder.withData(data);
|
||||
|
||||
return builder.build();
|
||||
|
||||
attributes.getTime().ifPresent(builder::withTime);
|
||||
attributes.getSchemaurl().ifPresent(builder::withSchemaurl);
|
||||
attributes.getDatacontentencoding().ifPresent(builder::withDatacontentencoding);
|
||||
attributes.getDatacontenttype().ifPresent(builder::withDatacontenttype);
|
||||
attributes.getSubject().ifPresent(builder::withSubject);
|
||||
extensions.forEach(builder::withExtension);
|
||||
|
||||
return builder
|
||||
.withData(data)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CloudEvent<AttributesImpl, T> build(T data, AttributesImpl attributes,
|
||||
public CloudEvent<AttributesImpl, T> build(T data, AttributesImpl attributes,
|
||||
Collection<ExtensionFormat> extensions){
|
||||
return CloudEventBuilder.<T>of(data, attributes, extensions, null);
|
||||
return CloudEventBuilder.of(data, attributes, extensions, this.validator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return An new {@link CloudEvent} immutable instance
|
||||
* @throws IllegalStateException When there are specification constraints
|
||||
* violations
|
||||
*/
|
||||
public CloudEventImpl<T> build() {
|
||||
|
||||
|
||||
AttributesImpl attributes = new AttributesImpl(id, source, SPEC_VERSION,
|
||||
type, time, schemaurl, datacontentencoding, datacontenttype,
|
||||
subject);
|
||||
|
||||
CloudEventImpl<T> cloudEvent =
|
||||
new CloudEventImpl<T>(attributes, data, extensions);
|
||||
|
||||
|
||||
CloudEventImpl<T> cloudEvent =
|
||||
new CloudEventImpl<>(attributes, data, extensions);
|
||||
|
||||
if(validator == null) {
|
||||
validator = getValidator();
|
||||
}
|
||||
|
||||
Set<ConstraintViolation<Object>> violations =
|
||||
validator.validate(cloudEvent);
|
||||
|
||||
|
||||
violations.addAll(validator.validate(cloudEvent.getAttributes()));
|
||||
|
||||
final String errs =
|
||||
|
||||
final String errs =
|
||||
violations.stream()
|
||||
.map(v -> format(MESSAGE, v.getPropertyPath(), v.getMessage()))
|
||||
.collect(Collectors.joining(MESSAGE_SEPARATOR));
|
||||
|
||||
|
||||
Optional.ofNullable(
|
||||
"".equals(errs) ? null : errs
|
||||
|
||||
|
||||
).ifPresent((e) -> {
|
||||
throw new IllegalStateException(format(ERR_MESSAGE, e));
|
||||
});
|
||||
|
||||
|
||||
return cloudEvent;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withSource(URI source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withTime(ZonedDateTime time) {
|
||||
this.time = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withSchemaurl(URI schemaurl) {
|
||||
this.schemaurl = schemaurl;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withDatacontentencoding(
|
||||
String datacontentencoding) {
|
||||
this.datacontentencoding = datacontentencoding;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withDatacontenttype(
|
||||
String datacontenttype) {
|
||||
this.datacontenttype = datacontenttype;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withSubject(
|
||||
String subject) {
|
||||
this.subject = subject;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withData(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CloudEventBuilder<T> withExtension(ExtensionFormat extension) {
|
||||
this.extensions.add(extension);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ public class CloudEventImpl<T> implements CloudEvent<AttributesImpl, T> {
|
|||
public static <T> CloudEventImpl<T> build(
|
||||
@JsonProperty("id") String id,
|
||||
@JsonProperty("source") URI source,
|
||||
@JsonProperty("specversion") String specversion,
|
||||
@JsonProperty("type") String type,
|
||||
@JsonProperty("time") ZonedDateTime time,
|
||||
@JsonProperty("schemaurl") URI schemaurl,
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ public enum ContextAttributes {
|
|||
subject;
|
||||
|
||||
public static final List<String> VALUES =
|
||||
Arrays.asList(ContextAttributes.values())
|
||||
.stream()
|
||||
Arrays.stream(ContextAttributes.values())
|
||||
.map(Enum::name)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,7 @@ public class ExtensionMapper {
|
|||
.filter(header -> null!= header.getValue())
|
||||
.map(header -> new SimpleEntry<>(header.getKey()
|
||||
.toLowerCase(Locale.US), header.getValue().toString()))
|
||||
.filter(header -> {
|
||||
return !RESERVED_HEADERS.contains(header.getKey());
|
||||
})
|
||||
.filter(header -> !RESERVED_HEADERS.contains(header.getKey()))
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package io.cloudevents.v03.http;
|
||||
|
||||
import javax.validation.Validator;
|
||||
|
||||
import io.cloudevents.extensions.DistributedTracingExtension;
|
||||
import io.cloudevents.format.BinaryUnmarshaller;
|
||||
import io.cloudevents.format.StructuredUnmarshaller;
|
||||
|
|
@ -31,18 +33,33 @@ import io.cloudevents.v03.CloudEventImpl;
|
|||
*/
|
||||
public class Unmarshallers {
|
||||
private Unmarshallers() {}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param type The type reference to use for 'data' unmarshal
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see BinaryUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
binary(Class<T> type) {
|
||||
return binary(type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param type The type reference to use for 'data' unmarshal
|
||||
* @param validator Provided instance of a {@link Validator}
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see BinaryUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
binary(Class<T> type) {
|
||||
binary(Class<T> type, Validator validator) {
|
||||
return
|
||||
BinaryUnmarshaller.<AttributesImpl, T, String>builder()
|
||||
.map(AttributeMapper::map)
|
||||
|
|
@ -52,20 +69,35 @@ public class Unmarshallers {
|
|||
.map(ExtensionMapper::map)
|
||||
.map(DistributedTracingExtension::unmarshall)
|
||||
.next()
|
||||
.builder(CloudEventBuilder.<T>builder()::build);
|
||||
.builder(CloudEventBuilder.<T>builder().withValidator(validator)::build);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param typeOfData The type reference to use for 'data' unmarshal
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see StructuredUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
structured(Class<T> typeOfData) {
|
||||
return structured(typeOfData, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param typeOfData The type reference to use for 'data' unmarshal
|
||||
* @param validator Provided instance of a {@link Validator}
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see StructuredUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
structured(Class<T> typeOfData) {
|
||||
structured(Class<T> typeOfData, Validator validator) {
|
||||
|
||||
return
|
||||
StructuredUnmarshaller.<AttributesImpl, T, String>
|
||||
|
|
@ -85,7 +117,7 @@ public class Unmarshallers {
|
|||
builder.withExtension(extension);
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
return builder.withValidator(validator).build();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,23 +165,12 @@ public class AttributesImpl implements Attributes {
|
|||
result.put(ContextAttributes.type.name(),
|
||||
attributes.getType());
|
||||
|
||||
attributes.getDatacontenttype().ifPresent(dct -> {
|
||||
result.put(ContextAttributes.datacontenttype.name(), dct);
|
||||
});
|
||||
|
||||
attributes.getDataschema().ifPresent(dataschema -> {
|
||||
result.put(ContextAttributes.dataschema.name(),
|
||||
dataschema.toString());
|
||||
});
|
||||
|
||||
attributes.getSubject().ifPresent(subject -> {
|
||||
result.put(ContextAttributes.subject.name(), subject);
|
||||
});
|
||||
|
||||
attributes.getTime().ifPresent(time -> {
|
||||
result.put(ContextAttributes.time.name(),
|
||||
time.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
|
||||
});
|
||||
attributes.getDatacontenttype().ifPresent(dct -> result.put(ContextAttributes.datacontenttype.name(), dct));
|
||||
attributes.getDataschema().ifPresent(dataschema -> result.put(ContextAttributes.dataschema.name(),
|
||||
dataschema.toString()));
|
||||
attributes.getSubject().ifPresent(subject -> result.put(ContextAttributes.subject.name(), subject));
|
||||
attributes.getTime().ifPresent(time -> result.put(ContextAttributes.time.name(),
|
||||
time.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -203,7 +192,7 @@ public class AttributesImpl implements Attributes {
|
|||
|
||||
URI dataschema =
|
||||
Optional.ofNullable(attributes.get(ContextAttributes.dataschema.name()))
|
||||
.map(schema -> URI.create(schema))
|
||||
.map(URI::create)
|
||||
.orElse(null);
|
||||
|
||||
String id = attributes.get(ContextAttributes.id.name());
|
||||
|
|
|
|||
|
|
@ -44,11 +44,13 @@ public class CloudEventBuilder<T> implements
|
|||
private URI dataschema;
|
||||
private String subject;
|
||||
private ZonedDateTime time;
|
||||
|
||||
|
||||
private T data;
|
||||
|
||||
|
||||
private final Set<ExtensionFormat> extensions = new HashSet<>();
|
||||
|
||||
|
||||
private Validator validator;
|
||||
|
||||
private static Validator getValidator() {
|
||||
if(null== VALIDATOR) {
|
||||
VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
|
|
@ -61,16 +63,16 @@ public class CloudEventBuilder<T> implements
|
|||
* @param <T> The 'data' type
|
||||
*/
|
||||
public static <T> CloudEventBuilder<T> builder() {
|
||||
return new CloudEventBuilder<T>();
|
||||
return new CloudEventBuilder<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builder with base event to copy attributes
|
||||
* @param <T> The 'data' type
|
||||
* @param base The base event to copy attributes
|
||||
*/
|
||||
public static <T> CloudEventBuilder<T> builder(
|
||||
CloudEvent<AttributesImpl, T> base) {
|
||||
CloudEvent<AttributesImpl, T> base) {
|
||||
Objects.requireNonNull(base);
|
||||
|
||||
CloudEventBuilder<T> result = new CloudEventBuilder<>();
|
||||
|
|
@ -82,31 +84,13 @@ public class CloudEventBuilder<T> implements
|
|||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getDataschema().ifPresent((schema) -> {
|
||||
result.withDataschema(schema);
|
||||
});
|
||||
|
||||
attributes.getDatacontenttype().ifPresent(dc -> {
|
||||
result.withDataContentType(dc);
|
||||
});
|
||||
|
||||
attributes.getSubject().ifPresent(subject -> {
|
||||
result.withSubject(subject);
|
||||
});
|
||||
|
||||
attributes.getTime().ifPresent(time -> {
|
||||
result.withTime(time);
|
||||
});
|
||||
|
||||
Accessor.extensionsOf(base)
|
||||
.forEach(extension -> {
|
||||
result.withExtension(extension);
|
||||
});
|
||||
|
||||
base.getData().ifPresent(data -> {
|
||||
result.withData(data);
|
||||
});
|
||||
|
||||
attributes.getDataschema().ifPresent(result::withDataschema);
|
||||
attributes.getDatacontenttype().ifPresent(result::withDataContentType);
|
||||
attributes.getSubject().ifPresent(result::withSubject);
|
||||
attributes.getTime().ifPresent(result::withTime);
|
||||
Accessor.extensionsOf(base).forEach(result::withExtension);
|
||||
base.getData().ifPresent(result::withData);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -120,30 +104,16 @@ public class CloudEventBuilder<T> implements
|
|||
.withSource(attributes.getSource())
|
||||
.withType(attributes.getType());
|
||||
|
||||
attributes.getTime().ifPresent((time) -> {
|
||||
builder.withTime(time);
|
||||
});
|
||||
|
||||
attributes.getDataschema().ifPresent((dataschema) -> {
|
||||
builder.withDataschema(dataschema);
|
||||
});
|
||||
|
||||
attributes.getDatacontenttype().ifPresent((dct) -> {
|
||||
builder.withDataContentType(dct);
|
||||
});
|
||||
|
||||
attributes.getSubject().ifPresent((subject) -> {
|
||||
builder.withSubject(subject);
|
||||
});
|
||||
|
||||
extensions.stream()
|
||||
.forEach(extension -> {
|
||||
builder.withExtension(extension);
|
||||
});
|
||||
|
||||
builder.withData(data);
|
||||
|
||||
return builder.build();
|
||||
attributes.getTime().ifPresent(builder::withTime);
|
||||
attributes.getDataschema().ifPresent(builder::withDataschema);
|
||||
attributes.getDatacontenttype().ifPresent(builder::withDataContentType);
|
||||
attributes.getSubject().ifPresent(builder::withSubject);
|
||||
extensions.forEach(builder::withExtension);
|
||||
|
||||
return builder
|
||||
.withData(data)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -157,17 +127,19 @@ public class CloudEventBuilder<T> implements
|
|||
AttributesImpl attributes = new AttributesImpl(id, source, SPEC_VERSION, type,
|
||||
datacontenttype, dataschema, subject, time);
|
||||
|
||||
CloudEventImpl<T> cloudEvent =
|
||||
new CloudEventImpl<T>(attributes, data, extensions);
|
||||
CloudEventImpl<T> cloudEvent =
|
||||
new CloudEventImpl<>(attributes, data, extensions);
|
||||
|
||||
if(data instanceof byte[]) {
|
||||
cloudEvent.setDataBase64((byte[])data);
|
||||
}
|
||||
|
||||
if(validator == null) {
|
||||
validator = getValidator();
|
||||
}
|
||||
Set<ConstraintViolation<Object>> violations =
|
||||
getValidator().validate(cloudEvent);
|
||||
validator.validate(cloudEvent);
|
||||
|
||||
violations.addAll(getValidator().validate(cloudEvent.getAttributes()));
|
||||
violations.addAll(validator.validate(cloudEvent.getAttributes()));
|
||||
|
||||
final String errs =
|
||||
violations.stream()
|
||||
|
|
@ -231,4 +203,9 @@ public class CloudEventBuilder<T> implements
|
|||
this.extensions.add(extension);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CloudEventBuilder<T> withValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,7 +140,6 @@ public class CloudEventImpl<T> implements CloudEvent<AttributesImpl, T> {
|
|||
public static <T> CloudEventImpl<T> build(
|
||||
@JsonProperty("id") String id,
|
||||
@JsonProperty("source") URI source,
|
||||
@JsonProperty("specversion") String specversion,
|
||||
@JsonProperty("type") String type,
|
||||
@JsonProperty("datacontenttype") String datacontenttype,
|
||||
@JsonProperty("dataschema") URI dataschema,
|
||||
|
|
|
|||
|
|
@ -36,8 +36,7 @@ public enum ContextAttributes {
|
|||
time;
|
||||
|
||||
public static final List<String> VALUES =
|
||||
Arrays.asList(ContextAttributes.values())
|
||||
.stream()
|
||||
Arrays.stream(ContextAttributes.values())
|
||||
.map(Enum::name)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,7 @@ public class ExtensionMapper {
|
|||
.filter(header -> null!= header.getValue())
|
||||
.map(header -> new SimpleEntry<>(header.getKey()
|
||||
.toLowerCase(Locale.US), header.getValue().toString()))
|
||||
.filter(header -> {
|
||||
return !RESERVED_HEADERS.contains(header.getKey());
|
||||
})
|
||||
.filter(header -> !RESERVED_HEADERS.contains(header.getKey()))
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,14 +58,14 @@ public class HeaderMapper {
|
|||
.toLowerCase(Locale.US), header.getValue()))
|
||||
.filter(header -> !header.getKey()
|
||||
.equals(ContextAttributes.datacontenttype.name()))
|
||||
.map(header -> new SimpleEntry<>(HEADER_PREFIX+header.getKey(),
|
||||
.map(header -> new SimpleEntry<>(HEADER_PREFIX + header.getKey(),
|
||||
header.getValue()))
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
|
||||
|
||||
result.putAll(
|
||||
extensions.entrySet()
|
||||
.stream()
|
||||
.filter(extension -> null!= extension.getValue())
|
||||
.filter(extension -> null != extension.getValue())
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue))
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package io.cloudevents.v1.http;
|
||||
|
||||
import javax.validation.Validator;
|
||||
|
||||
import io.cloudevents.extensions.DistributedTracingExtension;
|
||||
import io.cloudevents.format.BinaryUnmarshaller;
|
||||
import io.cloudevents.format.StructuredUnmarshaller;
|
||||
|
|
@ -23,8 +25,6 @@ import io.cloudevents.json.Json;
|
|||
import io.cloudevents.v1.AttributesImpl;
|
||||
import io.cloudevents.v1.CloudEventBuilder;
|
||||
import io.cloudevents.v1.CloudEventImpl;
|
||||
import io.cloudevents.v1.http.AttributeMapper;
|
||||
import io.cloudevents.v1.http.ExtensionMapper;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -33,18 +33,33 @@ import io.cloudevents.v1.http.ExtensionMapper;
|
|||
*/
|
||||
public class Unmarshallers {
|
||||
private Unmarshallers() {}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param type The type reference to use for 'data' unmarshal
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see BinaryUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
binary(Class<T> type) {
|
||||
return binary(type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param type The type reference to use for 'data' unmarshal
|
||||
* @param validator Provided instance of a {@link Validator}
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see BinaryUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
binary(Class<T> type, Validator validator) {
|
||||
return
|
||||
BinaryUnmarshaller.<AttributesImpl, T, String>builder()
|
||||
.map(AttributeMapper::map)
|
||||
|
|
@ -54,7 +69,7 @@ public class Unmarshallers {
|
|||
.map(ExtensionMapper::map)
|
||||
.map(DistributedTracingExtension::unmarshall)
|
||||
.next()
|
||||
.builder(CloudEventBuilder.<T>builder()::build);
|
||||
.builder(CloudEventBuilder.<T>builder().withValidator(validator)::build);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -68,7 +83,21 @@ public class Unmarshallers {
|
|||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
structured(Class<T> typeOfData) {
|
||||
|
||||
return structured(typeOfData, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data
|
||||
* for HTTP Transport Binding
|
||||
*
|
||||
* @param <T> The 'data' type
|
||||
* @param typeOfData The type reference to use for 'data' unmarshal
|
||||
* @param validator Provided instance of a {@link Validator}
|
||||
* @return A step to supply the headers, payload and to unmarshal
|
||||
* @see StructuredUnmarshaller
|
||||
*/
|
||||
public static <T> HeadersStep<AttributesImpl, T, String>
|
||||
structured(Class<T> typeOfData, Validator validator) {
|
||||
return
|
||||
StructuredUnmarshaller.<AttributesImpl, T, String>
|
||||
builder()
|
||||
|
|
@ -86,8 +115,8 @@ public class Unmarshallers {
|
|||
extensions.get().forEach(extension -> {
|
||||
builder.withExtension(extension);
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
|
||||
return builder.withValidator(validator).build();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,10 +78,7 @@ public class StructuredMarshallerTest {
|
|||
|
||||
StructuredMarshaller.<Attributes, Much, String, String>builder()
|
||||
.mime("Content-Type", "application/cloudevents+json")
|
||||
.map((ce) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((ce) -> null)
|
||||
.skip()
|
||||
.withEvent(null);
|
||||
}
|
||||
|
|
@ -91,10 +88,7 @@ public class StructuredMarshallerTest {
|
|||
// act
|
||||
StructuredMarshaller.<Attributes, Much, String, String>builder()
|
||||
.mime("Content-Type", "application/cloudevents+json")
|
||||
.map((ce) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((ce) -> null)
|
||||
.skip()
|
||||
.withEvent(() -> null);
|
||||
}
|
||||
|
|
@ -106,10 +100,7 @@ public class StructuredMarshallerTest {
|
|||
|
||||
StructuredMarshaller.<Attributes, Much, String, String>builder()
|
||||
.mime("Content-Type", "application/cloudevents+json")
|
||||
.map((ce) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((ce) -> null)
|
||||
.map(null);
|
||||
}
|
||||
|
||||
|
|
@ -118,14 +109,8 @@ public class StructuredMarshallerTest {
|
|||
// act
|
||||
StructuredMarshaller.<Attributes, Much, String, String>builder()
|
||||
.mime("Content-Type", "application/cloudevents+json")
|
||||
.map((ce) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((event) -> {
|
||||
|
||||
return null;
|
||||
});
|
||||
.map((ce) -> null)
|
||||
.map((event) -> null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -135,14 +120,8 @@ public class StructuredMarshallerTest {
|
|||
|
||||
StructuredMarshaller.<Attributes, Much, String, String>builder()
|
||||
.mime("Content-Type", "application/cloudevents+json")
|
||||
.map((ce) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((event) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((ce) -> null)
|
||||
.map((event) -> null)
|
||||
.map(null);
|
||||
}
|
||||
|
||||
|
|
@ -150,18 +129,9 @@ public class StructuredMarshallerTest {
|
|||
public void should_ok_on_extension_marshaller() {
|
||||
StructuredMarshaller.<Attributes, Much, String, String>builder()
|
||||
.mime("Content-Type", "application/cloudevents+json")
|
||||
.map((ce) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((event) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((extensions) -> {
|
||||
|
||||
return null;
|
||||
});
|
||||
.map((ce) -> null)
|
||||
.map((event) -> null)
|
||||
.map((extensions) -> null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -171,18 +141,9 @@ public class StructuredMarshallerTest {
|
|||
|
||||
StructuredMarshaller.<Attributes, Much, String, String>builder()
|
||||
.mime("Content-Type", "application/cloudevents+json")
|
||||
.map((ce) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((event) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((extensions) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((ce) -> null)
|
||||
.map((event) -> null)
|
||||
.map((extensions) -> null)
|
||||
.map(null);
|
||||
}
|
||||
|
||||
|
|
@ -190,18 +151,9 @@ public class StructuredMarshallerTest {
|
|||
public void should_ok_on_header_mapper() {
|
||||
StructuredMarshaller.<Attributes, Much, String, String>builder()
|
||||
.mime("Content-Type", "application/cloudevents+json")
|
||||
.map((ce) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((event) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((extensions) -> {
|
||||
|
||||
return null;
|
||||
})
|
||||
.map((ce) -> null)
|
||||
.map((event) -> null)
|
||||
.map((extensions) -> null)
|
||||
.map((attributes, extensions) -> null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,15 @@ package io.cloudevents.v02;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.validation.Validator;
|
||||
|
||||
import io.cloudevents.validation.MockValidator;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
|
@ -318,4 +323,39 @@ public class CloudEventBuilderTest {
|
|||
assertEquals(expected, actual.getData().get());
|
||||
assertEquals("0x010", actual.getAttributes().getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_build_event_using_custom_validator() {
|
||||
Validator validator = new MockValidator();
|
||||
String expected = "test";
|
||||
|
||||
CloudEventImpl<String> event = CloudEventBuilder
|
||||
.<String>builder()
|
||||
.withData(expected)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
|
||||
assertNotNull(event);
|
||||
assertEquals(expected, event.getData().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_build_event_from_event_using_custom_validator() {
|
||||
Validator validator = new MockValidator();
|
||||
String expected = "test";
|
||||
CloudEvent<AttributesImpl, String> event = CloudEventBuilder.of(
|
||||
expected,
|
||||
new AttributesImpl(null, null, null, null, null, null, null),
|
||||
Collections.emptyList(),
|
||||
validator
|
||||
);
|
||||
|
||||
CloudEvent<AttributesImpl, String> result = CloudEventBuilder
|
||||
.builder(event)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(expected, result.getData().get());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import javax.validation.ValidatorFactory;
|
|||
import javax.validation.executable.ExecutableValidator;
|
||||
import javax.validation.metadata.BeanDescriptor;
|
||||
|
||||
import io.cloudevents.validation.MockValidator;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
|
@ -217,33 +218,15 @@ public class CloudEventBuilderTest {
|
|||
assertTrue(actual instanceof String);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_copy_event_using_custom_validator() {
|
||||
Validator validator = new MockValidator();
|
||||
String expected = "test";
|
||||
CloudEvent<AttributesImpl, String> event = CloudEventBuilder.<String>of(
|
||||
expected,
|
||||
new AttributesImpl(null, null, null, null, null, null, null, null, null),
|
||||
Collections.emptyList(),
|
||||
validator
|
||||
);
|
||||
|
||||
try {
|
||||
CloudEventBuilder.<String>builder().build();
|
||||
fail("Expected validation error");
|
||||
} catch (IllegalStateException e) {
|
||||
assertNotNull(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_build_event_using_custom_validator() {
|
||||
Validator validator = new MockValidator();
|
||||
String expected = "test";
|
||||
|
||||
CloudEventImpl<String> event = CloudEventBuilder
|
||||
.<String>builder(validator)
|
||||
.<String>builder()
|
||||
.withData(expected)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
|
||||
assertNotNull(event);
|
||||
|
|
@ -262,43 +245,11 @@ public class CloudEventBuilderTest {
|
|||
);
|
||||
|
||||
CloudEvent<AttributesImpl, String> result = CloudEventBuilder
|
||||
.<String>builder(event, validator)
|
||||
.builder(event)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(expected, result.getData().get());
|
||||
}
|
||||
|
||||
private static class MockValidator implements Validator {
|
||||
|
||||
@Override
|
||||
public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDescriptor getConstraintsForClass(Class<?> clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutableValidator forExecutables() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,14 @@ package io.cloudevents.v1;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.validation.Validator;
|
||||
|
||||
import io.cloudevents.validation.MockValidator;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
|
@ -191,4 +196,37 @@ public class CloudEventBuilderTest {
|
|||
assertNotNull(actual);
|
||||
assertTrue(actual instanceof String);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_build_event_using_custom_validator() {
|
||||
Validator validator = new MockValidator();
|
||||
String expected = "test";
|
||||
|
||||
CloudEventImpl<String> event = CloudEventBuilder
|
||||
.<String>builder()
|
||||
.withData(expected)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
|
||||
assertNotNull(event);
|
||||
assertEquals(expected, event.getData().get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_build_event_from_event_using_custom_validator() {
|
||||
Validator validator = new MockValidator();
|
||||
String expected = "test";
|
||||
CloudEvent<AttributesImpl, String> event = CloudEventBuilder.<String>builder()
|
||||
.withData(expected)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
|
||||
CloudEvent<AttributesImpl, String> result = CloudEventBuilder
|
||||
.builder(event)
|
||||
.withValidator(validator)
|
||||
.build();
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(expected, result.getData().get());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package io.cloudevents.validation;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.executable.ExecutableValidator;
|
||||
import javax.validation.metadata.BeanDescriptor;
|
||||
|
||||
public class MockValidator implements Validator {
|
||||
|
||||
@Override
|
||||
public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDescriptor getConstraintsForClass(Class<?> clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutableValidator forExecutables() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue