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