Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public enum CloudEventRWExceptionKind {
INVALID_ATTRIBUTE_TYPE,
INVALID_ATTRIBUTE_VALUE,
INVALID_EXTENSION_TYPE,
DATA_CONVERSION,
OTHER
}

Expand Down Expand Up @@ -85,6 +86,14 @@ public static CloudEventRWException newInvalidExtensionType(String extensionName
);
}

public static CloudEventRWException newDataConversion(Throwable cause, String to) {
return new CloudEventRWException(
CloudEventRWExceptionKind.DATA_CONVERSION,
"Error while trying to convert data to " + to,
cause
);
}

public static CloudEventRWException newOther(Throwable cause) {
return new CloudEventRWException(
CloudEventRWExceptionKind.OTHER,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.cloudevents.jackson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cloudevents.CloudEventData;
import io.cloudevents.rw.CloudEventRWException;

import java.util.Objects;

public class PojoCloudEventData<T> implements CloudEventData {

private final ObjectMapper mapper;
private byte[] memoizedValue;
private final T value;

protected PojoCloudEventData(ObjectMapper mapper, T value) {
this(mapper, value, null);
}

protected PojoCloudEventData(ObjectMapper mapper, T value, byte[] memoizedValue) {
this.mapper = mapper;
this.value = value;
this.memoizedValue = memoizedValue;
}

public T getValue() {
return value;
}

@Override
public byte[] toBytes() {
if (this.memoizedValue == null) {
try {
this.memoizedValue = mapper.writeValueAsBytes(value);
} catch (JsonProcessingException e) {
throw CloudEventRWException.newDataConversion(e, "byte[]");
}
}
return this.memoizedValue;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PojoCloudEventData<?> that = (PojoCloudEventData<?>) o;
return Objects.equals(getValue(), that.getValue());
}

@Override
public int hashCode() {
return Objects.hash(getValue());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.cloudevents.jackson;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cloudevents.CloudEventData;
import io.cloudevents.rw.CloudEventDataMapper;
import io.cloudevents.rw.CloudEventRWException;

public class PojoCloudEventDataMapper<T> implements CloudEventDataMapper<PojoCloudEventData<T>> {

private final ObjectMapper mapper;
private final TypeReference<T> target;

private PojoCloudEventDataMapper(ObjectMapper mapper, TypeReference<T> target) {
this.mapper = mapper;
this.target = target;
}

@Override
public PojoCloudEventData<T> map(CloudEventData data) throws CloudEventRWException {
// Best case, event is already from json
if (data instanceof JsonCloudEventData) {
JsonNode node = ((JsonCloudEventData) data).getNode();
T value;
try {
value = this.mapper.convertValue(node, target);
} catch (Exception e) {
throw CloudEventRWException.newDataConversion(e, target.getType().toString());
}
return new PojoCloudEventData<>(mapper, value);
}

// Worst case, deserialize from bytes
T value;
byte[] bytes = data.toBytes();
try {
value = this.mapper.readValue(bytes, this.target);
} catch (Exception e) {
throw CloudEventRWException.newDataConversion(e, target.getType().toString());
}
return new PojoCloudEventData<>(mapper, value, bytes);
}

public static <T> PojoCloudEventDataMapper<T> from(ObjectMapper mapper, TypeReference<T> target) {
return new PojoCloudEventDataMapper<>(mapper, target);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.cloudevents.jackson;

import java.util.Objects;

public class MyPojo {
public int a;
public String b;

public MyPojo() {
}

public MyPojo(int a, String b) {
this.a = a;
this.b = b;
}

public int getA() {
return a;
}

public void setA(int a) {
this.a = a;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyPojo myPojo = (MyPojo) o;
return getA() == myPojo.getA() &&
Objects.equals(b, myPojo.b);
}

@Override
public int hashCode() {
return Objects.hash(getA(), b);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.cloudevents.jackson;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.core.impl.CloudEventUtils;
import io.cloudevents.core.test.Data;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class PojoCloudEventDataMapperTest {

private final JsonNode myPojoJson = JsonNodeFactory.instance.objectNode().put("a", 10).put("b", "Hello World!");
private final String myPojoSerialized = myPojoJson.toString();
private final MyPojo myPojo = new MyPojo(10, "Hello World!");

@Test
public void testWithBytes() {
ObjectMapper objectMapper = new ObjectMapper();

CloudEvent event = CloudEventBuilder.v1(Data.V1_MIN)
.withData("application/json", myPojoSerialized.getBytes())
.build();

PojoCloudEventData<MyPojo> mappedData = CloudEventUtils.mapData(
event,
PojoCloudEventDataMapper.from(objectMapper, new TypeReference<MyPojo>() {
})
);
assertThat(mappedData)
.isNotNull()
.extracting(PojoCloudEventData::getValue)
.isEqualTo(myPojo);
}

@Test
public void testWithJson() {
ObjectMapper objectMapper = new ObjectMapper();

CloudEvent event = CloudEventBuilder.v1(Data.V1_MIN)
.withData("application/json", new JsonCloudEventData(myPojoJson))
.build();

PojoCloudEventData<MyPojo> mappedData = CloudEventUtils.mapData(
event,
PojoCloudEventDataMapper.from(objectMapper, new TypeReference<MyPojo>() {
})
);
assertThat(mappedData)
.isNotNull()
.extracting(PojoCloudEventData::getValue)
.isEqualTo(myPojo);
}

}