This is an automated email from the ASF dual-hosted git repository. rouazana pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit f61d59593f57eb4b9c0834e95071ea67af2adc32 Author: Rémi Kowalski <[email protected]> AuthorDate: Tue Jul 16 15:12:20 2019 +0200 JAMES-2813 Handle missing and duplicate types for DTO deserialization --- .../eventstore/cassandra/JsonEventSerializer.java | 8 +++++ .../cassandra/JsonEventSerializerTest.java | 22 +++++++++++++ .../apache/james/json/JsonGenericSerializer.java | 36 +++++++++++++++++----- .../java/org/apache/JsonGenericSerializerTest.java | 20 +++++++++++- .../james/server/task/json/JsonTaskSerializer.java | 9 ++++++ .../server/task/json/TaskDeserializerTest.java | 4 +-- 6 files changed, 89 insertions(+), 10 deletions(-) diff --git a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/JsonEventSerializer.java b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/JsonEventSerializer.java index 4303ce5..943abc4 100644 --- a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/JsonEventSerializer.java +++ b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/JsonEventSerializer.java @@ -34,6 +34,12 @@ import com.google.common.collect.ImmutableSet; public class JsonEventSerializer { + public static class InvalidEventException extends RuntimeException { + public InvalidEventException(JsonGenericSerializer.InvalidTypeException original) { + super(original); + } + } + public static class UnknownEventException extends RuntimeException { public UnknownEventException(JsonGenericSerializer.UnknownTypeException original) { super(original); @@ -64,6 +70,8 @@ public class JsonEventSerializer { return jsonGenericSerializer.deserialize(value); } catch (JsonGenericSerializer.UnknownTypeException e) { throw new UnknownEventException(e); + } catch (JsonGenericSerializer.InvalidTypeException e) { + throw new InvalidEventException(e); } } diff --git a/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/JsonEventSerializerTest.java b/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/JsonEventSerializerTest.java index bfa669f..d042a44 100644 --- a/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/JsonEventSerializerTest.java +++ b/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/JsonEventSerializerTest.java @@ -39,6 +39,8 @@ class JsonEventSerializerTest { public static final String TEST_EVENT_JSON = "{\"type\":\"TestType\",\"data\":\"first\",\"eventId\":0,\"aggregate\":1}"; public static final String OTHER_EVENT_JSON = "{\"type\":\"other-type\",\"data\":1,\"eventId\":0,\"aggregate\":1}"; + public static final String MISSING_TYPE_EVENT_JSON = "{\"data\":1,\"eventId\":0,\"aggregate\":1}"; + public static final String DUPLICATE_TYPE_EVENT_JSON = "{\"type\":\"TestType\", \"type\":\"other-type\",\"data\":1,\"eventId\":0,\"aggregate\":1}"; @Test void shouldDeserializeKnownEvent() throws Exception { @@ -84,6 +86,25 @@ class JsonEventSerializerTest { .isEqualTo(TEST_EVENT); } + + @Test + void deserializeShouldThrowWhenEventWithDuplicatedTypes() { + assertThatThrownBy(() -> new JsonEventSerializer( + TestEventDTOModules.TEST_TYPE, + TestEventDTOModules.OTHER_TEST_TYPE) + .deserialize(DUPLICATE_TYPE_EVENT_JSON)) + .isInstanceOf(JsonEventSerializer.InvalidEventException.class); + } + + @Test + void deserializeShouldThrowWhenEventWithMissingType() { + assertThatThrownBy(() -> new JsonEventSerializer( + TestEventDTOModules.TEST_TYPE, + TestEventDTOModules.OTHER_TEST_TYPE) + .deserialize(MISSING_TYPE_EVENT_JSON)) + .isInstanceOf(JsonEventSerializer.InvalidEventException.class); + } + @Test void shouldSerializeKnownEvent() throws Exception { assertThatJson(new JsonEventSerializer(TestEventDTOModules.TEST_TYPE) @@ -98,4 +119,5 @@ class JsonEventSerializerTest { .isInstanceOf(JsonEventSerializer.UnknownEventException.class); } + } \ No newline at end of file diff --git a/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java b/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java index cd8283d..6934320 100644 --- a/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java +++ b/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java @@ -27,8 +27,10 @@ import java.util.function.Function; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.datatype.guava.GuavaModule; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -36,6 +38,17 @@ import com.github.steveash.guavate.Guavate; import com.google.common.collect.ImmutableSet; public class JsonGenericSerializer<T, U extends DTO<T>> { + + public static class InvalidTypeException extends RuntimeException { + public InvalidTypeException(String message) { + super(message); + } + + public InvalidTypeException(String message, MismatchedInputException exception) { + super(message, exception); + } + } + public static class UnknownTypeException extends RuntimeException { public UnknownTypeException(String message) { super(message); @@ -57,7 +70,7 @@ public class JsonGenericSerializer<T, U extends DTO<T>> { objectMapper.registerModule(new JavaTimeModule()); objectMapper.registerModule(new GuavaModule()); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_ABSENT); - + objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY); typeToModule = modules.stream() .collect(Guavate.toImmutableMap( DTOModule::getDomainObjectType, @@ -77,14 +90,22 @@ public class JsonGenericSerializer<T, U extends DTO<T>> { } public T deserialize(String value) throws IOException { - JsonNode jsonNode = objectMapper.readTree(value); + try { + JsonNode jsonNode = objectMapper.readTree(value); + + JsonNode typeNode = jsonNode.path("type"); - String type = jsonNode.path("type").asText(); + if (typeNode.isMissingNode()) { + throw new InvalidTypeException("No \"type\" property found in the json document"); + } - U dto = objectMapper.readValue( - objectMapper.treeAsTokens(jsonNode), - retrieveDTOClass(type)); - return dto.toDomainObject(); + U dto = objectMapper.readValue( + objectMapper.treeAsTokens(jsonNode), + retrieveDTOClass(typeNode.asText())); + return dto.toDomainObject(); + } catch (MismatchedInputException e) { + throw new InvalidTypeException("Duplicate \"type\" properties found in the json document", e); + } } private Class<? extends U> retrieveDTOClass(String type) { @@ -93,4 +114,5 @@ public class JsonGenericSerializer<T, U extends DTO<T>> { .orElseThrow(() -> new UnknownTypeException("unknown type " + type)); } + } diff --git a/json/src/test/java/org/apache/JsonGenericSerializerTest.java b/json/src/test/java/org/apache/JsonGenericSerializerTest.java index c69a400..c450e68 100644 --- a/json/src/test/java/org/apache/JsonGenericSerializerTest.java +++ b/json/src/test/java/org/apache/JsonGenericSerializerTest.java @@ -43,6 +43,8 @@ class JsonGenericSerializerTest { private static final FirstDomainObject FIRST = new FirstDomainObject(Optional.of(1L), ZonedDateTime.parse("2016-04-03T02:01+07:00[Asia/Vientiane]"), "first payload"); private static final SecondDomainObject SECOND = new SecondDomainObject(UUID.fromString("4a2c853f-7ffc-4ce3-9410-a47e85b3b741"), "second payload"); + private static final String MISSING_TYPE_JSON = "{\"id\":1,\"time\":\"2016-04-03T02:01+07:00[Asia/Vientiane]\",\"payload\":\"first payload\"}"; + private static final String DUPLICATE_TYPE_JSON = "{\"type\":\"first\", \"type\":\"second\", \"id\":1,\"time\":\"2016-04-03T02:01+07:00[Asia/Vientiane]\",\"payload\":\"first payload\"}"; private static final String FIRST_JSON = "{\"type\":\"first\",\"id\":1,\"time\":\"2016-04-03T02:01+07:00[Asia/Vientiane]\",\"payload\":\"first payload\"}"; private static final String SECOND_JSON = "{\"type\":\"second\",\"id\":\"4a2c853f-7ffc-4ce3-9410-a47e85b3b741\",\"payload\":\"second payload\"}"; @@ -54,6 +56,22 @@ class JsonGenericSerializerTest { } @Test + void shouldThrowWhenDeserializeEventWithMissingType() { + assertThatThrownBy(() -> JsonGenericSerializer.of(TestModules.FIRST_TYPE) + .deserialize(MISSING_TYPE_JSON)) + .isInstanceOf(JsonGenericSerializer.InvalidTypeException.class); + } + + @Test + void shouldThrowWhenDeserializeEventWithDuplicatedTypes() { + assertThatThrownBy(() -> JsonGenericSerializer.of( + TestModules.FIRST_TYPE, + TestModules.SECOND_TYPE) + .deserialize(DUPLICATE_TYPE_JSON)) + .isInstanceOf(JsonGenericSerializer.InvalidTypeException.class); + } + + @Test void shouldThrowWhenDeserializeUnknownType() { assertThatThrownBy(() -> JsonGenericSerializer.of() .deserialize(FIRST_JSON)) @@ -111,4 +129,4 @@ class JsonGenericSerializerTest { .isInstanceOf(JsonGenericSerializer.UnknownTypeException.class); } -} \ No newline at end of file +} diff --git a/server/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskSerializer.java b/server/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskSerializer.java index a502ce7..21b048e 100644 --- a/server/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskSerializer.java +++ b/server/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskSerializer.java @@ -34,6 +34,12 @@ import com.google.common.collect.ImmutableSet; public class JsonTaskSerializer { + public static class InvalidTaskException extends RuntimeException { + public InvalidTaskException(JsonGenericSerializer.InvalidTypeException original) { + super(original); + } + } + public static class UnknownTaskException extends RuntimeException { public UnknownTaskException(JsonGenericSerializer.UnknownTypeException original) { super(original); @@ -64,7 +70,10 @@ public class JsonTaskSerializer { return jsonGenericSerializer.deserialize(value); } catch (JsonGenericSerializer.UnknownTypeException e) { throw new UnknownTaskException(e); + } catch (JsonGenericSerializer.InvalidTypeException e) { + throw new InvalidTaskException(e); } } + } diff --git a/server/task-json/src/test/java/org/apache/james/server/task/json/TaskDeserializerTest.java b/server/task-json/src/test/java/org/apache/james/server/task/json/TaskDeserializerTest.java index 13f4062..0cb3d00 100644 --- a/server/task-json/src/test/java/org/apache/james/server/task/json/TaskDeserializerTest.java +++ b/server/task-json/src/test/java/org/apache/james/server/task/json/TaskDeserializerTest.java @@ -72,13 +72,13 @@ class TaskDeserializerTest { @Test void shouldThrowWhenMissingType() { assertThatThrownBy(() -> testee.deserialize(MISSING_TASK_AS_STRING)) - .isInstanceOf(JsonTaskSerializer.UnknownTaskException.class); + .isInstanceOf(JsonTaskSerializer.InvalidTaskException.class); } @Test void shouldThrowWhenDuplicateType() { assertThatThrownBy(() -> testee.deserialize(TWO_TYPES_TASK_AS_STRING)) - .isInstanceOf(JsonTaskSerializer.UnknownTaskException.class); + .isInstanceOf(JsonTaskSerializer.InvalidTaskException.class); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
