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:02 UTC

[james-project] 19/41: JAMES-2813 use jackson built-in type detection for polymorphic types

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 80bb1868e0b83c449c222d45f7b3d1e6e639047b
Author: Matthieu Baechler <ma...@apache.org>
AuthorDate: Fri Oct 18 16:40:40 2019 +0200

    JAMES-2813 use jackson built-in type detection for polymorphic types
---
 json/src/main/java/org/apache/james/json/DTO.java  |  6 +++
 .../apache/james/json/JsonGenericSerializer.java   | 54 ++++++++++++++--------
 2 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/json/src/main/java/org/apache/james/json/DTO.java b/json/src/main/java/org/apache/james/json/DTO.java
index 2e0fbdb..34f84d4 100644
--- a/json/src/main/java/org/apache/james/json/DTO.java
+++ b/json/src/main/java/org/apache/james/json/DTO.java
@@ -19,5 +19,11 @@
 
 package org.apache.james.json;
 
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", visible = true)
 public interface DTO {
+
+    String getType();
+
 }
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 e84630f..a1ed925 100644
--- a/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java
+++ b/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java
@@ -31,7 +31,9 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
 import com.fasterxml.jackson.databind.exc.MismatchedInputException;
+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;
@@ -57,12 +59,15 @@ public class JsonGenericSerializer<T, U extends DTO> {
                     Function.identity()));
         }
 
-        public Optional<DTOModule<T, U>> findModule(T domainObject) {
-            return Optional.ofNullable(domainClassToModule.get(domainObject.getClass()));
+        public Optional<U> convert(T domainObject) {
+            return Optional.ofNullable(domainClassToModule.get(domainObject.getClass()))
+                .map(module -> module.toDTO(domainObject));
         }
 
-        public Optional<DTOModule<T, U>> findModule(String type) {
-            return Optional.ofNullable(typeToModule.get(type));
+        public Optional<T> convert(U dto) {
+            String type = dto.getType();
+            return Optional.ofNullable(typeToModule.get(type))
+                .map(module -> module.getToDomainObjectConverter().convert(dto));
         }
     }
 
@@ -98,35 +103,48 @@ public class JsonGenericSerializer<T, U extends DTO> {
         objectMapper.setSerializationInclusion(JsonInclude.Include.NON_ABSENT);
         objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
         objectMapper.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);
     }
 
     public String serialize(T domainObject) throws JsonProcessingException {
-        U dto = dtoConverter.findModule(domainObject)
-            .map(module -> module.toDTO(domainObject))
+        U dto = dtoConverter.convert(domainObject)
             .orElseThrow(() -> new UnknownTypeException("unknown type " + domainObject.getClass()));
         return objectMapper.writeValueAsString(dto);
     }
 
 
     public T deserialize(String value) throws IOException {
-        try {
-            JsonNode jsonNode = objectMapper.readTree(value);
-
-            JsonNode typeNode = jsonNode.path("type");
+        U dto = jsonToDTO(value);
+        return dtoConverter.convert(dto)
+            .orElseThrow(() -> new UnknownTypeException("unknown type " + dto.getType()));
+    }
 
-            if (typeNode.isMissingNode()) {
-                throw new InvalidTypeException("No \"type\" property found in the json document");
+    public U jsonToDTO(String value) throws IOException {
+        try {
+            JsonNode jsonTree = detectDuplicateProperty(value);
+            return parseAsPolymorphicDTO(jsonTree);
+        } catch (InvalidTypeIdException e) {
+            String typeId = e.getTypeId();
+            if (typeId == null) {
+                throw new InvalidTypeException("Unable to deserialize the json document", e);
+            } else {
+                throw new UnknownTypeException("unknown type " + typeId);
             }
-
-            String type = typeNode.asText();
-            DTOModule<T, U> dtoModule = dtoConverter.findModule(type)
-                .orElseThrow(() -> new UnknownTypeException("unknown type " + type));
-            U dto = objectMapper.readValue(objectMapper.treeAsTokens(jsonNode), dtoModule.getDTOClass());
-            return dtoModule.getToDomainObjectConverter().convert(dto);
         } catch (MismatchedInputException e) {
             throw new InvalidTypeException("Unable to deserialize the json document", e);
         }
     }
 
+    private JsonNode detectDuplicateProperty(String value) throws IOException {
+        return objectMapper.readTree(value);
+    }
+
+    @SuppressWarnings("rawtypes")
+    private U parseAsPolymorphicDTO(JsonNode jsonTree) throws IOException {
+        return (U) objectMapper.readValue(objectMapper.treeAsTokens(jsonTree), DTO.class);
+    }
+
 }


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