Change canonical format of Cloud Event Message attributes to have 'ce-' prefix

This commit is contained in:
Oleg Zhurakousky
2020-12-02 11:24:03 +01:00
parent 0cdcc46f57
commit 523cd1023f
6 changed files with 108 additions and 102 deletions

View File

@@ -29,6 +29,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.GenericMessage; import org.springframework.messaging.support.GenericMessage;
import org.springframework.util.StringUtils;
/** /**
* Message builder which is aware of Cloud Event semantics. * Message builder which is aware of Cloud Event semantics.
@@ -145,16 +146,33 @@ public final class CloudEventMessageBuilder<T> {
return this.doBuild(); return this.doBuild();
} }
public Message<T> build(String attributePrefixToUse) { public Message<T> build(String attributePrefixToUse) {
String[] keys = this.headers.keySet().toArray(new String[] {}); if (StringUtils.hasText(attributePrefixToUse)) {
for (String key : keys) { String[] keys = this.headers.keySet().toArray(new String[] {});
Object value = this.headers.remove(key); for (String key : keys) {
this.headers.put(attributePrefixToUse + key, value); if (key.startsWith(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX)) {
Object value = headers.remove(key);
key = key.substring(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX.length());
headers.put(attributePrefixToUse + key, value);
}
else if (key.startsWith(CloudEventMessageUtils.AMQP_ATTR_PREFIX)) {
Object value = headers.remove(key);
key = key.substring(CloudEventMessageUtils.AMQP_ATTR_PREFIX.length());
headers.put(attributePrefixToUse + key, value);
}
else if (key.startsWith(CloudEventMessageUtils.KAFKA_ATTR_PREFIX)) {
Object value = headers.remove(key);
key = key.substring(CloudEventMessageUtils.KAFKA_ATTR_PREFIX.length());
headers.put(attributePrefixToUse + key, value);
}
}
} }
if (!this.headers.containsKey(attributePrefixToUse + CloudEventMessageUtils.SPECVERSION)) { if (!this.headers.containsKey(attributePrefixToUse + CloudEventMessageUtils.SPECVERSION)) {
this.headers.put(attributePrefixToUse + CloudEventMessageUtils.SPECVERSION, "1.0"); this.headers.put(attributePrefixToUse + CloudEventMessageUtils.SPECVERSION, "1.0");
} }
return build(); return doBuild();
} }
private Message<T> doBuild() { private Message<T> doBuild() {

View File

@@ -21,7 +21,6 @@ import java.net.URI;
import java.time.OffsetTime; import java.time.OffsetTime;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.MessageHeaders;
@@ -48,8 +47,13 @@ public final class CloudEventMessageUtils {
private static final ContentTypeResolver contentTypeResolver = new DefaultContentTypeResolver(); private static final ContentTypeResolver contentTypeResolver = new DefaultContentTypeResolver();
private CloudEventMessageUtils() { private static Field MESSAGE_HEADERS = ReflectionUtils.findField(MessageHeaders.class, "headers");
static {
MESSAGE_HEADERS.setAccessible(true);
}
private CloudEventMessageUtils() {
} }
/** /**
@@ -65,7 +69,7 @@ public final class CloudEventMessageUtils {
/** /**
* Prefix for attributes. * Prefix for attributes.
*/ */
public static String DEFAULT_ATTR_PREFIX = "ce_"; public static String DEFAULT_ATTR_PREFIX = "ce-";
/** /**
* AMQP attributes prefix. * AMQP attributes prefix.
@@ -75,57 +79,57 @@ public final class CloudEventMessageUtils {
/** /**
* Prefix for attributes. * Prefix for attributes.
*/ */
public static String HTTP_ATTR_PREFIX = "ce-"; public static String KAFKA_ATTR_PREFIX = "ce_";
/** /**
* Value for 'data' attribute. * Value for 'data' attribute.
*/ */
public static String DATA = "data"; public static String DATA = DEFAULT_ATTR_PREFIX + "data";
/** /**
* Value for 'id' attribute. * Value for 'id' attribute.
*/ */
public static String ID = "id"; public static String ID = DEFAULT_ATTR_PREFIX + "id";
/** /**
* Value for 'source' attribute. * Value for 'source' attribute.
*/ */
public static String SOURCE = "source"; public static String SOURCE = DEFAULT_ATTR_PREFIX + "source";
/** /**
* Value for 'specversion' attribute. * Value for 'specversion' attribute.
*/ */
public static String SPECVERSION = "specversion"; public static String SPECVERSION = DEFAULT_ATTR_PREFIX + "specversion";
/** /**
* Value for 'type' attribute. * Value for 'type' attribute.
*/ */
public static String TYPE = "type"; public static String TYPE = DEFAULT_ATTR_PREFIX + "type";
/** /**
* Value for 'datacontenttype' attribute. * Value for 'datacontenttype' attribute.
*/ */
public static String DATACONTENTTYPE = "datacontenttype"; public static String DATACONTENTTYPE = DEFAULT_ATTR_PREFIX + "datacontenttype";
/** /**
* Value for 'dataschema' attribute. * Value for 'dataschema' attribute.
*/ */
public static String DATASCHEMA = "dataschema"; public static String DATASCHEMA = DEFAULT_ATTR_PREFIX + "dataschema";
/** /**
* V03 name for 'dataschema' attribute. * V03 name for 'dataschema' attribute.
*/ */
public static final String SCHEMAURL = "schemaurl"; public static final String SCHEMAURL = DEFAULT_ATTR_PREFIX + "schemaurl";
/** /**
* Value for 'subject' attribute. * Value for 'subject' attribute.
*/ */
public static String SUBJECT = "subject"; public static String SUBJECT = DEFAULT_ATTR_PREFIX + "subject";
/** /**
* Value for 'time' attribute. * Value for 'time' attribute.
*/ */
public static String TIME = "time"; public static String TIME = DEFAULT_ATTR_PREFIX + "time";
public static String getId(Message<?> message) { public static String getId(Message<?> message) {
if (message.getHeaders().containsKey("_id")) { if (message.getHeaders().containsKey("_id")) {
@@ -171,16 +175,13 @@ public final class CloudEventMessageUtils {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected static Message<?> toCannonical(Message<?> inputMessage, MessageConverter messageConverter) { protected static Message<?> toCanonical(Message<?> inputMessage, MessageConverter messageConverter) {
Map<String, Object> headers = (Map<String, Object>) ReflectionUtils.getField(MESSAGE_HEADERS, inputMessage.getHeaders());
Field headersField = ReflectionUtils.findField(MessageHeaders.class, "headers"); canonicalizeHeaders(headers, false);
headersField.setAccessible(true);
Map<String, Object> headers = (Map<String, Object>) ReflectionUtils.getField(headersField, inputMessage.getHeaders());
canonicalizeHeaders(headers);
String inputContentType = (String) inputMessage.getHeaders().get(DATACONTENTTYPE); String inputContentType = (String) inputMessage.getHeaders().get(DATACONTENTTYPE);
// first check the obvious and see if content-type is `cloudevents` // first check the obvious and see if content-type is `cloudevents`
if (!isBinary(inputMessage) && headers.containsKey(MessageHeaders.CONTENT_TYPE)) { if (!isCloudEvent(inputMessage) && headers.containsKey(MessageHeaders.CONTENT_TYPE)) {
MimeType contentType = contentTypeResolver.resolve(inputMessage.getHeaders()); MimeType contentType = contentTypeResolver.resolve(inputMessage.getHeaders());
if (contentType.getType().equals(APPLICATION_CLOUDEVENTS.getType()) && contentType if (contentType.getType().equals(APPLICATION_CLOUDEVENTS.getType()) && contentType
.getSubtype().startsWith(APPLICATION_CLOUDEVENTS.getSubtype())) { .getSubtype().startsWith(APPLICATION_CLOUDEVENTS.getSubtype())) {
@@ -197,7 +198,7 @@ public final class CloudEventMessageUtils {
Map<String, Object> structuredCloudEvent = (Map<String, Object>) messageConverter Map<String, Object> structuredCloudEvent = (Map<String, Object>) messageConverter
.fromMessage(cloudEventMessage, Map.class); .fromMessage(cloudEventMessage, Map.class);
canonicalizeHeaders(structuredCloudEvent); canonicalizeHeaders(structuredCloudEvent, true);
Message<?> binaryCeMessage = buildBinaryMessageFromStructuredMap(structuredCloudEvent, Message<?> binaryCeMessage = buildBinaryMessageFromStructuredMap(structuredCloudEvent,
inputMessage.getHeaders()); inputMessage.getHeaders());
@@ -221,30 +222,14 @@ public final class CloudEventMessageUtils {
* @return prefix (e.g., 'ce_' or 'ce-' etc.) * @return prefix (e.g., 'ce_' or 'ce-' etc.)
*/ */
protected static String determinePrefixToUse(Map<String, Object> messageHeaders) { protected static String determinePrefixToUse(Map<String, Object> messageHeaders) {
Set<String> keys = messageHeaders.keySet(); for (String key : messageHeaders.keySet()) {
if (keys.contains("user-agent")) { if (key.startsWith(KAFKA_ATTR_PREFIX)) {
return HTTP_ATTR_PREFIX; return KAFKA_ATTR_PREFIX;
} }
else { else if (key.startsWith(AMQP_ATTR_PREFIX)) {
for (String key : messageHeaders.keySet()) { return AMQP_ATTR_PREFIX;
if (key.startsWith("kafka_")) {
return DEFAULT_ATTR_PREFIX;
}
else if (key.startsWith("amqp_")) {
return AMQP_ATTR_PREFIX;
}
else if (key.startsWith(DEFAULT_ATTR_PREFIX)) {
return DEFAULT_ATTR_PREFIX;
}
else if (key.startsWith(HTTP_ATTR_PREFIX)) {
return HTTP_ATTR_PREFIX;
}
else if (key.startsWith(AMQP_ATTR_PREFIX)) {
return AMQP_ATTR_PREFIX;
}
} }
} }
return ""; return "";
} }
@@ -254,7 +239,7 @@ public final class CloudEventMessageUtils {
* @param message input {@link Message} * @param message input {@link Message}
* @return true if this Message represents Cloud Event in binary-mode * @return true if this Message represents Cloud Event in binary-mode
*/ */
protected static boolean isBinary(Message<?> message) { protected static boolean isCloudEvent(Message<?> message) {
return message.getHeaders().containsKey(SPECVERSION) return message.getHeaders().containsKey(SPECVERSION)
&& message.getHeaders().containsKey(TYPE) && message.getHeaders().containsKey(TYPE)
&& message.getHeaders().containsKey(SOURCE); && message.getHeaders().containsKey(SOURCE);
@@ -265,23 +250,27 @@ public final class CloudEventMessageUtils {
* So, for example 'ce_source' will become 'source'. * So, for example 'ce_source' will become 'source'.
* @param headers message headers * @param headers message headers
*/ */
private static void canonicalizeHeaders(Map<String, Object> headers) { private static void canonicalizeHeaders(Map<String, Object> headers, boolean structured) {
String[] keys = headers.keySet().toArray(new String[] {}); String[] keys = headers.keySet().toArray(new String[] {});
for (String key : keys) { for (String key : keys) {
if (key.startsWith(HTTP_ATTR_PREFIX)) { if (key.startsWith(DEFAULT_ATTR_PREFIX)) {
Object value = headers.remove(key);
key = key.substring(HTTP_ATTR_PREFIX.length());
headers.put(key, value);
}
else if (key.startsWith(DEFAULT_ATTR_PREFIX)) {
Object value = headers.remove(key); Object value = headers.remove(key);
key = key.substring(DEFAULT_ATTR_PREFIX.length()); key = key.substring(DEFAULT_ATTR_PREFIX.length());
headers.put(key, value); headers.put(DEFAULT_ATTR_PREFIX + key, value);
}
else if (key.startsWith(KAFKA_ATTR_PREFIX)) {
Object value = headers.remove(key);
key = key.substring(KAFKA_ATTR_PREFIX.length());
headers.put(DEFAULT_ATTR_PREFIX + key, value);
} }
else if (key.startsWith(AMQP_ATTR_PREFIX)) { else if (key.startsWith(AMQP_ATTR_PREFIX)) {
Object value = headers.remove(key); Object value = headers.remove(key);
key = key.substring(AMQP_ATTR_PREFIX.length()); key = key.substring(AMQP_ATTR_PREFIX.length());
headers.put(key, value); headers.put(DEFAULT_ATTR_PREFIX + key, value);
}
else if (structured) {
Object value = headers.remove(key);
headers.put(DEFAULT_ATTR_PREFIX + key, value);
} }
} }
} }

View File

@@ -57,13 +57,13 @@ class CloudEventsFunctionInvocationHelper implements FunctionInvocationHelper<Me
@Override @Override
public Message<?> preProcessInput(Message<?> input, Object inputConverter) { public Message<?> preProcessInput(Message<?> input, Object inputConverter) {
return CloudEventMessageUtils.toCannonical(input, (MessageConverter) inputConverter); return CloudEventMessageUtils.toCanonical(input, (MessageConverter) inputConverter);
} }
@Override @Override
public Message<?> postProcessResult(Message<?> input, Object result) { public Message<?> postProcessResult(Message<?> input, Object result) {
Message<?> resultMessage = null; Message<?> resultMessage = null;
if (CloudEventMessageUtils.isBinary(input)) { if (CloudEventMessageUtils.isCloudEvent(input)) {
CloudEventMessageBuilder<?> messageBuilder = CloudEventMessageBuilder CloudEventMessageBuilder<?> messageBuilder = CloudEventMessageBuilder
.withData(result) .withData(result)
.setId(UUID.randomUUID().toString()) .setId(UUID.randomUUID().toString())
@@ -75,6 +75,7 @@ class CloudEventsFunctionInvocationHelper implements FunctionInvocationHelper<Me
} }
String prefix = this.determineOutputPrefix(input); String prefix = this.determineOutputPrefix(input);
resultMessage = messageBuilder.build(prefix); resultMessage = messageBuilder.build(prefix);
} }
else { else {

View File

@@ -31,6 +31,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@@ -56,7 +57,7 @@ public class CloudEventFunctionTests {
.build(); .build();
assertThat(inputMessage.getHeaders().getId()).isEqualTo(UUID.fromString(id)); assertThat(inputMessage.getHeaders().getId()).isEqualTo(UUID.fromString(id));
assertThat(CloudEventMessageUtils.isBinary(inputMessage)).isTrue(); assertThat(CloudEventMessageUtils.isCloudEvent(inputMessage)).isTrue();
Message<Person> resultMessage = (Message<Person>) function.apply(inputMessage); Message<Person> resultMessage = (Message<Person>) function.apply(inputMessage);
@@ -66,7 +67,7 @@ public class CloudEventFunctionTests {
* both on input and output that it is dealing with Cloud Event and generates * both on input and output that it is dealing with Cloud Event and generates
* appropriate headers/attributes * appropriate headers/attributes
*/ */
assertThat(CloudEventMessageUtils.isBinary(resultMessage)).isTrue(); assertThat(CloudEventMessageUtils.isCloudEvent(resultMessage)).isTrue();
assertThat(CloudEventMessageUtils.getType(resultMessage)).isEqualTo(Person.class.getName()); assertThat(CloudEventMessageUtils.getType(resultMessage)).isEqualTo(Person.class.getName());
assertThat(CloudEventMessageUtils.getSource(resultMessage)).isEqualTo(URI.create("http://spring.io/application-application")); assertThat(CloudEventMessageUtils.getSource(resultMessage)).isEqualTo(URI.create("http://spring.io/application-application"));
} }
@@ -95,7 +96,7 @@ public class CloudEventFunctionTests {
* both on input and output that it is dealing with Cloud Event and generates * both on input and output that it is dealing with Cloud Event and generates
* appropriate headers/attributes * appropriate headers/attributes
*/ */
assertThat(CloudEventMessageUtils.isBinary(resultMessage)).isTrue(); assertThat(CloudEventMessageUtils.isCloudEvent(resultMessage)).isTrue();
assertThat(CloudEventMessageUtils.getType(resultMessage)).isEqualTo(Person.class.getName()); assertThat(CloudEventMessageUtils.getType(resultMessage)).isEqualTo(Person.class.getName());
assertThat(CloudEventMessageUtils.getSource(resultMessage)).isEqualTo(URI.create("http://spring.io/application-application")); assertThat(CloudEventMessageUtils.getSource(resultMessage)).isEqualTo(URI.create("http://spring.io/application-application"));
} }
@@ -117,12 +118,12 @@ public class CloudEventFunctionTests {
"}"; "}";
Function<Object, Object> function = this.lookup("springRelease", TestConfiguration.class); Function<Object, Object> function = this.lookup("springRelease", TestConfiguration.class);
Message<String> inputMessage = CloudEventMessageBuilder Message<String> inputMessage = MessageBuilder
.withData(payload) .withPayload(payload)
.setHeader(MessageHeaders.CONTENT_TYPE, CloudEventMessageUtils.APPLICATION_CLOUDEVENTS_VALUE + "+json") .setHeader(MessageHeaders.CONTENT_TYPE, CloudEventMessageUtils.APPLICATION_CLOUDEVENTS_VALUE + "+json")
.build(); .build();
assertThat(CloudEventMessageUtils.isBinary(inputMessage)).isFalse(); assertThat(CloudEventMessageUtils.isCloudEvent(inputMessage)).isFalse();
Message<SpringReleaseEvent> resultMessage = (Message<SpringReleaseEvent>) function.apply(inputMessage); Message<SpringReleaseEvent> resultMessage = (Message<SpringReleaseEvent>) function.apply(inputMessage);
assertThat(resultMessage.getPayload().getReleaseDate()) assertThat(resultMessage.getPayload().getReleaseDate())
@@ -133,7 +134,7 @@ public class CloudEventFunctionTests {
// * both on input and output that it is dealing with Cloud Event and generates // * both on input and output that it is dealing with Cloud Event and generates
// * appropriate headers/attributes // * appropriate headers/attributes
// */ // */
assertThat(CloudEventMessageUtils.isBinary(resultMessage)).isTrue(); assertThat(CloudEventMessageUtils.isCloudEvent(resultMessage)).isTrue();
assertThat(CloudEventMessageUtils.getType(resultMessage)).isEqualTo(SpringReleaseEvent.class.getName()); assertThat(CloudEventMessageUtils.getType(resultMessage)).isEqualTo(SpringReleaseEvent.class.getName());
assertThat(CloudEventMessageUtils.getSource(resultMessage)).isEqualTo(URI.create("http://spring.io/application-application")); assertThat(CloudEventMessageUtils.getSource(resultMessage)).isEqualTo(URI.create("http://spring.io/application-application"));
} }
@@ -158,7 +159,7 @@ public class CloudEventFunctionTests {
.withData(payload) .withData(payload)
.setHeader(MessageHeaders.CONTENT_TYPE, CloudEventMessageUtils.APPLICATION_CLOUDEVENTS_VALUE + "+json") .setHeader(MessageHeaders.CONTENT_TYPE, CloudEventMessageUtils.APPLICATION_CLOUDEVENTS_VALUE + "+json")
.build(); .build();
assertThat(CloudEventMessageUtils.isBinary(inputMessage)).isFalse(); assertThat(CloudEventMessageUtils.isCloudEvent(inputMessage)).isFalse();
Message<SpringReleaseEvent> resultMessage = (Message<SpringReleaseEvent>) function.apply(inputMessage); Message<SpringReleaseEvent> resultMessage = (Message<SpringReleaseEvent>) function.apply(inputMessage);
assertThat(resultMessage.getPayload().getReleaseDate()) assertThat(resultMessage.getPayload().getReleaseDate())
@@ -169,7 +170,7 @@ public class CloudEventFunctionTests {
* both on input and output that it is dealing with Cloud Event and generates * both on input and output that it is dealing with Cloud Event and generates
* appropriate headers/attributes * appropriate headers/attributes
*/ */
assertThat(CloudEventMessageUtils.isBinary(resultMessage)).isTrue(); assertThat(CloudEventMessageUtils.isCloudEvent(resultMessage)).isTrue();
assertThat(CloudEventMessageUtils.getType(resultMessage)).isEqualTo(SpringReleaseEvent.class.getName()); assertThat(CloudEventMessageUtils.getType(resultMessage)).isEqualTo(SpringReleaseEvent.class.getName());
assertThat(CloudEventMessageUtils.getSource(resultMessage)).isEqualTo(URI.create("http://spring.io/application-application")); assertThat(CloudEventMessageUtils.getSource(resultMessage)).isEqualTo(URI.create("http://spring.io/application-application"));
} }

View File

@@ -131,7 +131,7 @@ public class CloudeventDemoApplication {
@Bean @Bean
public Consumer<Message<SpringReleaseEvent>> pojoConsumer(CloudEventHeaderEnricher enricher, RestTemplateBuilder builder) { public Consumer<Message<SpringReleaseEvent>> pojoConsumer(CloudEventHeaderEnricher enricher, RestTemplateBuilder builder) {
return eventMessage -> { return eventMessage -> {
Message<?> newMessage = enricher.enrich(CloudEventMessageBuilder.fromMessage(eventMessage)).build(CloudEventMessageUtils.HTTP_ATTR_PREFIX); Message<?> newMessage = enricher.enrich(CloudEventMessageBuilder.fromMessage(eventMessage)).build(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX);
RequestEntity<SpringReleaseEvent> entity = RequestEntity.post(URI.create("http://foo.com")) RequestEntity<SpringReleaseEvent> entity = RequestEntity.post(URI.create("http://foo.com"))
.headers(HeaderUtils.fromMessage(newMessage.getHeaders())) .headers(HeaderUtils.fromMessage(newMessage.getHeaders()))
.body(eventMessage.getPayload()); .body(eventMessage.getPayload());

View File

@@ -130,7 +130,7 @@ public class CloudeventDemoApplicationRESTTests {
SpringApplication.run(new Class[] {CloudeventDemoApplication.class, FooBarConverterConfiguration.class}, new String[] {}); SpringApplication.run(new Class[] {CloudeventDemoApplication.class, FooBarConverterConfiguration.class}, new String[] {});
HttpHeaders headers = this.buildHeaders(MediaType.valueOf("application/cloudevents+json;charset=utf-8")); HttpHeaders headers = this.buildHeaders(MediaType.valueOf("application/cloudevents+json;charset=utf-8"));
headers.set("datacontenttype", "foo/bar"); headers.set(CloudEventMessageUtils.DATACONTENTTYPE, "foo/bar");
String payload = "24-03-2004:Spring Framework:1.0"; String payload = "24-03-2004:Spring Framework:1.0";
RequestEntity<String> re = new RequestEntity<>(payload, headers, HttpMethod.POST, this.constructURI("/asPOJOMessage")); RequestEntity<String> re = new RequestEntity<>(payload, headers, HttpMethod.POST, this.constructURI("/asPOJOMessage"));
@@ -171,11 +171,11 @@ public class CloudeventDemoApplicationRESTTests {
response = testRestTemplate.exchange(re, String.class); response = testRestTemplate.exchange(re, String.class);
assertThat(response.getBody()).isEqualTo("releaseDate:24-03-2004; releaseName:Spring Framework; version:1.0"); assertThat(response.getBody()).isEqualTo("releaseDate:24-03-2004; releaseName:Spring Framework; version:1.0");
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.SOURCE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.SOURCE))
.isEqualTo(Collections.singletonList("https://interface21.com/")); .isEqualTo(Collections.singletonList("https://interface21.com/"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.TYPE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.TYPE))
.isEqualTo(Collections.singletonList("com.interface21")); .isEqualTo(Collections.singletonList("com.interface21"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.ID)).isNotNull(); assertThat(response.getHeaders().get(CloudEventMessageUtils.ID)).isNotNull();
} }
@Test @Test
@@ -207,11 +207,11 @@ public class CloudeventDemoApplicationRESTTests {
response = testRestTemplate.exchange(re, String.class); response = testRestTemplate.exchange(re, String.class);
assertThat(response.getBody()).isEqualTo("{\"version\":\"1.0\",\"releaseName\":\"Spring Framework\",\"releaseDate\":\"24-03-2004\"}"); assertThat(response.getBody()).isEqualTo("{\"version\":\"1.0\",\"releaseName\":\"Spring Framework\",\"releaseDate\":\"24-03-2004\"}");
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.SOURCE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.SOURCE))
.isEqualTo(Collections.singletonList("https://interface21.com/")); .isEqualTo(Collections.singletonList("https://interface21.com/"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.TYPE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.TYPE))
.isEqualTo(Collections.singletonList("com.interface21")); .isEqualTo(Collections.singletonList("com.interface21"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.ID)).isNotNull(); assertThat(response.getHeaders().get(CloudEventMessageUtils.ID)).isNotNull();
} }
@Test @Test
@@ -225,9 +225,9 @@ public class CloudeventDemoApplicationRESTTests {
ResponseEntity<String> response = testRestTemplate.exchange(re, String.class); ResponseEntity<String> response = testRestTemplate.exchange(re, String.class);
assertThat(response.getBody()).isEqualTo("{\"releaseDate\":\"01-10-2050\",\"releaseName\":\"Spring Framework\",\"version\":\"10.0\"}"); assertThat(response.getBody()).isEqualTo("{\"releaseDate\":\"01-10-2050\",\"releaseName\":\"Spring Framework\",\"version\":\"10.0\"}");
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.SOURCE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.SOURCE))
.isEqualTo(Collections.singletonList("https://interface21.com/")); .isEqualTo(Collections.singletonList("https://interface21.com/"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.TYPE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.TYPE))
.isEqualTo(Collections.singletonList("com.interface21")); .isEqualTo(Collections.singletonList("com.interface21"));
} }
@@ -242,9 +242,9 @@ public class CloudeventDemoApplicationRESTTests {
ResponseEntity<String> response = testRestTemplate.exchange(re, String.class); ResponseEntity<String> response = testRestTemplate.exchange(re, String.class);
assertThat(response.getBody()).isEqualTo("{\"releaseDate\":\"01-10-2006\",\"releaseName\":\"Spring Framework\",\"version\":\"2.0\"}"); assertThat(response.getBody()).isEqualTo("{\"releaseDate\":\"01-10-2006\",\"releaseName\":\"Spring Framework\",\"version\":\"2.0\"}");
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.SOURCE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.SOURCE))
.isEqualTo(Collections.singletonList("https://interface21.com/")); .isEqualTo(Collections.singletonList("https://interface21.com/"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.TYPE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.TYPE))
.isEqualTo(Collections.singletonList("com.interface21")); .isEqualTo(Collections.singletonList("com.interface21"));
} }
@@ -259,24 +259,20 @@ public class CloudeventDemoApplicationRESTTests {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON); headers.setContentType(MediaType.APPLICATION_JSON);
headers.set(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX + CloudEventMessageUtils.ID, UUID.randomUUID().toString()); headers.set(CloudEventMessageUtils.ID, UUID.randomUUID().toString());
headers.set(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX + CloudEventMessageUtils.SOURCE, "https://spring.io/"); headers.set(CloudEventMessageUtils.SOURCE, "https://spring.io/");
headers.set(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX + CloudEventMessageUtils.SPECVERSION, "1.0"); headers.set(CloudEventMessageUtils.SPECVERSION, "1.0");
headers.set(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX + CloudEventMessageUtils.TYPE, "org.springframework"); headers.set(CloudEventMessageUtils.TYPE, "org.springframework");
String payload = "{\"releaseDate\":\"01-10-2006\", \"releaseName\":\"Spring Framework\", \"version\":\"1.0\"}"; String payload = "{\"releaseDate\":\"01-10-2006\", \"releaseName\":\"Spring Framework\", \"version\":\"1.0\"}";
RequestEntity<String> re = new RequestEntity<>(payload, headers, HttpMethod.POST, this.constructURI("/consumeAndProduceCloudEventAsPojoToPojo")); RequestEntity<String> re = new RequestEntity<>(payload, headers, HttpMethod.POST, this.constructURI("/consumeAndProduceCloudEventAsPojoToPojo"));
ResponseEntity<String> response = testRestTemplate.exchange(re, String.class); ResponseEntity<String> response = testRestTemplate.exchange(re, String.class);
assertThat(response.getBody()).isEqualTo("{\"releaseDate\":\"01-10-2006\",\"releaseName\":\"Spring Framework\",\"version\":\"2.0\"}"); assertThat(response.getBody()).isEqualTo("{\"releaseDate\":\"01-10-2006\",\"releaseName\":\"Spring Framework\",\"version\":\"2.0\"}");
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.SOURCE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.SOURCE))
.isEqualTo(Collections.singletonList("https://interface21.com/")); .isEqualTo(Collections.singletonList("https://interface21.com/"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.TYPE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.TYPE))
.isEqualTo(Collections.singletonList("com.interface21")); .isEqualTo(Collections.singletonList("com.interface21"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX + CloudEventMessageUtils.TYPE)).isNull();
assertThat(response.getHeaders().get(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX + CloudEventMessageUtils.SOURCE)).isNull();
assertThat(response.getHeaders().get(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX + CloudEventMessageUtils.ID)).isNull();
assertThat(response.getHeaders().get(CloudEventMessageUtils.DEFAULT_ATTR_PREFIX + CloudEventMessageUtils.SPECVERSION)).isNull();
} }
@@ -317,11 +313,11 @@ public class CloudeventDemoApplicationRESTTests {
assertThat(springReleaseEvent.getReleaseName()).isEqualTo("Spring Framework"); assertThat(springReleaseEvent.getReleaseName()).isEqualTo("Spring Framework");
assertThat(springReleaseEvent.getVersion()).isEqualTo("10.0"); assertThat(springReleaseEvent.getVersion()).isEqualTo("10.0");
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.SOURCE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.SOURCE))
.isEqualTo(Collections.singletonList("https://interface21.com/")); .isEqualTo(Collections.singletonList("https://interface21.com/"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.TYPE)) assertThat(response.getHeaders().get(CloudEventMessageUtils.TYPE))
.isEqualTo(Collections.singletonList("com.interface21")); .isEqualTo(Collections.singletonList("com.interface21"));
assertThat(response.getHeaders().get(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.ID)).isNotNull(); assertThat(response.getHeaders().get(CloudEventMessageUtils.ID)).isNotNull();
} }
@Test @Test
@@ -345,10 +341,10 @@ public class CloudeventDemoApplicationRESTTests {
private HttpHeaders buildHeaders(MediaType contentType) { private HttpHeaders buildHeaders(MediaType contentType) {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(contentType); headers.setContentType(contentType);
headers.set(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.ID, UUID.randomUUID().toString()); headers.set(CloudEventMessageUtils.ID, UUID.randomUUID().toString());
headers.set(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.SOURCE, "https://spring.io/"); headers.set(CloudEventMessageUtils.SOURCE, "https://spring.io/");
headers.set(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.SPECVERSION, "1.0"); headers.set(CloudEventMessageUtils.SPECVERSION, "1.0");
headers.set(CloudEventMessageUtils.HTTP_ATTR_PREFIX + CloudEventMessageUtils.TYPE, "org.springframework"); headers.set(CloudEventMessageUtils.TYPE, "org.springframework");
return headers; return headers;
} }
@@ -383,7 +379,8 @@ public class CloudeventDemoApplicationRESTTests {
if (targetClass == null || !supportsMimeType(message.getHeaders())) { if (targetClass == null || !supportsMimeType(message.getHeaders())) {
return false; return false;
} }
else if (message.getHeaders().containsKey("datacontenttype") && message.getHeaders().get("datacontenttype").equals("foo/bar")) { else if (message.getHeaders().containsKey(CloudEventMessageUtils.DATACONTENTTYPE)
&& message.getHeaders().get(CloudEventMessageUtils.DATACONTENTTYPE).equals("foo/bar")) {
return true; return true;
} }
return false; return false;
@@ -391,8 +388,8 @@ public class CloudeventDemoApplicationRESTTests {
@Override @Override
protected Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) { protected Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) {
if (message.getHeaders().containsKey("datacontenttype") if (message.getHeaders().containsKey(CloudEventMessageUtils.DATACONTENTTYPE)
&& message.getHeaders().get("datacontenttype").equals("foo/bar") && message.getHeaders().get(CloudEventMessageUtils.DATACONTENTTYPE).equals("foo/bar")
&& SpringReleaseEvent.class == targetClass) { && SpringReleaseEvent.class == targetClass) {
SpringReleaseEvent event = new SpringReleaseEvent(); SpringReleaseEvent event = new SpringReleaseEvent();
String[] data = ((String) message.getPayload()).split(":"); String[] data = ((String) message.getPayload()).split(":");