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

[james-project] 23/41: JAMES-2813 use a staged builder to create serializers

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 805ebca371822761a93b8f28202b05d028fd5dfd
Author: Matthieu Baechler <ma...@apache.org>
AuthorDate: Tue Oct 22 17:05:46 2019 +0200

    JAMES-2813 use a staged builder to create serializers
---
 .../migration/MigrationTaskSerializationTest.java  |  4 +-
 .../eventstore/cassandra/JsonEventSerializer.java  | 40 +++++++++++---
 .../CassandraEventSourcingSystemTest.java          |  2 +-
 .../cassandra/CassandraEventStoreExtension.java    | 20 +++----
 .../cassandra/CassandraEventStoreTest.java         |  2 +-
 .../cassandra/JsonEventSerializerTest.java         | 33 ++++++------
 .../apache/james/json/JsonGenericSerializer.java   | 43 ++++++++++++---
 .../src/test/java/org/apache/DTOConverterTest.java | 13 ++---
 .../java/org/apache/JsonGenericSerializerTest.java | 61 +++++++++++-----------
 json/src/test/java/org/apache/dto/TestModules.java | 16 +++---
 ...ailboxPathV2MigrationTaskSerializationTest.java | 19 +++----
 .../mail/task/MailboxMergingTaskTest.java          |  6 +--
 ...aultGarbageCollectionTaskSerializationTest.java | 10 ++--
 .../james/mailbox/quota/cassandra/dto/DTOTest.java | 16 +++---
 ...sandraQuotaMailingListenersIntegrationTest.java |  4 +-
 ...rorRecoveryIndexationTaskSerializationTest.java |  5 +-
 .../FullReindexingTaskSerializationTest.java       |  4 +-
 .../MessageIdReindexingTaskSerializationTest.java  |  4 +-
 ...ngleMailboxReindexingTaskSerializationTest.java |  4 +-
 ...ngleMessageReindexingTaskSerializationTest.java |  4 +-
 .../UserReindexingTaskSerializationTest.java       |  4 +-
 ...ventSourcingDLPConfigurationStoreExtension.java |  8 ++-
 ...pingsSourcesMigrationTaskSerializationTest.java |  6 +--
 ...sandraEventSourcingFilteringManagementTest.java |  4 +-
 ...sandraMappingsSolveInconsistenciesTaskTest.java |  6 +--
 ...edMessagesVaultDeleteTaskSerializationTest.java |  4 +-
 ...edMessagesVaultExportTaskSerializationTest.java |  4 +-
 ...dMessagesVaultRestoreTaskSerializationTest.java |  4 +-
 .../WebadminApiQuerySerializationContractTest.java |  2 +-
 .../service/EventDeadLettersRedeliverTaskTest.java |  4 +-
 .../webadmin/service/ClearMailQueueTaskTest.java   |  8 +--
 .../service/DeleteMailsFromMailQueueTaskTest.java  | 10 ++--
 .../service/ClearMailRepositoryTaskTest.java       |  8 +--
 .../service/ReprocessingAllMailsTaskTest.java      |  8 +--
 .../service/ReprocessingOneMailTaskTest.java       |  8 +--
 .../CassandraMailQueueViewTestFactory.java         |  4 +-
 .../EventsourcingConfigurationManagementTest.java  |  6 ++-
 ...andraTaskExecutionDetailsProjectionDAOTest.java |  2 +-
 ...assandraTaskExecutionDetailsProjectionTest.java |  5 +-
 .../distributed/DistributedTaskManagerTest.java    | 15 +++---
 .../RabbitMQTerminationSubscriberTest.java         |  5 +-
 .../distributed/RabbitMQWorkQueueTest.java         |  4 +-
 .../distributed/TaskEventsSerializationTest.java   |  9 ++--
 .../JsonTaskAdditionalInformationSerializer.java   | 13 +++--
 .../james/server/task/json/JsonTaskSerializer.java | 13 +++--
 .../server/task/json/TaskDeserializerTest.java     |  2 +-
 .../server/task/json/TaskSerializationTest.java    |  8 +--
 .../james/server/task/json/TaskSerializerTest.java |  2 +-
 48 files changed, 262 insertions(+), 224 deletions(-)

diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/MigrationTaskSerializationTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/MigrationTaskSerializationTest.java
index c56e378..7dd5686 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/MigrationTaskSerializationTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/MigrationTaskSerializationTest.java
@@ -43,8 +43,8 @@ class MigrationTaskSerializationTest {
     private final CassandraSchemaVersionDAO cassandraSchemaVersionDAO = mock(CassandraSchemaVersionDAO.class);
     private final CassandraSchemaTransitions transitions = mock(CassandraSchemaTransitions.class);
     private final MigrationTask.Factory factory = target -> new MigrationTask(cassandraSchemaVersionDAO, transitions, target);
-    private final JsonTaskSerializer taskSerializer = new JsonTaskSerializer(MigrationTaskDTO.module(factory));
-    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(MigrationTaskAdditionalInformationDTO.serializationModule());
+    private final JsonTaskSerializer taskSerializer = JsonTaskSerializer.of(MigrationTaskDTO.module(factory));
+    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(MigrationTaskAdditionalInformationDTO.serializationModule());
 
     @Test
     void taskShouldBeSerializable() throws JsonProcessingException {
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 15f8005..3acdd58 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
@@ -20,6 +20,8 @@
 package org.apache.james.eventsourcing.eventstore.cassandra;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -27,15 +29,43 @@ import javax.inject.Inject;
 import org.apache.james.eventsourcing.Event;
 import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTO;
 import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
-import org.apache.james.json.DTOConverter;
 import org.apache.james.json.DTOModule;
 import org.apache.james.json.JsonGenericSerializer;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableSet;
 
 public class JsonEventSerializer {
 
+    public static RequireNestedConfiguration forModules(Set<? extends EventDTOModule<?, ?>> modules) {
+        return nestedTypesModules -> {
+            ImmutableSet<EventDTOModule<?, ?>> dtoModules = ImmutableSet.copyOf(modules);
+            return new JsonEventSerializer(dtoModules, ImmutableSet.copyOf(nestedTypesModules));
+        };
+    }
+
+    @SafeVarargs
+    public static RequireNestedConfiguration forModules(EventDTOModule<?, ?>... modules) {
+        return forModules(ImmutableSet.copyOf(modules));
+    }
+
+    public interface RequireNestedConfiguration {
+        JsonEventSerializer withNestedTypeModules(Set<DTOModule<?, ?>> modules);
+
+        default JsonEventSerializer withNestedTypeModules(DTOModule<?, ?>... modules) {
+            return withNestedTypeModules(ImmutableSet.copyOf(modules));
+        }
+
+        default JsonEventSerializer withNestedTypeModules(Set<DTOModule<?, ?>>... modules) {
+            return withNestedTypeModules(Arrays.stream(modules).flatMap(Collection::stream).collect(Guavate.toImmutableSet()));
+        }
+
+        default JsonEventSerializer withoutNestedType() {
+            return withNestedTypeModules(ImmutableSet.of());
+        }
+    }
+
     public static class InvalidEventException extends RuntimeException {
         public InvalidEventException(JsonGenericSerializer.InvalidTypeException original) {
             super(original);
@@ -51,14 +81,10 @@ public class JsonEventSerializer {
     private JsonGenericSerializer<Event, EventDTO> jsonGenericSerializer;
 
     @Inject
-    public JsonEventSerializer(DTOConverter<Event, EventDTO> converter, Set<EventDTOModule<?, ?>> modules, Set<DTOModule<?, ?>> nestedTypesModules) {
-        jsonGenericSerializer = new JsonGenericSerializer<>(modules, nestedTypesModules, converter);
+    private JsonEventSerializer(Set<EventDTOModule<?, ?>> modules, Set<DTOModule<?, ?>> nestedTypesModules) {
+        jsonGenericSerializer = JsonGenericSerializer.forModules(modules).withNestedTypeModules(nestedTypesModules);
     }
     
-    public JsonEventSerializer(EventDTOModule<?, ?>... modules) {
-        this(new DTOConverter<>(ImmutableSet.copyOf(modules)), ImmutableSet.copyOf(modules), ImmutableSet.of());
-    }
-
     public String serialize(Event event) throws JsonProcessingException {
         try {
             return jsonGenericSerializer.serialize(event);
diff --git a/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventSourcingSystemTest.java b/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventSourcingSystemTest.java
index 92c5401..6858b2d 100644
--- a/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventSourcingSystemTest.java
+++ b/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventSourcingSystemTest.java
@@ -25,5 +25,5 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class CassandraEventSourcingSystemTest implements EventSourcingSystemTest {
     @RegisterExtension
-    static CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(TestEventDTOModules.TEST_TYPE);
+    static CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(JsonEventSerializer.forModules(TestEventDTOModules.TEST_TYPE).withoutNestedType());
 }
diff --git a/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStoreExtension.java b/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStoreExtension.java
index bed4553..d338495 100644
--- a/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStoreExtension.java
+++ b/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStoreExtension.java
@@ -19,12 +19,8 @@
 
 package org.apache.james.eventsourcing.eventstore.cassandra;
 
-import java.util.Set;
-
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.eventsourcing.eventstore.EventStore;
-import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
-import org.apache.james.json.DTOConverter;
 import org.junit.jupiter.api.extension.AfterAllCallback;
 import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeAllCallback;
@@ -34,21 +30,19 @@ import org.junit.jupiter.api.extension.ParameterContext;
 import org.junit.jupiter.api.extension.ParameterResolutionException;
 import org.junit.jupiter.api.extension.ParameterResolver;
 
-import com.google.common.collect.ImmutableSet;
-
 public class CassandraEventStoreExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, ParameterResolver {
 
-    private final Set<EventDTOModule<?, ?>> modules;
     private CassandraClusterExtension cassandra;
+    private final JsonEventSerializer eventSerializer;
     private EventStoreDao eventStoreDao;
 
-    public CassandraEventStoreExtension(@SuppressWarnings("rawtypes") EventDTOModule... modules) {
-        this(new CassandraClusterExtension(CassandraEventStoreModule.MODULE), ImmutableSet.copyOf(modules));
+    public CassandraEventStoreExtension(JsonEventSerializer eventSerializer) {
+        this(new CassandraClusterExtension(CassandraEventStoreModule.MODULE), eventSerializer);
     }
 
-    public CassandraEventStoreExtension(CassandraClusterExtension cassandra, Set<EventDTOModule<?, ?>> module) {
+    public CassandraEventStoreExtension(CassandraClusterExtension cassandra, JsonEventSerializer eventSerializer) {
         this.cassandra = cassandra;
-        this.modules = module;
+        this.eventSerializer = eventSerializer;
     }
 
     @Override
@@ -63,9 +57,7 @@ public class CassandraEventStoreExtension implements BeforeAllCallback, AfterAll
 
     @Override
     public void beforeEach(ExtensionContext context) {
-        JsonEventSerializer jsonEventSerializer = new JsonEventSerializer(modules.toArray(new EventDTOModule[0]));
-
-        eventStoreDao = new EventStoreDao(cassandra.getCassandraCluster().getConf(), jsonEventSerializer);
+        eventStoreDao = new EventStoreDao(cassandra.getCassandraCluster().getConf(), eventSerializer);
     }
 
     @Override
diff --git a/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStoreTest.java b/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStoreTest.java
index f40eac1..562bd9b 100644
--- a/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStoreTest.java
+++ b/event-sourcing/event-store-cassandra/src/test/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStoreTest.java
@@ -25,5 +25,5 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 
 class CassandraEventStoreTest implements EventStoreTest {
     @RegisterExtension
-    static CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(TestEventDTOModules.TEST_TYPE);
+    static CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(JsonEventSerializer.forModules(TestEventDTOModules.TEST_TYPE).withoutNestedType());
 }
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 043532a..d0d6c65 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
@@ -28,7 +28,6 @@ import org.apache.james.eventsourcing.TestAggregateId;
 import org.apache.james.eventsourcing.TestEvent;
 import org.apache.james.eventsourcing.eventstore.cassandra.dto.OtherEvent;
 import org.apache.james.eventsourcing.eventstore.cassandra.dto.TestEventDTOModules;
-import org.apache.james.json.DTOModule;
 import org.junit.jupiter.api.Test;
 
 class JsonEventSerializerTest {
@@ -45,23 +44,23 @@ class JsonEventSerializerTest {
 
     @Test
     void shouldDeserializeKnownEvent() throws Exception {
-        assertThat(new JsonEventSerializer(TestEventDTOModules.TEST_TYPE)
+        assertThat(JsonEventSerializer.forModules(TestEventDTOModules.TEST_TYPE).withoutNestedType()
             .deserialize(TEST_EVENT_JSON))
             .isEqualTo(TEST_EVENT);
     }
 
     @Test
     void shouldThrowWhenDeserializeUnknownEvent() {
-        assertThatThrownBy(() -> new JsonEventSerializer()
+        assertThatThrownBy(() -> JsonEventSerializer.forModules().withoutNestedType()
             .deserialize(TEST_EVENT_JSON))
             .isInstanceOf(JsonEventSerializer.UnknownEventException.class);
     }
 
     @Test
     void serializeShouldHandleAllKnownEvents() throws Exception {
-        JsonEventSerializer jsonEventSerializer = new JsonEventSerializer(
-            TestEventDTOModules.TEST_TYPE,
-            TestEventDTOModules.OTHER_TEST_TYPE);
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(TestEventDTOModules.TEST_TYPE, TestEventDTOModules.OTHER_TEST_TYPE)
+            .withoutNestedType();
 
         assertThatJson(
             jsonEventSerializer.serialize(OTHER_EVENT))
@@ -74,9 +73,9 @@ class JsonEventSerializerTest {
 
     @Test
     void deserializeShouldHandleAllKnownEvents() throws Exception {
-        JsonEventSerializer jsonEventSerializer = new JsonEventSerializer(
-            TestEventDTOModules.TEST_TYPE,
-            TestEventDTOModules.OTHER_TEST_TYPE);
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(TestEventDTOModules.TEST_TYPE, TestEventDTOModules.OTHER_TEST_TYPE)
+            .withoutNestedType();
 
         assertThatJson(
             jsonEventSerializer.deserialize(OTHER_EVENT_JSON))
@@ -90,32 +89,32 @@ class JsonEventSerializerTest {
 
     @Test
     void deserializeShouldThrowWhenEventWithDuplicatedTypes() {
-        assertThatThrownBy(() -> new JsonEventSerializer(
-                TestEventDTOModules.TEST_TYPE,
-                TestEventDTOModules.OTHER_TEST_TYPE)
+        assertThatThrownBy(() -> JsonEventSerializer
+            .forModules(TestEventDTOModules.TEST_TYPE, TestEventDTOModules.OTHER_TEST_TYPE)
+            .withoutNestedType()
             .deserialize(DUPLICATE_TYPE_EVENT_JSON))
             .isInstanceOf(JsonEventSerializer.InvalidEventException.class);
     }
 
     @Test
     void deserializeShouldThrowWhenEventWithMissingType() {
-        assertThatThrownBy(() -> new JsonEventSerializer(
-                TestEventDTOModules.TEST_TYPE,
-                TestEventDTOModules.OTHER_TEST_TYPE)
+        assertThatThrownBy(() -> JsonEventSerializer
+            .forModules(TestEventDTOModules.TEST_TYPE, TestEventDTOModules.OTHER_TEST_TYPE)
+            .withoutNestedType()
             .deserialize(MISSING_TYPE_EVENT_JSON))
             .isInstanceOf(JsonEventSerializer.InvalidEventException.class);
     }
 
     @Test
     void shouldSerializeKnownEvent() throws Exception {
-        assertThatJson(new JsonEventSerializer(TestEventDTOModules.TEST_TYPE)
+        assertThatJson(JsonEventSerializer.forModules(TestEventDTOModules.TEST_TYPE).withoutNestedType()
             .serialize(TEST_EVENT))
             .isEqualTo(TEST_EVENT_JSON);
     }
 
     @Test
     void shouldThrowWhenSerializeUnknownEvent() {
-        assertThatThrownBy(() -> new JsonEventSerializer()
+        assertThatThrownBy(() -> JsonEventSerializer.forModules().withoutNestedType()
             .serialize(TEST_EVENT))
             .isInstanceOf(JsonEventSerializer.UnknownEventException.class);
     }
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 a9cfdcc..bc2c156 100644
--- a/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java
+++ b/json/src/main/java/org/apache/james/json/JsonGenericSerializer.java
@@ -20,6 +20,8 @@
 package org.apache.james.json;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Set;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
@@ -34,11 +36,40 @@ 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;
 import com.google.common.collect.Sets;
 
 public class JsonGenericSerializer<T, U extends DTO> {
 
+    public static <T, U extends DTO> RequireNestedConfiguration<T, U> forModules(Set<? extends DTOModule<? extends T, ? extends U>> modules) {
+        return nestedTypesModules -> {
+            ImmutableSet<DTOModule<? extends T, ? extends U>> dtoModules = ImmutableSet.copyOf(modules);
+            return new JsonGenericSerializer<>(dtoModules, ImmutableSet.copyOf(nestedTypesModules), new DTOConverter<>(dtoModules));
+        };
+    }
+
+    @SafeVarargs
+    public static <T, U extends DTO> RequireNestedConfiguration<T, U> forModules(DTOModule<? extends T, ? extends U>... modules) {
+        return forModules(ImmutableSet.copyOf(modules));
+    }
+
+    public interface RequireNestedConfiguration<T, U extends DTO> {
+        JsonGenericSerializer<T, U> withNestedTypeModules(Set<DTOModule<?, ?>> modules);
+
+        default JsonGenericSerializer<T, U> withNestedTypeModules(DTOModule<?, ?>... modules) {
+            return withNestedTypeModules(ImmutableSet.copyOf(modules));
+        }
+
+        default JsonGenericSerializer<T, U> withNestedTypeModules(Set<DTOModule<?, ?>>... modules) {
+            return withNestedTypeModules(Arrays.stream(modules).flatMap(Collection::stream).collect(Guavate.toImmutableSet()));
+        }
+
+        default JsonGenericSerializer<T, U> withoutNestedType() {
+            return withNestedTypeModules(ImmutableSet.of());
+        }
+    }
+
     public static class InvalidTypeException extends RuntimeException {
         public InvalidTypeException(String message) {
             super(message);
@@ -58,12 +89,7 @@ public class JsonGenericSerializer<T, U extends DTO> {
     private final ObjectMapper objectMapper;
     private final DTOConverter<T, U> dtoConverter;
 
-    @SafeVarargs
-    public static <T, U extends DTO> JsonGenericSerializer<T, U> of(DTOModule<T, U>... modules) {
-        return new JsonGenericSerializer<>(ImmutableSet.copyOf(modules), ImmutableSet.of(), DTOConverter.of(modules));
-    }
-
-    public JsonGenericSerializer(Set<? extends DTOModule<? extends T, ? extends U>> modules, Set<? extends DTOModule<?, ?>> nestedTypesModules, DTOConverter<T, U> converter) {
+    private JsonGenericSerializer(Set<? extends DTOModule<? extends T, ? extends U>> modules, Set<? extends DTOModule<?, ?>> nestedTypesModules, DTOConverter<T, U> converter) {
         this.dtoConverter = converter;
         this.objectMapper = buildObjectMapper(Sets.union(modules, nestedTypesModules));
     }
@@ -76,9 +102,10 @@ public class JsonGenericSerializer<T, U extends DTO> {
             .setSerializationInclusion(JsonInclude.Include.NON_ABSENT)
             .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
             .enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
-        modules.stream()
+        NamedType[] namedTypes = modules.stream()
             .map(module -> new NamedType(module.getDTOClass(), module.getDomainObjectType()))
-            .forEach(objectMapper::registerSubtypes);
+            .toArray(NamedType[]::new);
+        objectMapper.registerSubtypes(namedTypes);
         return objectMapper;
     }
 
diff --git a/json/src/test/java/org/apache/DTOConverterTest.java b/json/src/test/java/org/apache/DTOConverterTest.java
index d75fffe..6783b0e 100644
--- a/json/src/test/java/org/apache/DTOConverterTest.java
+++ b/json/src/test/java/org/apache/DTOConverterTest.java
@@ -43,15 +43,16 @@ import org.junit.jupiter.params.provider.MethodSource;
 class DTOConverterTest {
     private static final Optional<NestedType> NO_CHILD = Optional.empty();
     private static final Optional<DTO> NO_CHILD_DTO = Optional.empty();
-    private static final FirstDomainObject FIRST = new FirstDomainObject(Optional.of(1L), ZonedDateTime.parse("2016-04-03T02:01+07:00[Asia/Vientiane]"), "first payload", NO_CHILD);
-    private static final FirstDTO FIRST_DTO = new FirstDTO("first", Optional.of(1L), "2016-04-03T02:01+07:00[Asia/Vientiane]", "first payload", NO_CHILD_DTO);
-    private static final SecondDomainObject SECOND = new SecondDomainObject(UUID.fromString("4a2c853f-7ffc-4ce3-9410-a47e85b3b741"), "second payload", NO_CHILD);
-    private static final SecondDTO SECOND_DTO = new SecondDTO("second", "4a2c853f-7ffc-4ce3-9410-a47e85b3b741", "second payload", NO_CHILD_DTO);
+    private static final BaseType FIRST = new FirstDomainObject(Optional.of(1L), ZonedDateTime.parse("2016-04-03T02:01+07:00[Asia/Vientiane]"), "first payload", NO_CHILD);
+    private static final DTO FIRST_DTO = new FirstDTO("first", Optional.of(1L), "2016-04-03T02:01+07:00[Asia/Vientiane]", "first payload", NO_CHILD_DTO);
+    private static final BaseType SECOND = new SecondDomainObject(UUID.fromString("4a2c853f-7ffc-4ce3-9410-a47e85b3b741"), "second payload", NO_CHILD);
+    private static final DTO SECOND_DTO = new SecondDTO("second", "4a2c853f-7ffc-4ce3-9410-a47e85b3b741", "second payload", NO_CHILD_DTO);
 
     @SuppressWarnings("unchecked")
     @Test
     void shouldConvertFromKnownDTO() throws Exception {
-        assertThat(DTOConverter.of(TestModules.FIRST_TYPE)
+        assertThat(DTOConverter
+            .<BaseType, DTO>of(TestModules.FIRST_TYPE)
             .convert(FIRST_DTO))
             .contains(FIRST);
     }
@@ -105,7 +106,7 @@ class DTOConverterTest {
     @SuppressWarnings("unchecked")
     @Test
     void shouldConvertFromKnownDomainObject() throws Exception {
-        assertThat(DTOConverter.of(TestModules.FIRST_TYPE)
+        assertThat(DTOConverter.<BaseType, DTO>of(TestModules.FIRST_TYPE)
             .convert(FIRST))
             .hasValueSatisfying(result -> assertThat(result).isInstanceOf(FirstDTO.class).isEqualToComparingFieldByField(FIRST_DTO));
     }
diff --git a/json/src/test/java/org/apache/JsonGenericSerializerTest.java b/json/src/test/java/org/apache/JsonGenericSerializerTest.java
index 3fc6c45..d9bcde1 100644
--- a/json/src/test/java/org/apache/JsonGenericSerializerTest.java
+++ b/json/src/test/java/org/apache/JsonGenericSerializerTest.java
@@ -44,10 +44,10 @@ import org.junit.jupiter.params.provider.MethodSource;
 
 class JsonGenericSerializerTest {
     private static final Optional<NestedType> NO_CHILD = Optional.empty();
-    private static final FirstDomainObject FIRST = new FirstDomainObject(Optional.of(1L), ZonedDateTime.parse("2016-04-03T02:01+07:00[Asia/Vientiane]"), "first payload", NO_CHILD);
-    private static final SecondDomainObject SECOND = new SecondDomainObject(UUID.fromString("4a2c853f-7ffc-4ce3-9410-a47e85b3b741"), "second payload", NO_CHILD);
-    private static final SecondDomainObject SECOND_WITH_NESTED = new SecondDomainObject(UUID.fromString("4a2c853f-7ffc-4ce3-9410-a47e85b3b741"), "second payload", Optional.of(new FirstNestedType(12)));
-    private static final FirstDomainObject FIRST_WITH_NESTED = new FirstDomainObject(Optional.of(1L), ZonedDateTime.parse("2016-04-03T02:01+07:00[Asia/Vientiane]"), "payload", Optional.of(new SecondNestedType("bar")));
+    private static final BaseType FIRST = new FirstDomainObject(Optional.of(1L), ZonedDateTime.parse("2016-04-03T02:01+07:00[Asia/Vientiane]"), "first payload", NO_CHILD);
+    private static final BaseType SECOND = new SecondDomainObject(UUID.fromString("4a2c853f-7ffc-4ce3-9410-a47e85b3b741"), "second payload", NO_CHILD);
+    private static final BaseType SECOND_WITH_NESTED = new SecondDomainObject(UUID.fromString("4a2c853f-7ffc-4ce3-9410-a47e85b3b741"), "second payload", Optional.of(new FirstNestedType(12)));
+    private static final BaseType FIRST_WITH_NESTED = new FirstDomainObject(Optional.of(1L), ZonedDateTime.parse("2016-04-03T02:01+07:00[Asia/Vientiane]"), "payload", Optional.of(new SecondNestedType("bar")));
 
     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\"}";
@@ -56,51 +56,50 @@ class JsonGenericSerializerTest {
     private static final String SECOND_JSON = "{\"type\":\"second\",\"id\":\"4a2c853f-7ffc-4ce3-9410-a47e85b3b741\",\"payload\":\"second payload\"}";
     private static final String SECOND_WITH_NESTED_JSON = "{\"type\":\"second\",\"id\":\"4a2c853f-7ffc-4ce3-9410-a47e85b3b741\",\"payload\":\"second payload\", \"child\": {\"foo\": 12, \"type\": \"first-nested\"}}";
 
-    @SuppressWarnings("unchecked")
     @Test
     void shouldDeserializeKnownType() throws Exception {
-        assertThat(JsonGenericSerializer.of(TestModules.FIRST_TYPE)
+        assertThat(JsonGenericSerializer.forModules(TestModules.FIRST_TYPE).withoutNestedType()
             .deserialize(FIRST_JSON))
             .isEqualTo(FIRST);
     }
 
-    @SuppressWarnings("unchecked")
     @Test
     void shouldDeserializeNestedTypeWithSecond() throws Exception {
-        assertThat(JsonGenericSerializer.of(TestModules.FIRST_TYPE, TestModules.SECOND_TYPE, TestModules.FIRST_NESTED, TestModules.SECOND_NESTED)
+        assertThat(JsonGenericSerializer
+            .forModules(TestModules.FIRST_TYPE, TestModules.SECOND_TYPE)
+            .withNestedTypeModules(TestModules.FIRST_NESTED, TestModules.SECOND_NESTED)
             .deserialize(SECOND_WITH_NESTED_JSON))
             .isEqualTo(SECOND_WITH_NESTED);
     }
 
-    @SuppressWarnings("unchecked")
     @Test
     void shouldDeserializeNestedTypeWithFirst() throws Exception {
-        assertThat(JsonGenericSerializer.of(TestModules.FIRST_TYPE, TestModules.SECOND_TYPE, TestModules.FIRST_NESTED, TestModules.SECOND_NESTED)
+        assertThat(JsonGenericSerializer
+            .forModules(TestModules.FIRST_TYPE, TestModules.SECOND_TYPE)
+            .withNestedTypeModules(TestModules.FIRST_NESTED, TestModules.SECOND_NESTED)
             .deserialize(FIRST_JSON_WITH_NESTED))
             .isEqualTo(FIRST_WITH_NESTED);
     }
 
-    @SuppressWarnings("unchecked")
     @Test
     void shouldThrowWhenDeserializeEventWithMissingType() {
-        assertThatThrownBy(() -> JsonGenericSerializer.of(TestModules.FIRST_TYPE)
+        assertThatThrownBy(() -> JsonGenericSerializer.forModules(TestModules.FIRST_TYPE).withoutNestedType()
             .deserialize(MISSING_TYPE_JSON))
             .isInstanceOf(JsonGenericSerializer.InvalidTypeException.class);
     }
 
-    @SuppressWarnings("unchecked")
     @Test
     void shouldThrowWhenDeserializeEventWithDuplicatedTypes() {
-        assertThatThrownBy(() -> JsonGenericSerializer.of(
-                TestModules.FIRST_TYPE,
-                TestModules.SECOND_TYPE)
+        assertThatThrownBy(() -> JsonGenericSerializer
+            .forModules(TestModules.FIRST_TYPE, TestModules.SECOND_TYPE)
+            .withoutNestedType()
             .deserialize(DUPLICATE_TYPE_JSON))
             .isInstanceOf(JsonGenericSerializer.InvalidTypeException.class);
     }
 
     @Test
     void shouldThrowWhenDeserializeUnknownType() {
-        assertThatThrownBy(() -> JsonGenericSerializer.of()
+        assertThatThrownBy(() -> JsonGenericSerializer.forModules().withoutNestedType()
             .deserialize(FIRST_JSON))
             .isInstanceOf(JsonGenericSerializer.UnknownTypeException.class);
     }
@@ -108,12 +107,11 @@ class JsonGenericSerializerTest {
     @ParameterizedTest
     @MethodSource
     void serializeShouldHandleAllKnownTypes(BaseType domainObject, String serializedJson) throws Exception {
-        @SuppressWarnings("unchecked")
-        JsonGenericSerializer<BaseType, DTO> serializer = JsonGenericSerializer.of(
-                TestModules.FIRST_TYPE,
-                TestModules.SECOND_TYPE);
 
-        assertThatJson(serializer.serialize(domainObject))
+        assertThatJson(JsonGenericSerializer
+            .forModules(TestModules.FIRST_TYPE, TestModules.SECOND_TYPE)
+            .withoutNestedType()
+            .serialize(domainObject))
             .isEqualTo(serializedJson);
     }
 
@@ -124,12 +122,10 @@ class JsonGenericSerializerTest {
     @ParameterizedTest
     @MethodSource
     void deserializeShouldHandleAllKnownTypes(BaseType domainObject, String serializedJson) throws Exception {
-        @SuppressWarnings("unchecked")
-        JsonGenericSerializer<BaseType, DTO> serializer = JsonGenericSerializer.of(
-                TestModules.FIRST_TYPE,
-                TestModules.SECOND_TYPE);
-
-        assertThatJson(serializer.deserialize(serializedJson))
+        assertThatJson(JsonGenericSerializer
+            .forModules(TestModules.FIRST_TYPE, TestModules.SECOND_TYPE)
+            .withoutNestedType()
+            .deserialize(serializedJson))
             .isEqualTo(domainObject);
     }
 
@@ -144,17 +140,20 @@ class JsonGenericSerializerTest {
         );
     }
 
-    @SuppressWarnings("unchecked")
     @Test
     void shouldSerializeKnownType() throws Exception {
-        assertThatJson(JsonGenericSerializer.of(TestModules.FIRST_TYPE)
+        assertThatJson(JsonGenericSerializer
+            .<BaseType, DTO>forModules(TestModules.FIRST_TYPE)
+            .withoutNestedType()
             .serialize(FIRST))
             .isEqualTo(FIRST_JSON);
     }
 
     @Test
     void shouldThrowWhenSerializeUnknownType() {
-        assertThatThrownBy(() -> JsonGenericSerializer.of()
+        assertThatThrownBy(() -> JsonGenericSerializer
+            .forModules()
+            .withoutNestedType()
             .serialize(FIRST))
             .isInstanceOf(JsonGenericSerializer.UnknownTypeException.class);
     }
diff --git a/json/src/test/java/org/apache/dto/TestModules.java b/json/src/test/java/org/apache/dto/TestModules.java
index ad4d04b..d7cb781 100644
--- a/json/src/test/java/org/apache/dto/TestModules.java
+++ b/json/src/test/java/org/apache/dto/TestModules.java
@@ -24,7 +24,7 @@ import org.apache.james.json.DTOConverter;
 import org.apache.james.json.DTOModule;
 
 public interface TestModules {
-    TestNestedModule FIRST_NESTED = DTOModule
+    TestNestedModule<?, ?> FIRST_NESTED = DTOModule
         .forDomainObject(FirstNestedType.class)
         .convertToDTO(FirstNestedDTO.class)
         .toDomainObjectConverter(FirstNestedDTO::toDomainObject)
@@ -34,7 +34,7 @@ public interface TestModules {
             .typeName("first-nested")
         .withFactory(TestNestedModule::new);
 
-    TestNestedModule SECOND_NESTED = DTOModule
+    TestNestedModule<?, ?> SECOND_NESTED = DTOModule
         .forDomainObject(SecondNestedType.class)
         .convertToDTO(SecondNestedDTO.class)
         .toDomainObjectConverter(SecondNestedDTO::toDomainObject)
@@ -44,10 +44,9 @@ public interface TestModules {
         .typeName("second-nested")
         .withFactory(TestNestedModule::new);
 
-    DTOConverter NESTED_CONVERTERS = DTOConverter.of(FIRST_NESTED, SECOND_NESTED);
+    DTOConverter<NestedType, DTO> NESTED_CONVERTERS = DTOConverter.of(FIRST_NESTED, SECOND_NESTED);
 
-    @SuppressWarnings("rawtypes")
-    TestModule FIRST_TYPE = DTOModule
+    TestModule<?, ?> FIRST_TYPE = DTOModule
         .forDomainObject(FirstDomainObject.class)
         .convertToDTO(FirstDTO.class)
         .toDomainObjectConverter(dto -> dto.toDomainObject(NESTED_CONVERTERS))
@@ -56,12 +55,11 @@ public interface TestModules {
             domainObject.getId(),
             domainObject.getTime().toString(),
             domainObject.getPayload(),
-            NESTED_CONVERTERS.convert(domainObject.getChild())))
+            domainObject.getChild().flatMap(NESTED_CONVERTERS::convert)))
         .typeName("first")
         .withFactory(TestModule::new);
 
-    @SuppressWarnings("rawtypes")
-    TestModule SECOND_TYPE = DTOModule
+    TestModule<?, ?> SECOND_TYPE = DTOModule
         .forDomainObject(SecondDomainObject.class)
         .convertToDTO(SecondDTO.class)
         .toDomainObjectConverter(dto -> dto.toDomainObject(NESTED_CONVERTERS))
@@ -69,7 +67,7 @@ public interface TestModules {
             typeName,
             domainObject.getId().toString(),
             domainObject.getPayload(),
-            NESTED_CONVERTERS.convert(domainObject.getChild())))
+            domainObject.getChild().flatMap(NESTED_CONVERTERS::convert)))
         .typeName("second")
         .withFactory(TestModule::new);
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTaskSerializationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTaskSerializationTest.java
index f0a0277..4012d94 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTaskSerializationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTaskSerializationTest.java
@@ -30,9 +30,9 @@ import java.time.Instant;
 import org.apache.james.server.task.json.JsonTaskAdditionalInformationSerializer;
 import org.apache.james.server.task.json.JsonTaskSerializer;
 import org.apache.james.task.TaskExecutionDetails;
+import org.junit.jupiter.api.Test;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
-import org.junit.jupiter.api.Test;
 
 class MailboxPathV2MigrationTaskSerializationTest {
     private static final Instant TIMESTAMP = Instant.parse("2018-11-13T12:00:55Z");
@@ -42,8 +42,8 @@ class MailboxPathV2MigrationTaskSerializationTest {
     private static final MailboxPathV2Migration.AdditionalInformation DETAILS = new MailboxPathV2Migration.AdditionalInformation(42L, 10, TIMESTAMP);
     private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{\"type\": \"cassandra-mailbox-path-v2-migration\", \"remainingCount\":42,\"initialCount\":10, \"timestamp\":\"2018-11-13T12:00:55Z\"}";
 
-    private static final JsonTaskSerializer TASK_SERIALIZER = new JsonTaskSerializer(MailboxPathV2MigrationTaskDTO.MODULE.apply(MIGRATION));
-    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(MailboxPathV2MigrationTaskAdditionalInformationDTO.MODULE);
+    private static final JsonTaskSerializer TASK_SERIALIZER = JsonTaskSerializer.of(MailboxPathV2MigrationTaskDTO.MODULE.apply(MIGRATION));
+    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(MailboxPathV2MigrationTaskAdditionalInformationDTO.MODULE);
 
     @Test
     void taskShouldBeSerializable() throws JsonProcessingException {
@@ -63,12 +63,13 @@ class MailboxPathV2MigrationTaskSerializationTest {
     }
 
     @Test
-    void additonalInformationShouldBeDeserializable() throws IOException {
+    void additionalInformationShouldBeDeserializable() throws IOException {
         TaskExecutionDetails.AdditionalInformation deserialized = JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER.deserialize(SERIALIZED_ADDITIONAL_INFORMATION);
-        assertThat(deserialized).isInstanceOf(MailboxPathV2Migration.AdditionalInformation.class);
-
-        MailboxPathV2Migration.AdditionalInformation additionalInformation = (MailboxPathV2Migration.AdditionalInformation) deserialized;
-        assertThat(additionalInformation.getRemainingCount()).isEqualTo(DETAILS.getRemainingCount());
-        assertThat(additionalInformation.getInitialCount()).isEqualTo(DETAILS.getInitialCount());
+        assertThat(deserialized).isInstanceOfSatisfying(MailboxPathV2Migration.AdditionalInformation.class,
+            additionalInformation -> {
+                assertThat(additionalInformation.getRemainingCount()).isEqualTo(DETAILS.getRemainingCount());
+                assertThat(additionalInformation.getInitialCount()).isEqualTo(DETAILS.getInitialCount());
+            }
+        );
     }
 }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskTest.java
index 4e7b48e..dabac7c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskTest.java
@@ -29,10 +29,10 @@ import java.time.Instant;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.server.task.json.JsonTaskAdditionalInformationSerializer;
 import org.apache.james.server.task.json.JsonTaskSerializer;
+import org.junit.jupiter.api.Test;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
-import org.junit.jupiter.api.Test;
 
 class MailboxMergingTaskTest {
     private static final Instant TIMESTAMP = Instant.parse("2018-11-13T12:00:55Z");
@@ -42,8 +42,8 @@ class MailboxMergingTaskTest {
     private static final MailboxMergingTaskRunner TASK_RUNNER = mock(MailboxMergingTaskRunner.class);
     private static final MailboxMergingTask TASK = new MailboxMergingTask(TASK_RUNNER, 0L, CASSANDRA_ID_FACTORY.fromString("3b8e5f90-b94f-20f8-ce7b-3c4aad93b90c"), CASSANDRA_ID_FACTORY.fromString("2c7f4081-aa30-11e9-bf6c-2d3b9e84aafd"));
     private static final MailboxMergingTask.Details DETAILS = new MailboxMergingTask.Details(CASSANDRA_ID_FACTORY.fromString("3b8e5f90-b94f-20f8-ce7b-3c4aad93b90c"), CASSANDRA_ID_FACTORY.fromString("2c7f4081-aa30-11e9-bf6c-2d3b9e84aafd"), 10, 15, 20, TIMESTAMP);
-    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(MailboxMergingTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
-    private static final JsonTaskSerializer TESTEE = new JsonTaskSerializer(MailboxMergingTaskDTO.module(TASK_RUNNER));
+    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(MailboxMergingTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
+    private static final JsonTaskSerializer TESTEE = JsonTaskSerializer.of(MailboxMergingTaskDTO.module(TASK_RUNNER));
 
     @Test
     void taskShouldBeSerializable() throws JsonProcessingException {
diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BlobStoreVaultGarbageCollectionTaskSerializationTest.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BlobStoreVaultGarbageCollectionTaskSerializationTest.java
index 6852dd7..ab2fff9 100644
--- a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BlobStoreVaultGarbageCollectionTaskSerializationTest.java
+++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BlobStoreVaultGarbageCollectionTaskSerializationTest.java
@@ -32,21 +32,19 @@ import org.apache.james.blob.api.BucketName;
 import org.apache.james.server.task.json.JsonTaskAdditionalInformationSerializer;
 import org.apache.james.server.task.json.JsonTaskSerializer;
 import org.apache.james.task.Task;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.common.collect.ImmutableList;
-
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.collect.ImmutableList;
 import reactor.core.publisher.Flux;
 
 class BlobStoreVaultGarbageCollectionTaskSerializationTest {
    private static final BlobStoreDeletedMessageVault DELETED_MESSAGE_VAULT = Mockito.mock(BlobStoreDeletedMessageVault.class);
    private static final BlobStoreVaultGarbageCollectionTask.Factory TASK_FACTORY = new BlobStoreVaultGarbageCollectionTask.Factory(DELETED_MESSAGE_VAULT);
 
-    private static final JsonTaskSerializer TASK_SERIALIZER = new JsonTaskSerializer(BlobStoreVaultGarbageCollectionTaskDTO.module(TASK_FACTORY));
+    private static final JsonTaskSerializer TASK_SERIALIZER = JsonTaskSerializer.of(BlobStoreVaultGarbageCollectionTaskDTO.module(TASK_FACTORY));
     private static final ZonedDateTime BEGINNING_OF_RETENTION_PERIOD = ZonedDateTime.parse("2019-09-03T15:26:13.356+02:00[Europe/Paris]");
     private static final ImmutableList<BucketName> BUCKET_IDS = ImmutableList.of(BucketName.of("1"), BucketName.of("2"), BucketName.of("3"));
     private static final Flux<BucketName> RETENTION_OPERATION = Flux.fromIterable(BUCKET_IDS);
@@ -57,7 +55,7 @@ class BlobStoreVaultGarbageCollectionTaskSerializationTest {
     private static final String SERIALIZED_TASK = "{\"type\":\"deleted-messages-blob-store-based-garbage-collection\"}";
     private static final String SERIALIZED_ADDITIONAL_INFORMATION_TASK = "{\"type\":\"deleted-messages-blob-store-based-garbage-collection\", \"beginningOfRetentionPeriod\":\"2019-09-03T15:26:13.356+02:00[Europe/Paris]\",\"deletedBuckets\":[\"1\", \"2\", \"3\"], \"timestamp\": \"2018-11-13T12:00:55Z\"}";
 
-    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(BlobStoreVaultGarbageCollectionTaskAdditionalInformationDTO.MODULE);
+    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(BlobStoreVaultGarbageCollectionTaskAdditionalInformationDTO.MODULE);
 
     @BeforeAll
     static void setUp() {
diff --git a/mailbox/plugin/quota-mailing-cassandra/src/test/java/org/apache/james/mailbox/quota/cassandra/dto/DTOTest.java b/mailbox/plugin/quota-mailing-cassandra/src/test/java/org/apache/james/mailbox/quota/cassandra/dto/DTOTest.java
index 2311487..394bf6f 100644
--- a/mailbox/plugin/quota-mailing-cassandra/src/test/java/org/apache/james/mailbox/quota/cassandra/dto/DTOTest.java
+++ b/mailbox/plugin/quota-mailing-cassandra/src/test/java/org/apache/james/mailbox/quota/cassandra/dto/DTOTest.java
@@ -148,56 +148,56 @@ class DTOTest {
 
     @Test
     void shouldSerializeQuotaThresholdChangedEvent() throws Exception {
-        assertThatJson(new JsonEventSerializer(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE)
+        assertThatJson(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType()
             .serialize(EVENT))
             .isEqualTo(EVENT_JSON);
     }
 
     @Test
     void shouldDeserializeQuotaThresholdChangedEvent() throws Exception {
-        assertThat(new JsonEventSerializer(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE)
+        assertThat(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType()
             .deserialize(EVENT_JSON))
             .isEqualTo(EVENT);
     }
 
     @Test
     void shouldSerializeEvent2() throws Exception {
-        assertThatJson(new JsonEventSerializer(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE)
+        assertThatJson(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType()
             .serialize(EVENT_2))
             .isEqualTo(EVENT_JSON_2);
     }
 
     @Test
     void shouldDeserializeEvent2() throws Exception {
-        assertThat(new JsonEventSerializer(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE)
+        assertThat(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType()
             .deserialize(EVENT_JSON_2))
             .isEqualTo(EVENT_2);
     }
 
     @Test
     void shouldSerializeEvent3() throws Exception {
-        assertThatJson(new JsonEventSerializer(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE)
+        assertThatJson(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType()
             .serialize(EVENT_3))
             .isEqualTo(EVENT_JSON_3);
     }
 
     @Test
     void shouldDeserializeEvent3() throws Exception {
-        assertThat(new JsonEventSerializer(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE)
+        assertThat(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType()
             .deserialize(EVENT_JSON_3))
             .isEqualTo(EVENT_3);
     }
 
     @Test
     void shouldSerializeEvent4() throws Exception {
-        assertThatJson(new JsonEventSerializer(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE)
+        assertThatJson(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType()
             .serialize(EVENT_4))
             .isEqualTo(EVENT_JSON_4);
     }
 
     @Test
     void shouldDeserializeEvent4() throws Exception {
-        assertThat(new JsonEventSerializer(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE)
+        assertThat(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType()
             .deserialize(EVENT_JSON_4))
             .isEqualTo(EVENT_4);
     }
diff --git a/mailbox/plugin/quota-mailing-cassandra/src/test/java/org/apache/james/mailbox/quota/cassandra/listeners/CassandraQuotaMailingListenersIntegrationTest.java b/mailbox/plugin/quota-mailing-cassandra/src/test/java/org/apache/james/mailbox/quota/cassandra/listeners/CassandraQuotaMailingListenersIntegrationTest.java
index 8864507..55c3c44 100644
--- a/mailbox/plugin/quota-mailing-cassandra/src/test/java/org/apache/james/mailbox/quota/cassandra/listeners/CassandraQuotaMailingListenersIntegrationTest.java
+++ b/mailbox/plugin/quota-mailing-cassandra/src/test/java/org/apache/james/mailbox/quota/cassandra/listeners/CassandraQuotaMailingListenersIntegrationTest.java
@@ -20,11 +20,13 @@
 package org.apache.james.mailbox.quota.cassandra.listeners;
 
 import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreExtension;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
 import org.apache.james.mailbox.quota.cassandra.dto.QuotaEventDTOModules;
 import org.apache.james.mailbox.quota.mailing.listeners.QuotaThresholdMailingIntegrationTest;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 class CassandraQuotaMailingListenersIntegrationTest implements QuotaThresholdMailingIntegrationTest {
     @RegisterExtension
-    static CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE);
+    static CassandraEventStoreExtension eventStoreExtension =
+        new CassandraEventStoreExtension(JsonEventSerializer.forModules(QuotaEventDTOModules.QUOTA_THRESHOLD_CHANGE).withoutNestedType());
 }
diff --git a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/ErrorRecoveryIndexationTaskSerializationTest.java b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/ErrorRecoveryIndexationTaskSerializationTest.java
index cbc823c..d71ad03 100644
--- a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/ErrorRecoveryIndexationTaskSerializationTest.java
+++ b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/ErrorRecoveryIndexationTaskSerializationTest.java
@@ -33,7 +33,6 @@ import org.apache.james.server.task.json.JsonTaskAdditionalInformationSerializer
 import org.apache.james.server.task.json.JsonTaskSerializer;
 import org.apache.james.task.Task;
 import org.apache.mailbox.tools.indexer.ReprocessingContextInformationDTO.ReprocessingContextInformationForErrorRecoveryIndexationTask;
-
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -71,9 +70,9 @@ class ErrorRecoveryIndexationTaskSerializationTest {
     void setUp() {
         reIndexerPerformer = mock(ReIndexerPerformer.class);
         ErrorRecoveryIndexationTask.Factory factory = new ErrorRecoveryIndexationTask.Factory(reIndexerPerformer, mailboxIdFactory);
-        taskSerializer = new JsonTaskSerializer(ErrorRecoveryIndexationTaskDTO.module(factory));
+        taskSerializer = JsonTaskSerializer.of(ErrorRecoveryIndexationTaskDTO.module(factory));
 
-        jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+        jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
             ReprocessingContextInformationForErrorRecoveryIndexationTask.serializationModule(mailboxIdFactory));
 
         reIndexingExecutionFailures = new ReIndexingExecutionFailures(ImmutableList.of(
diff --git a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/FullReindexingTaskSerializationTest.java b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/FullReindexingTaskSerializationTest.java
index 0c1a34b..3d0f9c5 100644
--- a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/FullReindexingTaskSerializationTest.java
+++ b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/FullReindexingTaskSerializationTest.java
@@ -61,9 +61,9 @@ class FullReindexingTaskSerializationTest {
     @BeforeEach
     void setUp() {
         reIndexerPerformer = mock(ReIndexerPerformer.class);
-        taskSerializer = new JsonTaskSerializer(FullReindexingTask.module(reIndexerPerformer));
+        taskSerializer = JsonTaskSerializer.of(FullReindexingTask.module(reIndexerPerformer));
 
-        jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+        jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
             ReprocessingContextInformationForFullReindexingTask.serializationModule(new TestId.Factory()));
 
         reIndexingExecutionFailures = new ReIndexingExecutionFailures(ImmutableList.of(
diff --git a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/MessageIdReindexingTaskSerializationTest.java b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/MessageIdReindexingTaskSerializationTest.java
index c1a873e..4c27cef 100644
--- a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/MessageIdReindexingTaskSerializationTest.java
+++ b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/MessageIdReindexingTaskSerializationTest.java
@@ -49,11 +49,11 @@ class MessageIdReindexingTaskSerializationTest {
     @BeforeEach
     void setUp() {
         messageIdFactory = new TestMessageId.Factory();
-        jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+        jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
             MessageIdReindexingTaskAdditionalInformationDTO.serializationModule(messageIdFactory));
         reIndexerPerformer = mock(ReIndexerPerformer.class);
         MessageIdReIndexingTask.Factory factory = new MessageIdReIndexingTask.Factory(reIndexerPerformer, messageIdFactory);
-        taskSerializer = new JsonTaskSerializer(MessageIdReindexingTaskDTO.module(factory));
+        taskSerializer = JsonTaskSerializer.of(MessageIdReindexingTaskDTO.module(factory));
     }
 
     @Test
diff --git a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/SingleMailboxReindexingTaskSerializationTest.java b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/SingleMailboxReindexingTaskSerializationTest.java
index 0ce4f36..b5c23c7 100644
--- a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/SingleMailboxReindexingTaskSerializationTest.java
+++ b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/SingleMailboxReindexingTaskSerializationTest.java
@@ -65,9 +65,9 @@ class SingleMailboxReindexingTaskSerializationTest {
     void setUp() {
         reIndexerPerformer = mock(ReIndexerPerformer.class);
         SingleMailboxReindexingTask.Factory factory = new SingleMailboxReindexingTask.Factory(reIndexerPerformer, new TestId.Factory());
-        taskSerializer = new JsonTaskSerializer(SingleMailboxReindexingTaskDTO.module(factory));
+        taskSerializer = JsonTaskSerializer.of(SingleMailboxReindexingTaskDTO.module(factory));
 
-        jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+        jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
             SingleMailboxReindexingTaskAdditionalInformationDTO.serializationModule(new TestId.Factory()));
 
         reIndexingExecutionFailures = new ReIndexingExecutionFailures(ImmutableList.of(
diff --git a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/SingleMessageReindexingTaskSerializationTest.java b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/SingleMessageReindexingTaskSerializationTest.java
index 9ba44ee..b97441b 100644
--- a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/SingleMessageReindexingTaskSerializationTest.java
+++ b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/SingleMessageReindexingTaskSerializationTest.java
@@ -45,14 +45,14 @@ class SingleMessageReindexingTaskSerializationTest {
     private final String SERIALIZED_ADDITIONAL_INFORMATION = "{\"type\": \"message-reindexing\", \"mailboxId\": \"1\", \"uid\": 10, \"timestamp\":\"2018-11-13T12:00:55Z\"}";
     private final TestId mailboxId = TestId.of(1L);
     private final MessageUid messageUid = MessageUid.of(10L);
-    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
         SingleMessageReindexingTaskAdditionalInformationDTO.serializationModule(mailboxIdFactory));
 
     @BeforeEach
     void setUp() {
         reIndexerPerformer = mock(ReIndexerPerformer.class);
         SingleMessageReindexingTask.Factory factory = new SingleMessageReindexingTask.Factory(reIndexerPerformer, mailboxIdFactory);
-        taskSerializer = new JsonTaskSerializer(SingleMessageReindexingTaskDTO.module(factory));
+        taskSerializer = JsonTaskSerializer.of(SingleMessageReindexingTaskDTO.module(factory));
     }
 
     @Test
diff --git a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/UserReindexingTaskSerializationTest.java b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/UserReindexingTaskSerializationTest.java
index 701c131..ce2135a 100644
--- a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/UserReindexingTaskSerializationTest.java
+++ b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/UserReindexingTaskSerializationTest.java
@@ -68,8 +68,8 @@ class UserReindexingTaskSerializationTest {
     void setUp() {
         reIndexerPerformer = mock(ReIndexerPerformer.class);
         UserReindexingTask.Factory factory = new UserReindexingTask.Factory(reIndexerPerformer);
-        taskSerializer = new JsonTaskSerializer(UserReindexingTaskDTO.module(factory));
-        jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+        taskSerializer = JsonTaskSerializer.of(UserReindexingTaskDTO.module(factory));
+        jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
             UserReindexingTaskAdditionalInformationDTO.serializationModule(new TestId.Factory()));
 
         reIndexingExecutionFailures = new ReIndexingExecutionFailures(ImmutableList.of(
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/dlp/eventsourcing/cassandra/CassandraEventSourcingDLPConfigurationStoreExtension.java b/server/data/data-cassandra/src/test/java/org/apache/james/dlp/eventsourcing/cassandra/CassandraEventSourcingDLPConfigurationStoreExtension.java
index bc81db2..d438db7 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/dlp/eventsourcing/cassandra/CassandraEventSourcingDLPConfigurationStoreExtension.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/dlp/eventsourcing/cassandra/CassandraEventSourcingDLPConfigurationStoreExtension.java
@@ -35,8 +35,6 @@ import org.junit.jupiter.api.extension.ParameterContext;
 import org.junit.jupiter.api.extension.ParameterResolutionException;
 import org.junit.jupiter.api.extension.ParameterResolver;
 
-import com.google.common.collect.ImmutableSet;
-
 public class CassandraEventSourcingDLPConfigurationStoreExtension implements BeforeAllCallback, AfterAllCallback, AfterEachCallback, ParameterResolver {
 
     private final DockerCassandraExtension dockerCassandraExtension;
@@ -72,9 +70,9 @@ public class CassandraEventSourcingDLPConfigurationStoreExtension implements Bef
 
     @Override
     public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
-        JsonEventSerializer jsonEventSerializer = new JsonEventSerializer(
-                DLPConfigurationModules.DLP_CONFIGURATION_STORE,
-                DLPConfigurationModules.DLP_CONFIGURATION_CLEAR);
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(DLPConfigurationModules.DLP_CONFIGURATION_STORE, DLPConfigurationModules.DLP_CONFIGURATION_CLEAR)
+            .withoutNestedType();
 
         EventStoreDao eventStoreDao = new EventStoreDao(
             cassandra.getConf(),
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/migration/MappingsSourcesMigrationTaskSerializationTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/migration/MappingsSourcesMigrationTaskSerializationTest.java
index e98fb43..edae144 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/migration/MappingsSourcesMigrationTaskSerializationTest.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/migration/MappingsSourcesMigrationTaskSerializationTest.java
@@ -29,9 +29,9 @@ import java.time.Instant;
 
 import org.apache.james.server.task.json.JsonTaskAdditionalInformationSerializer;
 import org.apache.james.server.task.json.JsonTaskSerializer;
+import org.junit.jupiter.api.Test;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
-import org.junit.jupiter.api.Test;
 
 class MappingsSourcesMigrationTaskSerializationTest {
     private static final Instant TIMESTAMP = Instant.parse("2018-11-13T12:00:55Z");
@@ -41,8 +41,8 @@ class MappingsSourcesMigrationTaskSerializationTest {
     private static final MappingsSourcesMigration.AdditionalInformation DETAILS = new MappingsSourcesMigration.AdditionalInformation(42L, 10, TIMESTAMP);
     private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{\"type\": \"mappings-sources-migration\", \"successfulMappingsCount\":42,\"errorMappingsCount\":10,\"timestamp\":\"2018-11-13T12:00:55Z\"}";
 
-    private static final JsonTaskSerializer TASK_SERIALIZER = new JsonTaskSerializer(MappingsSourcesMigrationTaskDTO.MODULE.apply(MIGRATION));
-    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(MappingsSourcesMigrationTaskAdditionalInformationDTO.serializationModule(MappingsSourcesMigration.TYPE));
+    private static final JsonTaskSerializer TASK_SERIALIZER = JsonTaskSerializer.of(MappingsSourcesMigrationTaskDTO.MODULE.apply(MIGRATION));
+    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(MappingsSourcesMigrationTaskAdditionalInformationDTO.serializationModule(MappingsSourcesMigration.TYPE));
 
     @Test
     void taskShouldBeSerializable() throws JsonProcessingException {
diff --git a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/CassandraEventSourcingFilteringManagementTest.java b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/CassandraEventSourcingFilteringManagementTest.java
index 68be998..555581e 100644
--- a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/CassandraEventSourcingFilteringManagementTest.java
+++ b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/filtering/CassandraEventSourcingFilteringManagementTest.java
@@ -20,10 +20,12 @@
 package org.apache.james.jmap.cassandra.filtering;
 
 import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreExtension;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
 import org.apache.james.jmap.api.filtering.FilteringManagementContract;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 class CassandraEventSourcingFilteringManagementTest implements FilteringManagementContract {
     @RegisterExtension
-    static CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(FilteringRuleSetDefineDTOModules.FILTERING_RULE_SET_DEFINED);
+    static CassandraEventStoreExtension eventStoreExtension =
+        new CassandraEventStoreExtension(JsonEventSerializer.forModules(FilteringRuleSetDefineDTOModules.FILTERING_RULE_SET_DEFINED).withoutNestedType());
 }
diff --git a/server/protocols/webadmin/webadmin-cassandra-data/src/test/java/org/apache/james/webadmin/service/CassandraMappingsSolveInconsistenciesTaskTest.java b/server/protocols/webadmin/webadmin-cassandra-data/src/test/java/org/apache/james/webadmin/service/CassandraMappingsSolveInconsistenciesTaskTest.java
index 9aa17cb..5faaa81 100644
--- a/server/protocols/webadmin/webadmin-cassandra-data/src/test/java/org/apache/james/webadmin/service/CassandraMappingsSolveInconsistenciesTaskTest.java
+++ b/server/protocols/webadmin/webadmin-cassandra-data/src/test/java/org/apache/james/webadmin/service/CassandraMappingsSolveInconsistenciesTaskTest.java
@@ -24,20 +24,20 @@ import static org.mockito.Mockito.mock;
 
 import java.io.IOException;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
 import org.apache.james.rrt.cassandra.CassandraMappingsSourcesDAO;
 import org.apache.james.rrt.cassandra.migration.MappingsSourcesMigration;
 import org.apache.james.server.task.json.JsonTaskSerializer;
+import org.junit.jupiter.api.Test;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
-import org.junit.jupiter.api.Test;
 
 class CassandraMappingsSolveInconsistenciesTaskTest {
     private static final String SERIALIZED = "{\"type\":\"cassandra-mappings-solve-inconsistencies\"}";
     private static final MappingsSourcesMigration MAPPINGS_SOURCES_MIGRATION = mock(MappingsSourcesMigration.class);
     private static final CassandraMappingsSourcesDAO CASSANDRA_MAPPINGS_SOURCES_DAO = mock(CassandraMappingsSourcesDAO.class);
     private static final CassandraMappingsSolveInconsistenciesTask TASK = new CassandraMappingsSolveInconsistenciesTask(MAPPINGS_SOURCES_MIGRATION, CASSANDRA_MAPPINGS_SOURCES_DAO);
-    private static final JsonTaskSerializer TESTEE = new JsonTaskSerializer(CassandraMappingsSolveInconsistenciesTask.module(MAPPINGS_SOURCES_MIGRATION, CASSANDRA_MAPPINGS_SOURCES_DAO));
+    private static final JsonTaskSerializer TESTEE = JsonTaskSerializer.of(CassandraMappingsSolveInconsistenciesTask.module(MAPPINGS_SOURCES_MIGRATION, CASSANDRA_MAPPINGS_SOURCES_DAO));
 
     @Test
     void taskShouldBeSerializable() throws JsonProcessingException {
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultDeleteTaskSerializationTest.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultDeleteTaskSerializationTest.java
index 8706f96..38277cc 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultDeleteTaskSerializationTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultDeleteTaskSerializationTest.java
@@ -56,8 +56,8 @@ class DeletedMessagesVaultDeleteTaskSerializationTest {
     void setUp() {
         deletedMessageVault = mock(DeletedMessageVault.class);
         DeletedMessagesVaultDeleteTask.Factory factory = new DeletedMessagesVaultDeleteTask.Factory(deletedMessageVault, messageIdFactory);
-        taskSerializer = new JsonTaskSerializer(DeletedMessagesVaultDeleteTaskDTO.module(factory));
-        jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(DeletedMessagesVaultDeleteTaskAdditionalInformationDTO.serializationModule(messageIdFactory));
+        taskSerializer = JsonTaskSerializer.of(DeletedMessagesVaultDeleteTaskDTO.module(factory));
+        jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(DeletedMessagesVaultDeleteTaskAdditionalInformationDTO.serializationModule(messageIdFactory));
     }
 
     @Test
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultExportTaskSerializationTest.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultExportTaskSerializationTest.java
index 65f0b0f..bee616e 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultExportTaskSerializationTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultExportTaskSerializationTest.java
@@ -65,7 +65,7 @@ class DeletedMessagesVaultExportTaskSerializationTest {
         "\"exportTo\":\"james@apache.org\"}\n";
     private static final String SERIALIZED_ADDITIONAL_INFORMATION_TASK = "{\"type\":\"deleted-messages-export\", \"exportTo\":\"james@apache.org\",\"userExportFrom\":\"james\",\"totalExportedMessages\":42, \"timestamp\":\"2018-11-13T12:00:55Z\"}";
 
-    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(DeletedMessagesVaultExportTaskAdditionalInformationDTO.MODULE);
+    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(DeletedMessagesVaultExportTaskAdditionalInformationDTO.MODULE);
 
     @BeforeAll
     static void init() throws AddressException {
@@ -77,7 +77,7 @@ class DeletedMessagesVaultExportTaskSerializationTest {
     void setUp() {
         exportService = mock(ExportService.class);
         DeletedMessagesVaultExportTaskDTO.Factory factory = new DeletedMessagesVaultExportTaskDTO.Factory(exportService, queryTranslator);
-        taskSerializer = new JsonTaskSerializer(DeletedMessagesVaultExportTaskDTO.module(factory));
+        taskSerializer = JsonTaskSerializer.of(DeletedMessagesVaultExportTaskDTO.module(factory));
     }
 
     @Test
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRestoreTaskSerializationTest.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRestoreTaskSerializationTest.java
index 4bfa982..42e6f20 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRestoreTaskSerializationTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRestoreTaskSerializationTest.java
@@ -59,13 +59,13 @@ class DeletedMessagesVaultRestoreTaskSerializationTest {
         "}";
     private static final String SERIALIZED_ADDITIONAL_INFORMATION_TASK = "{\"type\":\"deleted-messages-restore\", \"user\":\"james\",\"successfulRestoreCount\":42,\"errorRestoreCount\":10, \"timestamp\":\"2018-11-13T12:00:55Z\"}";
 
-    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(DeletedMessagesVaultRestoreTaskAdditionalInformationDTO.MODULE);
+    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(DeletedMessagesVaultRestoreTaskAdditionalInformationDTO.MODULE);
 
     @BeforeEach
     void setUp() {
         exportService = mock(RestoreService.class);
         DeletedMessagesVaultRestoreTaskDTO.Factory factory = new DeletedMessagesVaultRestoreTaskDTO.Factory(exportService, queryTranslator);
-        taskSerializer = new JsonTaskSerializer(DeletedMessagesVaultRestoreTaskDTO.module(factory));
+        taskSerializer = JsonTaskSerializer.of(DeletedMessagesVaultRestoreTaskDTO.module(factory));
     }
 
     @Test
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/WebadminApiQuerySerializationContractTest.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/WebadminApiQuerySerializationContractTest.java
index 0dadb58..ef5b656 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/WebadminApiQuerySerializationContractTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/WebadminApiQuerySerializationContractTest.java
@@ -94,7 +94,7 @@ class WebadminApiQuerySerializationContractTest {
     private final static QueryTranslator queryTranslator = new QueryTranslator(mailboxIdFactory);
     private final static RestoreService restoreService = Mockito.mock(RestoreService.class);
     private final static DeletedMessagesVaultRestoreTaskDTO.Factory factory = new DeletedMessagesVaultRestoreTaskDTO.Factory(restoreService, queryTranslator);
-    private final static JsonTaskSerializer taskSerializer = new JsonTaskSerializer(DeletedMessagesVaultRestoreTaskDTO.module(factory));
+    private final static JsonTaskSerializer taskSerializer = JsonTaskSerializer.of(DeletedMessagesVaultRestoreTaskDTO.module(factory));
 
     /**
      * Enforce that the format of the query serialized in json in the body of the request to the webadmin is stable.
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/EventDeadLettersRedeliverTaskTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/EventDeadLettersRedeliverTaskTest.java
index 9764739..0c24d8a 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/EventDeadLettersRedeliverTaskTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/EventDeadLettersRedeliverTaskTest.java
@@ -58,12 +58,12 @@ class EventDeadLettersRedeliverTaskTest {
     private static final EventDeadLettersRedeliverAllTask TASK_ALL = new EventDeadLettersRedeliverAllTask(SERVICE);
     private static final EventDeadLettersRedeliverGroupTask TASK_GROUP = new EventDeadLettersRedeliverGroupTask(SERVICE, new GenericGroup("abc"));
     private static final EventDeadLettersRedeliverOneTask TASK_ONE = new EventDeadLettersRedeliverOneTask(SERVICE, new GenericGroup("abc"), EventDeadLetters.InsertionId.of("fcbc3c92-e9a0-4ece-94ed-6e6b45045258"));
-    private static final JsonTaskSerializer TESTEE = new JsonTaskSerializer(
+    private static final JsonTaskSerializer TESTEE = JsonTaskSerializer.of(
         EventDeadLettersRedeliverAllTaskDTO.module(SERVICE),
         EventDeadLettersRedeliverGroupTaskDTO.module(SERVICE),
         EventDeadLettersRedeliverOneTaskDTO.module(SERVICE));
 
-    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
         EventDeadLettersRedeliveryTaskAdditionalInformationForAll.MODULE,
         EventDeadLettersRedeliveryTaskAdditionalInformationForGroup.MODULE,
         EventDeadLettersRedeliveryTaskAdditionalInformationForOne.MODULE);
diff --git a/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/service/ClearMailQueueTaskTest.java b/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/service/ClearMailQueueTaskTest.java
index cdde343..54d2c95 100644
--- a/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/service/ClearMailQueueTaskTest.java
+++ b/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/service/ClearMailQueueTaskTest.java
@@ -44,7 +44,7 @@ class ClearMailQueueTaskTest {
     private static final String QUEUE_NAME = "anyQueue";
     private static final long INITIAL_COUNT = 0L;
     private static final long REMAINING_COUNT = 10L;
-    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
         ClearMailQueueTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
     private static final String SERIALIZED_TASK_ADDITIONAL_INFORMATION = "{\"type\": \"clear-mail-queue\", \"mailQueueName\":\"anyQueue\",\"initialCount\":0,\"remainingCount\":10, \"timestamp\":\"2018-11-13T12:00:55Z\"}";
 
@@ -54,7 +54,7 @@ class ClearMailQueueTaskTest {
         ManageableMailQueue mockedQueue = mock(ManageableMailQueue.class);
         when(mockedQueue.getName()).thenReturn(QUEUE_NAME);
         when(mailQueueFactory.getQueue(anyString())).thenAnswer(arg -> Optional.of(mockedQueue));
-        JsonTaskSerializer testee = new JsonTaskSerializer(ClearMailQueueTaskDTO.module(mailQueueFactory));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ClearMailQueueTaskDTO.module(mailQueueFactory));
 
         ManageableMailQueue queue = mailQueueFactory.getQueue(QUEUE_NAME).get();
         ClearMailQueueTask task = new ClearMailQueueTask(queue);
@@ -67,7 +67,7 @@ class ClearMailQueueTaskTest {
         ManageableMailQueue mockedQueue = mock(ManageableMailQueue.class);
         when(mockedQueue.getName()).thenReturn(QUEUE_NAME);
         when(mailQueueFactory.getQueue(anyString())).thenAnswer(arg -> Optional.of(mockedQueue));
-        JsonTaskSerializer testee = new JsonTaskSerializer(ClearMailQueueTaskDTO.module(mailQueueFactory));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ClearMailQueueTaskDTO.module(mailQueueFactory));
 
         ManageableMailQueue queue = mailQueueFactory.getQueue(QUEUE_NAME).get();
         ClearMailQueueTask task = new ClearMailQueueTask(queue);
@@ -78,7 +78,7 @@ class ClearMailQueueTaskTest {
     void taskShouldThrowWhenDeserializeAnUnknownQueue() throws Exception {
         MailQueueFactory<ManageableMailQueue> mailQueueFactory = mock(MailQueueFactory.class);
         when(mailQueueFactory.getQueue(anyString())).thenReturn(Optional.empty());
-        JsonTaskSerializer testee = new JsonTaskSerializer(ClearMailQueueTaskDTO.module(mailQueueFactory));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ClearMailQueueTaskDTO.module(mailQueueFactory));
 
         String serializedJson = "{\"type\": \"clear-mail-queue\", \"queue\": \"anyQueue\"}";
         assertThatThrownBy(() -> testee.deserialize(serializedJson))
diff --git a/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/service/DeleteMailsFromMailQueueTaskTest.java b/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/service/DeleteMailsFromMailQueueTaskTest.java
index 098a1f6..edd4c54 100644
--- a/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/service/DeleteMailsFromMailQueueTaskTest.java
+++ b/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/service/DeleteMailsFromMailQueueTaskTest.java
@@ -50,7 +50,7 @@ class DeleteMailsFromMailQueueTaskTest {
     private MailQueueFactory<ManageableMailQueue> mailQueueFactory;
     private ManageableMailQueue mockedQueue;
     private final static String queueName = "anyQueue";
-    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(DeleteMailsFromMailQueueTaskAdditionalInformationDTO.MODULE);
+    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(DeleteMailsFromMailQueueTaskAdditionalInformationDTO.MODULE);
 
     @BeforeEach
     private void setUp() {
@@ -64,7 +64,7 @@ class DeleteMailsFromMailQueueTaskTest {
     @MethodSource
     void taskShouldBeSerializable(Optional<MailAddress> sender, Optional<String> name, Optional<MailAddress> recipient, String serializedJson) throws Exception {
 
-        JsonTaskSerializer testee = new JsonTaskSerializer(DeleteMailsFromMailQueueTaskDTO.module(mailQueueFactory));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(DeleteMailsFromMailQueueTaskDTO.module(mailQueueFactory));
 
         ManageableMailQueue queue = mailQueueFactory.getQueue(queueName).get();
         DeleteMailsFromMailQueueTask task = new DeleteMailsFromMailQueueTask(queue, sender, name, recipient);
@@ -78,7 +78,7 @@ class DeleteMailsFromMailQueueTaskTest {
     @ParameterizedTest
     @MethodSource
     void taskShouldBeDeserializable(Optional<MailAddress> sender, Optional<String> name, Optional<MailAddress> recipient, String serializedJson) throws Exception {
-        JsonTaskSerializer testee = new JsonTaskSerializer(DeleteMailsFromMailQueueTaskDTO.module(mailQueueFactory));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(DeleteMailsFromMailQueueTaskDTO.module(mailQueueFactory));
 
         ManageableMailQueue queue = mailQueueFactory.getQueue(queueName).get();
         DeleteMailsFromMailQueueTask task = new DeleteMailsFromMailQueueTask(queue, sender, name, recipient);
@@ -101,7 +101,7 @@ class DeleteMailsFromMailQueueTaskTest {
     void taskShouldThrowWhenDeserializeAnUnknownQueue() throws Exception {
         MailQueueFactory<ManageableMailQueue> mailQueueFactory = mock(MailQueueFactory.class);
         when(mailQueueFactory.getQueue(anyString())).thenReturn(Optional.empty());
-        JsonTaskSerializer testee = new JsonTaskSerializer(DeleteMailsFromMailQueueTaskDTO.module(mailQueueFactory));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(DeleteMailsFromMailQueueTaskDTO.module(mailQueueFactory));
 
         String serializedJson = "{\"type\": \"delete-mails-from-mail-queue\", \"queue\": \"anyQueue\", \"sender\": \"a@b.c\"}";
         assertThatThrownBy(() -> testee.deserialize(serializedJson))
@@ -110,7 +110,7 @@ class DeleteMailsFromMailQueueTaskTest {
 
     @Test
     void taskShouldThrowWhenDeserializeAMalformedMailAddress() throws Exception {
-        JsonTaskSerializer testee = new JsonTaskSerializer(DeleteMailsFromMailQueueTaskDTO.module(mailQueueFactory));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(DeleteMailsFromMailQueueTaskDTO.module(mailQueueFactory));
 
         String serializedJson = "{\"type\": \"delete-mails-from-mail-queue\", \"queue\": \"" + queueName + "\", \"sender\": \"a.b.c\"}";
         assertThatThrownBy(() -> testee.deserialize(serializedJson))
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ClearMailRepositoryTaskTest.java b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ClearMailRepositoryTaskTest.java
index 33b47f4..fdaf67f 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ClearMailRepositoryTaskTest.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ClearMailRepositoryTaskTest.java
@@ -50,19 +50,19 @@ class ClearMailRepositoryTaskTest {
     private static final ClearMailRepositoryTask TASK = new ClearMailRepositoryTask(MAIL_REPOSITORIES, MAIL_REPOSITORY_PATH);
     private static final long INITIAL_COUNT = 0L;
     private static final long REMAINING_COUNT = 10L;
-    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(
+    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(
         ClearMailRepositoryTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
 
     @Test
     void taskShouldBeSerializable() throws JsonProcessingException {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ClearMailRepositoryTaskDTO.module(FACTORY));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ClearMailRepositoryTaskDTO.module(FACTORY));
         JsonAssertions.assertThatJson(testee.serialize(TASK))
             .isEqualTo(SERIALIZED);
     }
 
     @Test
     void taskShouldBeDeserializable() throws IOException {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ClearMailRepositoryTaskDTO.module(FACTORY));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ClearMailRepositoryTaskDTO.module(FACTORY));
 
         assertThat(testee.deserialize(SERIALIZED))
             .isEqualToComparingFieldByFieldRecursively(TASK);
@@ -70,7 +70,7 @@ class ClearMailRepositoryTaskTest {
 
     @Test
     void taskShouldThrowOnDeserializationUrlDecodingError() {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ClearMailRepositoryTaskDTO.module(FACTORY));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ClearMailRepositoryTaskDTO.module(FACTORY));
 
         assertThatThrownBy(() -> testee.deserialize("{\"type\":\"clear-mail-repository\",\"mailRepositoryPath\":\"%\"}"))
             .isInstanceOf(ClearMailRepositoryTask.InvalidMailRepositoryPathDeserializationException.class);
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingAllMailsTaskTest.java b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingAllMailsTaskTest.java
index f05c984..c419a1c 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingAllMailsTaskTest.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingAllMailsTaskTest.java
@@ -44,7 +44,7 @@ class ReprocessingAllMailsTaskTest {
 
     private static final Instant TIMESTAMP = Instant.parse("2018-11-13T12:00:55Z");
     private static final ReprocessingService REPROCESSING_SERVICE = mock(ReprocessingService.class);
-    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(ReprocessingAllMailsTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
+    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(ReprocessingAllMailsTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
     private static final long REPOSITORY_SIZE = 5L;
     private static final MailRepositoryPath REPOSITORY_PATH = MailRepositoryPath.from("a");
     private static final String TARGET_QUEUE = "queue";
@@ -63,7 +63,7 @@ class ReprocessingAllMailsTaskTest {
                                   String targetQueue,
                                   Optional<String> targetProcessor,
                                   String serialized) throws JsonProcessingException {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ReprocessingAllMailsTaskDTO.module(REPROCESSING_SERVICE));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ReprocessingAllMailsTaskDTO.module(REPROCESSING_SERVICE));
         ReprocessingAllMailsTask task = new ReprocessingAllMailsTask(REPROCESSING_SERVICE, repositorySize, repositoryPath, targetQueue, targetProcessor);
         assertThatJson(testee.serialize(task))
             .isEqualTo(serialized);
@@ -80,7 +80,7 @@ class ReprocessingAllMailsTaskTest {
                                     String targetQueue,
                                     Optional<String> targetProcessor,
                                     String serialized) throws IOException {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ReprocessingAllMailsTaskDTO.module(REPROCESSING_SERVICE));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ReprocessingAllMailsTaskDTO.module(REPROCESSING_SERVICE));
         ReprocessingAllMailsTask task = new ReprocessingAllMailsTask(REPROCESSING_SERVICE, repositorySize, repositoryPath, targetQueue, targetProcessor);
 
         assertThat(testee.deserialize(serialized))
@@ -101,7 +101,7 @@ class ReprocessingAllMailsTaskTest {
     @ParameterizedTest
     @ValueSource(strings = {"{\"type\":\"reprocessing-all\",\"repositorySize\":5,\"repositoryPath\":\"%\",\"targetQueue\":\"queue\",\"targetProcessor\":\"targetProcessor\"}", "{\"type\":\"reprocessing-all\",\"repositorySize\":5,\"repositoryPath\":\"%\",\"targetQueue\":\"queue\"}"})
     void taskShouldThrowOnDeserializationUrlDecodingError(String serialized) {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ReprocessingAllMailsTaskDTO.module(REPROCESSING_SERVICE));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ReprocessingAllMailsTaskDTO.module(REPROCESSING_SERVICE));
 
         assertThatThrownBy(() -> testee.deserialize(serialized))
             .isInstanceOf(ReprocessingAllMailsTask.InvalidMailRepositoryPathDeserializationException.class);
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingOneMailTaskTest.java b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingOneMailTaskTest.java
index b23c4cf..434a16b 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingOneMailTaskTest.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingOneMailTaskTest.java
@@ -55,7 +55,7 @@ class ReprocessingOneMailTaskTest {
     private static final String TARGET_QUEUE = "queue";
     private static final MailKey MAIL_KEY = new MailKey("myMail");
     private static final Optional<String> TARGET_PROCESSOR = Optional.of("targetProcessor");
-    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = new JsonTaskAdditionalInformationSerializer(ReprocessingOneMailTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
+    private JsonTaskAdditionalInformationSerializer jsonAdditionalInformationSerializer = JsonTaskAdditionalInformationSerializer.of(ReprocessingOneMailTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
 
     @ParameterizedTest
     @MethodSource
@@ -64,7 +64,7 @@ class ReprocessingOneMailTaskTest {
                                   MailKey mailKey,
                                   Optional<String> targetProcessor,
                                   String serialized) throws JsonProcessingException {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ReprocessingOneMailTaskDTO.module(CLOCK, REPROCESSING_SERVICE));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ReprocessingOneMailTaskDTO.module(CLOCK, REPROCESSING_SERVICE));
         ReprocessingOneMailTask task = new ReprocessingOneMailTask(REPROCESSING_SERVICE, repositoryPath, targetQueue, mailKey, targetProcessor, CLOCK);
         JsonAssertions.assertThatJson(testee.serialize(task))
             .isEqualTo(serialized);
@@ -81,7 +81,7 @@ class ReprocessingOneMailTaskTest {
                                     MailKey mailKey,
                                     Optional<String> targetProcessor,
                                     String serialized) throws IOException {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ReprocessingOneMailTaskDTO.module(CLOCK, REPROCESSING_SERVICE));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ReprocessingOneMailTaskDTO.module(CLOCK, REPROCESSING_SERVICE));
         ReprocessingOneMailTask task = new ReprocessingOneMailTask(REPROCESSING_SERVICE, repositoryPath, targetQueue, mailKey, targetProcessor, CLOCK);
 
         assertThat(testee.deserialize(serialized))
@@ -102,7 +102,7 @@ class ReprocessingOneMailTaskTest {
     @ParameterizedTest
     @ValueSource(strings = {"{\"type\":\"reprocessing-one\",\"repositoryPath\":\"%\",\"targetQueue\":\"queue\",\"mailKey\": \"myMail\",\"targetProcessor\":\"targetProcessor\"}", "{\"type\":\"reprocessing-one\",\"repositoryPath\":\"%\",\"targetQueue\":\"queue\",\"mailKey\": \"myMail\"}"})
     void taskShouldThrowOnDeserializationUrlDecodingError(String serialized) {
-        JsonTaskSerializer testee = new JsonTaskSerializer(ReprocessingOneMailTaskDTO.module(CLOCK, REPROCESSING_SERVICE));
+        JsonTaskSerializer testee = JsonTaskSerializer.of(ReprocessingOneMailTaskDTO.module(CLOCK, REPROCESSING_SERVICE));
 
         assertThatThrownBy(() -> testee.deserialize(serialized))
             .isInstanceOf(ReprocessingOneMailTask.InvalidMailRepositoryPathDeserializationException.class);
diff --git a/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueViewTestFactory.java b/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueViewTestFactory.java
index 5ce44f7..a43c6c6 100644
--- a/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueViewTestFactory.java
+++ b/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueViewTestFactory.java
@@ -33,8 +33,6 @@ import org.apache.james.queue.rabbitmq.view.cassandra.configuration.CassandraMai
 import org.apache.james.queue.rabbitmq.view.cassandra.configuration.EventsourcingConfigurationManagement;
 
 import com.datastax.driver.core.Session;
-import com.google.common.collect.ImmutableSet;
-
 import reactor.core.publisher.Mono;
 
 public class CassandraMailQueueViewTestFactory {
@@ -54,7 +52,7 @@ public class CassandraMailQueueViewTestFactory {
 
 
         EventsourcingConfigurationManagement eventsourcingConfigurationManagement = new EventsourcingConfigurationManagement(new CassandraEventStore(new EventStoreDao(session,
-            new JsonEventSerializer(CassandraMailQueueViewConfigurationModule.MAIL_QUEUE_VIEW_CONFIGURATION))));
+            JsonEventSerializer.forModules(CassandraMailQueueViewConfigurationModule.MAIL_QUEUE_VIEW_CONFIGURATION).withoutNestedType())));
 
         return new CassandraMailQueueView.Factory(
             cassandraMailQueueMailStore,
diff --git a/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/view/cassandra/configuration/EventsourcingConfigurationManagementTest.java b/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/view/cassandra/configuration/EventsourcingConfigurationManagementTest.java
index 5f96ef3..960c421 100644
--- a/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/view/cassandra/configuration/EventsourcingConfigurationManagementTest.java
+++ b/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/view/cassandra/configuration/EventsourcingConfigurationManagementTest.java
@@ -29,14 +29,16 @@ import java.util.List;
 import org.apache.james.eventsourcing.Event;
 import org.apache.james.eventsourcing.eventstore.EventStore;
 import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreExtension;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 class EventsourcingConfigurationManagementTest {
 
     @RegisterExtension
-    static CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(
-        CassandraMailQueueViewConfigurationModule.MAIL_QUEUE_VIEW_CONFIGURATION);
+    static CassandraEventStoreExtension eventStoreExtension =
+        new CassandraEventStoreExtension(
+            JsonEventSerializer.forModules(CassandraMailQueueViewConfigurationModule.MAIL_QUEUE_VIEW_CONFIGURATION).withoutNestedType());
 
     private static final int DEFAULT_BUCKET_COUNT = 10;
     private static final int DEFAULT_UPDATE_PACE = 100;
diff --git a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/cassandra/CassandraTaskExecutionDetailsProjectionDAOTest.java b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/cassandra/CassandraTaskExecutionDetailsProjectionDAOTest.java
index 2247d4c..991c2d0 100644
--- a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/cassandra/CassandraTaskExecutionDetailsProjectionDAOTest.java
+++ b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/cassandra/CassandraTaskExecutionDetailsProjectionDAOTest.java
@@ -47,7 +47,7 @@ class CassandraTaskExecutionDetailsProjectionDAOTest {
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
         CassandraModule.aggregateModules(CassandraSchemaVersionModule.MODULE, CassandraZonedDateTimeModule.MODULE, CassandraTaskExecutionDetailsProjectionModule.MODULE()));
-    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
+    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
 
     private CassandraTaskExecutionDetailsProjectionDAO testee;
 
diff --git a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/cassandra/CassandraTaskExecutionDetailsProjectionTest.java b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/cassandra/CassandraTaskExecutionDetailsProjectionTest.java
index a2dcf15..0492207 100644
--- a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/cassandra/CassandraTaskExecutionDetailsProjectionTest.java
+++ b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/cassandra/CassandraTaskExecutionDetailsProjectionTest.java
@@ -30,9 +30,6 @@ import org.apache.james.server.task.json.JsonTaskAdditionalInformationSerializer
 import org.apache.james.server.task.json.dto.MemoryReferenceWithCounterTaskAdditionalInformationDTO;
 import org.apache.james.task.eventsourcing.TaskExecutionDetailsProjection;
 import org.apache.james.task.eventsourcing.TaskExecutionDetailsProjectionContract;
-
-import org.apache.james.task.eventsourcing.cassandra.CassandraTaskExecutionDetailsProjection;
-import org.apache.james.task.eventsourcing.cassandra.CassandraTaskExecutionDetailsProjectionDAO;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
@@ -41,7 +38,7 @@ class CassandraTaskExecutionDetailsProjectionTest implements TaskExecutionDetail
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
             CassandraModule.aggregateModules(CassandraSchemaVersionModule.MODULE, CassandraZonedDateTimeModule.MODULE, CassandraTaskExecutionDetailsProjectionModule.MODULE()));
-    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
+    private static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
 
     private Supplier<CassandraTaskExecutionDetailsProjection> testeeSupplier;
 
diff --git a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/DistributedTaskManagerTest.java b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/DistributedTaskManagerTest.java
index ff98f90..02c6024 100644
--- a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/DistributedTaskManagerTest.java
+++ b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/DistributedTaskManagerTest.java
@@ -45,6 +45,7 @@ import org.apache.james.json.DTOConverter;
 import org.apache.james.server.task.json.JsonTaskAdditionalInformationSerializer;
 import org.apache.james.server.task.json.JsonTaskSerializer;
 import org.apache.james.server.task.json.dto.AdditionalInformationDTO;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule;
 import org.apache.james.server.task.json.dto.MemoryReferenceTaskStore;
 import org.apache.james.server.task.json.dto.MemoryReferenceWithCounterTaskAdditionalInformationDTO;
 import org.apache.james.server.task.json.dto.MemoryReferenceWithCounterTaskStore;
@@ -72,8 +73,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.google.common.collect.ImmutableSet;
-
 class DistributedTaskManagerTest implements TaskManagerContract {
 
     static class TrackedRabbitMQWorkQueueSupplier implements WorkQueueSupplier {
@@ -99,8 +98,9 @@ class DistributedTaskManagerTest implements TaskManagerContract {
         }
     }
 
-    static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
-    static final DTOConverter<TaskExecutionDetails.AdditionalInformation, AdditionalInformationDTO> DTO_CONVERTER = DTOConverter.of(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
+    public static final AdditionalInformationDTOModule<?, ?> ADDITIONAL_INFORMATION_MODULE = MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE;
+    static final JsonTaskAdditionalInformationSerializer JSON_TASK_ADDITIONAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(ADDITIONAL_INFORMATION_MODULE);
+    static final DTOConverter<TaskExecutionDetails.AdditionalInformation, AdditionalInformationDTO> DTO_CONVERTER = DTOConverter.of(ADDITIONAL_INFORMATION_MODULE);
     static final Hostname HOSTNAME = new Hostname("foo");
     static final Hostname HOSTNAME_2 = new Hostname("bar");
 
@@ -116,7 +116,7 @@ class DistributedTaskManagerTest implements TaskManagerContract {
             CassandraZonedDateTimeModule.MODULE,
             CassandraTaskExecutionDetailsProjectionModule.MODULE()));
 
-    JsonTaskSerializer taskSerializer = new JsonTaskSerializer(
+    JsonTaskSerializer taskSerializer = JsonTaskSerializer.of(
         TestTaskDTOModules.COMPLETED_TASK_MODULE,
         TestTaskDTOModules.FAILED_TASK_MODULE,
         TestTaskDTOModules.THROWING_TASK_MODULE,
@@ -126,7 +126,8 @@ class DistributedTaskManagerTest implements TaskManagerContract {
     Set<EventDTOModule<?, ?>> eventDtoModule = TasksSerializationModule.list(taskSerializer, DTO_CONVERTER);
 
     @RegisterExtension
-    CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(CASSANDRA_CLUSTER, eventDtoModule);
+    CassandraEventStoreExtension eventStoreExtension = new CassandraEventStoreExtension(CASSANDRA_CLUSTER,
+        JsonEventSerializer.forModules(eventDtoModule).withNestedTypeModules(ADDITIONAL_INFORMATION_MODULE));
 
     @RegisterExtension
     CountDownLatchExtension countDownLatchExtension = new CountDownLatchExtension();
@@ -145,7 +146,7 @@ class DistributedTaskManagerTest implements TaskManagerContract {
         this.workQueueSupplier = new TrackedRabbitMQWorkQueueSupplier(RABBIT_MQ_EXTENSION.getRabbitChannelPool(), taskSerializer);
         this.eventStore = eventStore;
         this.terminationSubscribers = new ArrayList<>();
-        this.eventSerializer = new JsonEventSerializer(new DTOConverter<>(eventDtoModule), eventDtoModule, ImmutableSet.of());
+        this.eventSerializer = JsonEventSerializer.forModules(eventDtoModule).withoutNestedType();
     }
 
     @AfterEach
diff --git a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/RabbitMQTerminationSubscriberTest.java b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/RabbitMQTerminationSubscriberTest.java
index db2c02b..7e358cd 100644
--- a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/RabbitMQTerminationSubscriberTest.java
+++ b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/RabbitMQTerminationSubscriberTest.java
@@ -39,13 +39,12 @@ import org.awaitility.Awaitility;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.google.common.collect.ImmutableSet;
 import reactor.core.publisher.Flux;
 
 class RabbitMQTerminationSubscriberTest implements TerminationSubscriberContract {
-    private static final JsonTaskSerializer TASK_SERIALIZER = new JsonTaskSerializer();
+    private static final JsonTaskSerializer TASK_SERIALIZER = JsonTaskSerializer.of();
     private static final Set<EventDTOModule<?, ?>> MODULES = TasksSerializationModule.list(TASK_SERIALIZER, DTOConverter.of());
-    private static final JsonEventSerializer SERIALIZER = new JsonEventSerializer(new DTOConverter<>(MODULES), MODULES, ImmutableSet.of());
+    private static final JsonEventSerializer SERIALIZER = JsonEventSerializer.forModules(MODULES).withoutNestedType();
 
     @RegisterExtension
     static RabbitMQExtension rabbitMQExtension = RabbitMQExtension.singletonRabbitMQ();
diff --git a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/RabbitMQWorkQueueTest.java b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/RabbitMQWorkQueueTest.java
index fefb6f1..3d8b17e 100644
--- a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/RabbitMQWorkQueueTest.java
+++ b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/RabbitMQWorkQueueTest.java
@@ -100,7 +100,7 @@ class RabbitMQWorkQueueTest {
     @BeforeEach
     void setUp() {
         worker = spy(new ImmediateWorker());
-        serializer = new JsonTaskSerializer(TestTaskDTOModules.COMPLETED_TASK_MODULE);
+        serializer = JsonTaskSerializer.of(TestTaskDTOModules.COMPLETED_TASK_MODULE);
         testee = new RabbitMQWorkQueue(worker, rabbitMQExtension.getRabbitChannelPool(), serializer);
         testee.start();
     }
@@ -150,7 +150,7 @@ class RabbitMQWorkQueueTest {
         TaskWithId taskWithId = new TaskWithId(taskId, task);
 
         ImmediateWorker otherTaskManagerWorker = new ImmediateWorker();
-        JsonTaskSerializer otherTaskSerializer = new JsonTaskSerializer(TestTaskDTOModules.TEST_TYPE);
+        JsonTaskSerializer otherTaskSerializer = JsonTaskSerializer.of(TestTaskDTOModules.TEST_TYPE);
         try (RabbitMQWorkQueue otherWorkQueue = new RabbitMQWorkQueue(otherTaskManagerWorker, rabbitMQExtension.getRabbitChannelPool(), otherTaskSerializer)) {
             //wait to be sur that the first workqueue has subscribed as an exclusive consumer of the RabbitMQ queue.
             Thread.sleep(200);
diff --git a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/TaskEventsSerializationTest.java b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/TaskEventsSerializationTest.java
index 4edfa51..0b5d1e0 100644
--- a/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/TaskEventsSerializationTest.java
+++ b/server/task/task-distributed/src/test/java/org/apache/james/task/eventsourcing/distributed/TaskEventsSerializationTest.java
@@ -53,14 +53,13 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
-import com.google.common.collect.ImmutableSet;
 import net.javacrumbs.jsonunit.assertj.JsonAssertions;
 import scala.Option;
 
 class TaskEventsSerializationTest {
     static final Instant TIMESTAMP = Instant.parse("2018-11-13T12:00:55Z");
     static final DTOConverter<TaskExecutionDetails.AdditionalInformation, AdditionalInformationDTO> ADDITIONAL_INFORMATION_CONVERTER = DTOConverter.of(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
-    static final JsonTaskAdditionalInformationSerializer TASK_ADDITIONNAL_INFORMATION_SERIALIZER = new JsonTaskAdditionalInformationSerializer(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
+    static final JsonTaskAdditionalInformationSerializer TASK_ADDITIONNAL_INFORMATION_SERIALIZER = JsonTaskAdditionalInformationSerializer.of(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
     static final TaskAggregateId AGGREGATE_ID = new TaskAggregateId(TaskId.fromString("2c7f4081-aa30-11e9-bf6c-2d3b9e84aafd"));
     static final EventId EVENT_ID = EventId.fromSerialized(42);
     static final Task TASK = new CompletedTask();
@@ -68,12 +67,14 @@ class TaskEventsSerializationTest {
     static final MemoryReferenceWithCounterTask.AdditionalInformation COUNTER_ADDITIONAL_INFORMATION = new MemoryReferenceWithCounterTask.AdditionalInformation(3, TIMESTAMP);
 
     private final Set<EventDTOModule<?, ?>> list = TasksSerializationModule.list(
-        new JsonTaskSerializer(
+        JsonTaskSerializer.of(
             TestTaskDTOModules.COMPLETED_TASK_MODULE,
             TestTaskDTOModules.MEMORY_REFERENCE_WITH_COUNTER_TASK_MODULE.apply(new MemoryReferenceWithCounterTaskStore())),
         ADDITIONAL_INFORMATION_CONVERTER);
 
-    JsonEventSerializer serializer = new JsonEventSerializer(new DTOConverter<>(list), list, ImmutableSet.of(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE));
+    JsonEventSerializer serializer = JsonEventSerializer
+        .forModules(list)
+        .withNestedTypeModules(MemoryReferenceWithCounterTaskAdditionalInformationDTO.SERIALIZATION_MODULE);
 
     @ParameterizedTest
     @MethodSource
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 eb68ef9..52c0608 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
@@ -23,7 +23,6 @@ import java.util.Set;
 
 import javax.inject.Inject;
 
-import org.apache.james.json.DTOConverter;
 import org.apache.james.json.JsonGenericSerializer;
 import org.apache.james.server.task.json.dto.AdditionalInformationDTO;
 import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule;
@@ -34,6 +33,10 @@ import com.google.common.collect.ImmutableSet;
 
 public class JsonTaskAdditionalInformationSerializer {
 
+    public static JsonTaskAdditionalInformationSerializer of(AdditionalInformationDTOModule<?, ?>... modules) {
+        return new JsonTaskAdditionalInformationSerializer(ImmutableSet.copyOf(modules));
+    }
+
     public static class InvalidAdditionalInformationException extends RuntimeException {
         public InvalidAdditionalInformationException(JsonGenericSerializer.InvalidTypeException original) {
             super(original);
@@ -49,12 +52,8 @@ public class JsonTaskAdditionalInformationSerializer {
     private JsonGenericSerializer<TaskExecutionDetails.AdditionalInformation, AdditionalInformationDTO> jsonGenericSerializer;
 
     @Inject
-    public JsonTaskAdditionalInformationSerializer(Set<AdditionalInformationDTOModule<?, ?>> modules) {
-        jsonGenericSerializer = new JsonGenericSerializer(modules, ImmutableSet.of(), new DTOConverter<>(modules));
-    }
-
-    public JsonTaskAdditionalInformationSerializer(@SuppressWarnings("rawtypes") AdditionalInformationDTOModule... modules) {
-        this(ImmutableSet.copyOf(modules));
+    private JsonTaskAdditionalInformationSerializer(Set<AdditionalInformationDTOModule<?, ?>> modules) {
+        jsonGenericSerializer = JsonGenericSerializer.forModules(modules).withoutNestedType();
     }
 
     public String serialize(TaskExecutionDetails.AdditionalInformation additionalInformation) throws JsonProcessingException {
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 313aa50..31f4a77 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
@@ -24,7 +24,6 @@ import java.util.Set;
 
 import javax.inject.Inject;
 
-import org.apache.james.json.DTOConverter;
 import org.apache.james.json.JsonGenericSerializer;
 import org.apache.james.server.task.json.dto.TaskDTO;
 import org.apache.james.server.task.json.dto.TaskDTOModule;
@@ -35,6 +34,10 @@ import com.google.common.collect.ImmutableSet;
 
 public class JsonTaskSerializer {
 
+    public static JsonTaskSerializer of(TaskDTOModule<?, ?>... modules) {
+        return new JsonTaskSerializer(ImmutableSet.copyOf(modules));
+    }
+
     public static class InvalidTaskException  extends RuntimeException {
         public InvalidTaskException(JsonGenericSerializer.InvalidTypeException original) {
             super(original);
@@ -50,12 +53,8 @@ public class JsonTaskSerializer {
     private JsonGenericSerializer<Task, TaskDTO> jsonGenericSerializer;
 
     @Inject
-    public JsonTaskSerializer(DTOConverter<Task, TaskDTO> converter, Set<TaskDTOModule<?, ?>> modules) {
-        jsonGenericSerializer = new JsonGenericSerializer(modules, ImmutableSet.of(), converter);
-    }
-
-    public JsonTaskSerializer(@SuppressWarnings("rawtypes") TaskDTOModule... modules) {
-        this(DTOConverter.of(modules), ImmutableSet.copyOf(modules));
+    private JsonTaskSerializer(Set<TaskDTOModule<?, ?>> modules) {
+        jsonGenericSerializer = JsonGenericSerializer.forModules(modules).withoutNestedType();
     }
 
     public String serialize(Task task) throws JsonProcessingException {
diff --git a/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskDeserializerTest.java b/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskDeserializerTest.java
index 4d2a947..305593f 100644
--- a/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskDeserializerTest.java
+++ b/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskDeserializerTest.java
@@ -52,7 +52,7 @@ class TaskDeserializerTest {
 
     @BeforeEach
     void setUp() {
-        testee = new JsonTaskSerializer(TestTaskDTOModules.TEST_TYPE);
+        testee = JsonTaskSerializer.of(TestTaskDTOModules.TEST_TYPE);
     }
 
     @Test
diff --git a/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskSerializationTest.java b/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskSerializationTest.java
index 85205ad..09e11ce 100644
--- a/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskSerializationTest.java
+++ b/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskSerializationTest.java
@@ -51,7 +51,7 @@ class TaskSerializationTest {
     @ParameterizedTest
     @MethodSource
     void taskShouldBeSerializable(Task task, TaskDTOModule<?, ?> module, String expectedJson) throws Exception {
-        String actual = new JsonTaskSerializer(module).serialize(task);
+        String actual = JsonTaskSerializer.of(module).serialize(task);
         assertThatJson(actual).isEqualTo(expectedJson);
     }
 
@@ -62,7 +62,7 @@ class TaskSerializationTest {
     @ParameterizedTest
     @MethodSource
     void taskShouldBeDeserializable(Task task, TaskDTOModule<?, ?> module, String serializedJson) throws Exception {
-        assertThat(new JsonTaskSerializer(module).deserialize(serializedJson))
+        assertThat(JsonTaskSerializer.of(module).deserialize(serializedJson))
             .isInstanceOf(task.getClass());
     }
 
@@ -82,7 +82,7 @@ class TaskSerializationTest {
     void memoryReferenceTaskShouldSerialize() throws JsonProcessingException {
         MemoryReferenceTask memoryReferenceTask = new MemoryReferenceTask(() -> Task.Result.COMPLETED);
 
-        String actual = new JsonTaskSerializer(MEMORY_REFERENCE_TASK_MODULE.apply(new MemoryReferenceTaskStore())).serialize(memoryReferenceTask);
+        String actual = JsonTaskSerializer.of(MEMORY_REFERENCE_TASK_MODULE.apply(new MemoryReferenceTaskStore())).serialize(memoryReferenceTask);
         assertThatJson(actual).isEqualTo(SERIALIZED_MEMORY_REFERENCE_TASK);
     }
 
@@ -92,7 +92,7 @@ class TaskSerializationTest {
         MemoryReferenceTask memoryReferenceTask = new MemoryReferenceTask(() -> Task.Result.COMPLETED);
         memoryReferenceTaskStore.add(memoryReferenceTask);
 
-        Task task = new JsonTaskSerializer(MEMORY_REFERENCE_TASK_MODULE.apply(memoryReferenceTaskStore)).deserialize(SERIALIZED_MEMORY_REFERENCE_TASK);
+        Task task = JsonTaskSerializer.of(MEMORY_REFERENCE_TASK_MODULE.apply(memoryReferenceTaskStore)).deserialize(SERIALIZED_MEMORY_REFERENCE_TASK);
         assertThat(task).isInstanceOf(MemoryReferenceTask.class);
     }
 }
diff --git a/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskSerializerTest.java b/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskSerializerTest.java
index 38983bc..d018068 100644
--- a/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskSerializerTest.java
+++ b/server/task/task-json/src/test/java/org/apache/james/server/task/json/TaskSerializerTest.java
@@ -30,7 +30,7 @@ class TaskSerializerTest {
 
     @Test
     void shouldSerializeTaskWithItsType() throws Exception {
-        JsonTaskSerializer testee = new JsonTaskSerializer(TestTaskDTOModules.TEST_TYPE);
+        JsonTaskSerializer testee = JsonTaskSerializer.of(TestTaskDTOModules.TEST_TYPE);
         long parameter = 1L;
         TestTask task = new TestTask(parameter);
         JsonAssertions.assertThatJson(testee.serialize(task)).isEqualTo(TASK_AS_STRING);


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