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 <[email protected]> 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: [email protected] For additional commands, e-mail: [email protected]
