You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2019/11/20 07:32:03 UTC

[james-project] 20/41: JAMES-2813 Split JsonGenericSerializer between conversion and serialization

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 27f2845344e1a97c63215d512aa3e17110f3083b
Author: Matthieu Baechler <ma...@apache.org>
AuthorDate: Mon Oct 21 10:14:42 2019 +0200

    JAMES-2813 Split JsonGenericSerializer between conversion and serialization
---
 .../eventstore/cassandra/JsonEventSerializer.java  |   3 +-
 .../java/org/apache/james/json/DTOConverter.java   |  65 ++++++++++++
 .../apache/james/json/JsonGenericSerializer.java   |  60 +++--------
 .../src/test/java/org/apache/DTOConverterTest.java | 115 +++++++++++++++++++++
 .../JsonTaskAdditionalInformationSerializer.java   |   3 +-
 .../james/server/task/json/JsonTaskSerializer.java |   3 +-
 6 files changed, 202 insertions(+), 47 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 52b0d3a..0bc17a1 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
@@ -50,7 +50,8 @@ public class JsonEventSerializer {
 
     @Inject
     public JsonEventSerializer(Set<EventDTOModule<?, ?>> modules) {
-        jsonGenericSerializer = new JsonGenericSerializer(modules);
+        //FIXME
+        jsonGenericSerializer = new JsonGenericSerializer(modules, null);
     }
     
     public JsonEventSerializer(EventDTOModule<?, ?>... modules) {
diff --git a/json/src/main/java/org/apache/james/json/DTOConverter.java b/json/src/main/java/org/apache/james/json/DTOConverter.java
new file mode 100644
index 0000000..1fe27f3
--- /dev/null
+++ b/json/src/main/java/org/apache/james/json/DTOConverter.java
@@ -0,0 +1,65 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.json;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableSet;
+
+public class DTOConverter<T, U extends DTO> {
+
+    private final Map<String, DTOModule<T, U>> typeToModule;
+    private final Map<Class<? extends T>, DTOModule<T, U>> domainClassToModule;
+
+    @SafeVarargs
+    public static <T, U extends DTO> DTOConverter<T, U> of(DTOModule<T, U>... modules) {
+        return new DTOConverter<>(ImmutableSet.copyOf(modules));
+    }
+
+    public DTOConverter(Set<DTOModule<T, U>> modules) {
+        typeToModule = modules.stream()
+            .collect(Guavate.toImmutableMap(
+                DTOModule::getDomainObjectType,
+                Function.identity()));
+
+        domainClassToModule = modules.stream()
+            .collect(Guavate.toImmutableMap(
+                DTOModule::getDomainObjectClass,
+                Function.identity()));
+    }
+
+    public Optional<U> convert(T domainObject) {
+        return Optional
+            .ofNullable(domainClassToModule.get(domainObject.getClass()))
+            .map(module -> module.toDTO(domainObject));
+    }
+
+    public Optional<T> convert(U dto) {
+        String type = dto.getType();
+        return Optional
+            .ofNullable(typeToModule.get(type))
+            .map(DTOModule::getToDomainObjectConverter)
+            .map(convert -> convert.convert(dto));
+    }
+}
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 a1ed925..ceb3066 100644
--- a/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java
+++ b/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java
@@ -20,10 +20,7 @@
 package org.apache.james.json;
 
 import java.io.IOException;
-import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
-import java.util.function.Function;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -37,40 +34,10 @@ import com.fasterxml.jackson.databind.jsontype.NamedType;
 import com.fasterxml.jackson.datatype.guava.GuavaModule;
 import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableSet;
 
 public class JsonGenericSerializer<T, U extends DTO> {
 
-    private static class DTOConverter<T, U extends DTO> {
-
-        private final Map<String, DTOModule<T, U>> typeToModule;
-        private final Map<Class<? extends T>, DTOModule<T, U>> domainClassToModule;
-
-        public DTOConverter(Set<DTOModule<T, U>> modules) {
-            typeToModule = modules.stream()
-                .collect(Guavate.toImmutableMap(
-                    DTOModule::getDomainObjectType,
-                    Function.identity()));
-
-            domainClassToModule = modules.stream()
-                .collect(Guavate.toImmutableMap(
-                    DTOModule::getDomainObjectClass,
-                    Function.identity()));
-        }
-
-        public Optional<U> convert(T domainObject) {
-            return Optional.ofNullable(domainClassToModule.get(domainObject.getClass()))
-                .map(module -> module.toDTO(domainObject));
-        }
-
-        public Optional<T> convert(U dto) {
-            String type = dto.getType();
-            return Optional.ofNullable(typeToModule.get(type))
-                .map(module -> module.getToDomainObjectConverter().convert(dto));
-        }
-    }
-
     public static class InvalidTypeException extends RuntimeException {
         public InvalidTypeException(String message) {
             super(message);
@@ -92,21 +59,26 @@ public class JsonGenericSerializer<T, U extends DTO> {
 
     @SafeVarargs
     public static <T, U extends DTO> JsonGenericSerializer<T, U> of(DTOModule<T, U>... modules) {
-        return new JsonGenericSerializer<>(ImmutableSet.copyOf(modules));
+        return new JsonGenericSerializer<>(ImmutableSet.copyOf(modules), DTOConverter.of(modules));
+    }
+
+    public JsonGenericSerializer(Set<DTOModule<T, U>> modules, DTOConverter<T, U> converter) {
+        this.dtoConverter = converter;
+        this.objectMapper = buildObjectMapper(modules);
     }
 
-    public JsonGenericSerializer(Set<DTOModule<T, U>> modules) {
-        objectMapper = new ObjectMapper();
-        objectMapper.registerModule(new Jdk8Module());
-        objectMapper.registerModule(new JavaTimeModule());
-        objectMapper.registerModule(new GuavaModule());
-        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_ABSENT);
-        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
-        objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
+    private ObjectMapper buildObjectMapper(Set<DTOModule<T, U>> modules) {
+        ObjectMapper objectMapper = new ObjectMapper()
+            .registerModule(new Jdk8Module())
+            .registerModule(new JavaTimeModule())
+            .registerModule(new GuavaModule())
+            .setSerializationInclusion(JsonInclude.Include.NON_ABSENT)
+            .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+            .enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
         modules.stream()
             .map(module -> new NamedType(module.getDTOClass(), module.getDomainObjectType()))
             .forEach(objectMapper::registerSubtypes);
-        dtoConverter = new DTOConverter<>(modules);
+        return objectMapper;
     }
 
     public String serialize(T domainObject) throws JsonProcessingException {
@@ -122,7 +94,7 @@ public class JsonGenericSerializer<T, U extends DTO> {
             .orElseThrow(() -> new UnknownTypeException("unknown type " + dto.getType()));
     }
 
-    public U jsonToDTO(String value) throws IOException {
+    private U jsonToDTO(String value) throws IOException {
         try {
             JsonNode jsonTree = detectDuplicateProperty(value);
             return parseAsPolymorphicDTO(jsonTree);
diff --git a/json/src/test/java/org/apache/DTOConverterTest.java b/json/src/test/java/org/apache/DTOConverterTest.java
new file mode 100644
index 0000000..3987dbd
--- /dev/null
+++ b/json/src/test/java/org/apache/DTOConverterTest.java
@@ -0,0 +1,115 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.ZonedDateTime;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import org.apache.dto.BaseType;
+import org.apache.dto.FirstDTO;
+import org.apache.dto.FirstDomainObject;
+import org.apache.dto.SecondDTO;
+import org.apache.dto.SecondDomainObject;
+import org.apache.dto.TestModules;
+import org.apache.james.json.DTO;
+import org.apache.james.json.DTOConverter;
+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;
+
+class DTOConverterTest {
+    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 FirstDTO FIRST_DTO = new FirstDTO("first", Optional.of(1L), "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 SecondDTO SECOND_DTO = new SecondDTO("second", "4a2c853f-7ffc-4ce3-9410-a47e85b3b741", "second payload");
+
+    @SuppressWarnings("unchecked")
+    @Test
+    void shouldConvertFromKnownDTO() throws Exception {
+        assertThat(DTOConverter.of(TestModules.FIRST_TYPE)
+            .convert(FIRST_DTO))
+            .contains(FIRST);
+    }
+
+    @Test
+    void shouldReturnEmptyWhenConvertingFromUnknownDTO() {
+        assertThat(DTOConverter.of()
+            .convert(FIRST_DTO))
+            .isEmpty();
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void convertFromDomainObjectShouldHandleAllKnownTypes(BaseType domainObject, DTO dto) throws Exception {
+        @SuppressWarnings("unchecked")
+        DTOConverter<BaseType, DTO> serializer = DTOConverter.of(
+                TestModules.FIRST_TYPE,
+                TestModules.SECOND_TYPE);
+
+        assertThat(serializer.convert(domainObject))
+            .hasValueSatisfying(result -> assertThat(result).isInstanceOf(dto.getClass()).isEqualToComparingFieldByField(dto));
+    }
+
+    private static Stream<Arguments> convertFromDomainObjectShouldHandleAllKnownTypes() {
+        return allKnownTypes();
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void convertFromDTOShouldHandleAllKnownTypes(BaseType domainObject, DTO dto) throws Exception {
+        @SuppressWarnings("unchecked")
+        DTOConverter<BaseType, DTO> serializer = DTOConverter.of(
+                TestModules.FIRST_TYPE,
+                TestModules.SECOND_TYPE);
+
+        assertThat(serializer.convert(dto))
+            .hasValueSatisfying(result -> assertThat(result).isInstanceOf(domainObject.getClass()).isEqualToComparingFieldByField(domainObject));
+    }
+
+    private static Stream<Arguments> convertFromDTOShouldHandleAllKnownTypes() {
+        return allKnownTypes();
+    }
+
+    private static Stream<Arguments> allKnownTypes() {
+        return Stream.of(
+                Arguments.of(SECOND, SECOND_DTO),
+                Arguments.of(FIRST, FIRST_DTO)
+        );
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    void shouldConvertFromKnownDomainObject() throws Exception {
+        assertThat(DTOConverter.of(TestModules.FIRST_TYPE)
+            .convert(FIRST))
+            .hasValueSatisfying(result -> assertThat(result).isInstanceOf(FirstDTO.class).isEqualToComparingFieldByField(FIRST_DTO));
+    }
+
+    @Test
+    void shouldReturnEmptyWhenConvertUnknownDomainObject() {
+        assertThat(DTOConverter.of().convert(FIRST))
+            .isEmpty();
+    }
+}
diff --git a/server/task/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskAdditionalInformationSerializer.java b/server/task/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskAdditionalInformationSerializer.java
index 751cc17..5d0cc48 100644
--- a/server/task/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskAdditionalInformationSerializer.java
+++ b/server/task/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskAdditionalInformationSerializer.java
@@ -49,7 +49,8 @@ public class JsonTaskAdditionalInformationSerializer {
 
     @Inject
     public JsonTaskAdditionalInformationSerializer(Set<AdditionalInformationDTOModule<?, ?>> modules) {
-        jsonGenericSerializer = new JsonGenericSerializer(modules);
+        //FIXME
+        jsonGenericSerializer = new JsonGenericSerializer(modules, null);
     }
 
     public JsonTaskAdditionalInformationSerializer(@SuppressWarnings("rawtypes") AdditionalInformationDTOModule... modules) {
diff --git a/server/task/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskSerializer.java b/server/task/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskSerializer.java
index 9ecd7c4..90ebe54 100644
--- a/server/task/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskSerializer.java
+++ b/server/task/task-json/src/main/java/org/apache/james/server/task/json/JsonTaskSerializer.java
@@ -50,7 +50,8 @@ public class JsonTaskSerializer {
 
     @Inject
     public JsonTaskSerializer(Set<TaskDTOModule<?, ?>> modules) {
-        jsonGenericSerializer = new JsonGenericSerializer(modules);
+        //FIXME
+        jsonGenericSerializer = new JsonGenericSerializer(modules, null);
     }
 
     public JsonTaskSerializer(@SuppressWarnings("rawtypes") TaskDTOModule... modules) {


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org