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
@@ -1,18 +1,20 @@
package io.cloudevents.jackson;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
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;
import java.util.List;

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

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

private PojoCloudEventDataMapper(ObjectMapper mapper, TypeReference<T> target) {
private PojoCloudEventDataMapper(ObjectMapper mapper, JavaType target) {
this.mapper = mapper;
this.target = target;
}
Expand All @@ -26,7 +28,7 @@ public PojoCloudEventData<T> map(CloudEventData data) throws CloudEventRWExcepti
try {
value = this.mapper.convertValue(node, target);
} catch (Exception e) {
throw CloudEventRWException.newDataConversion(e, target.getType().toString());
throw CloudEventRWException.newDataConversion(e, target.getTypeName());
}
return new PojoCloudEventData<>(mapper, value);
}
Expand All @@ -37,12 +39,43 @@ public PojoCloudEventData<T> map(CloudEventData data) throws CloudEventRWExcepti
try {
value = this.mapper.readValue(bytes, this.target);
} catch (Exception e) {
throw CloudEventRWException.newDataConversion(e, target.getType().toString());
throw CloudEventRWException.newDataConversion(e, target.getTypeName());
}
return new PojoCloudEventData<>(mapper, value, bytes);
}

/**
* Creates a {@link PojoCloudEventDataMapper} mapping {@link CloudEventData} into {@link PojoCloudEventData}&lt;T&gt;.
*
* <p>
* When working with generic types (e.g. {@link List}&lt{@link String}&gt),
* it's better to use {@link PojoCloudEventDataMapper#from(ObjectMapper, TypeReference)}.
* </p>
*
* @param mapper {@link ObjectMapper} used for POJO deserialization
* @param target target type as {@link Class}&lt;T&gt;
* @param <T> POJO Type
* @return {@link CloudEventDataMapper}
*/
public static <T> PojoCloudEventDataMapper<T> from(ObjectMapper mapper, Class<T> target) {
return new PojoCloudEventDataMapper<>(mapper, mapper.getTypeFactory().constructType(target));
}

/**
* Creates a {@link PojoCloudEventDataMapper} mapping {@link CloudEventData} into {@link PojoCloudEventData}&lt;T&gt;.
*
* <p>
* This overload is more suitable for mapping generic objects (e.g. {@link List}&lt{@link String}&gt),
* as opposed to {@link PojoCloudEventDataMapper#from(ObjectMapper, Class)}.
* </p>
*
* @param mapper {@link ObjectMapper} used for POJO deserialization
* @param target target type as {@link TypeReference}&lt;T&gt;
* @param <T> POJO Type
* @return {@link CloudEventDataMapper}
*/
public static <T> PojoCloudEventDataMapper<T> from(ObjectMapper mapper, TypeReference<T> target) {
return new PojoCloudEventDataMapper<>(mapper, target);
return new PojoCloudEventDataMapper<>(mapper, mapper.getTypeFactory().constructType(target));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
import io.cloudevents.core.impl.CloudEventUtils;
import io.cloudevents.core.test.Data;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

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

Expand All @@ -18,42 +23,48 @@ public class PojoCloudEventDataMapperTest {
private final String myPojoSerialized = myPojoJson.toString();
private final MyPojo myPojo = new MyPojo(10, "Hello World!");

@Test
public void testWithBytes() {
ObjectMapper objectMapper = new ObjectMapper();
@ParameterizedTest
@MethodSource("getPojoMappers")
public void testWithBytes(PojoCloudEventDataMapper<MyPojo> mapper) {

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>() {
})
mapper
);
assertThat(mappedData)
.isNotNull()
.extracting(PojoCloudEventData::getValue)
.isEqualTo(myPojo);
}

@Test
public void testWithJson() {
ObjectMapper objectMapper = new ObjectMapper();
@ParameterizedTest
@MethodSource("getPojoMappers")
public void testWithJson(PojoCloudEventDataMapper<MyPojo> mapper) {

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>() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More than modifying this test, can you create a new one for class?

})
mapper
);
assertThat(mappedData)
.isNotNull()
.extracting(PojoCloudEventData::getValue)
.isEqualTo(myPojo);
}

private static Stream<Arguments> getPojoMappers() {
final ObjectMapper objectMapper = new ObjectMapper();
return Stream.of(
Arguments.of(PojoCloudEventDataMapper.from(objectMapper, new TypeReference<MyPojo>() {})),
Arguments.of(PojoCloudEventDataMapper.from(objectMapper, MyPojo.class))
);
}

}