Json mapper (#258)
* Implemented Pojo mapper using jackson Added other exception kinds Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Fixup for the rebase Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Removed comment Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Equals and hash code Signed-off-by: Francesco Guardiani <francescoguard@gmail.com> * Fixed rebase issues Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
This commit is contained in:
parent
3bd9a6922f
commit
c7baada605
|
@ -25,6 +25,7 @@ public class CloudEventRWException extends RuntimeException {
|
|||
INVALID_ATTRIBUTE_TYPE,
|
||||
INVALID_ATTRIBUTE_VALUE,
|
||||
INVALID_EXTENSION_TYPE,
|
||||
DATA_CONVERSION,
|
||||
OTHER
|
||||
}
|
||||
|
||||
|
@ -85,6 +86,14 @@ public class CloudEventRWException extends RuntimeException {
|
|||
);
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue