You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2023/05/03 03:21:44 UTC

[james-project] branch master updated: JAMES-3829 Drop FST (#1545)

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


The following commit(s) were added to refs/heads/master by this push:
     new bd32e30640 JAMES-3829 Drop FST (#1545)
bd32e30640 is described below

commit bd32e30640c3db4ba74e39ba46145f95f18aa46b
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Wed May 3 10:21:38 2023 +0700

    JAMES-3829 Drop FST (#1545)
---
 mailet/api/pom.xml                                 |  16 ---
 .../java/org/apache/mailet/AttributeValue.java     |  25 ++---
 .../main/java/org/apache/mailet/Serializer.java    | 123 ++++++++++-----------
 .../java/org/apache/mailet/AttributeValueTest.java |  68 ++++--------
 .../transport/mailets/SMIMECheckSignature.java     |  95 ++++++++--------
 .../james/transport/mailets/SMIMEDecrypt.java      |   6 +-
 .../james/transport/mailets/ICalendarParser.java   |   2 +-
 .../james/transport/mailets/ICALToHeadersTest.java |   8 +-
 .../transport/mailets/ICALToJsonAttributeTest.java |  32 +++---
 .../transport/mailets/ICalendarParserTest.java     |  16 ++-
 .../james/transport/matchers/HasExceptionTest.java |  33 +++---
 .../org/apache/james/server/core/MailImpl.java     |   6 +-
 .../mailrepository/jpa/JPAMailRepository.java      |   8 +-
 .../james/mailetcontainer/impl/ProcessorUtil.java  |   2 +-
 .../transport/mailets/jsieve/ActionUtils.java      |  16 +--
 .../james/mailrepository/blob/MailMetadata.scala   |   2 +-
 .../CassandraMailRepositoryMailDaoV2.java          |   7 +-
 .../apache/james/queue/api/MailQueueContract.java  |  18 ---
 .../james/queue/jms/JMSCacheableMailQueue.java     |   6 +-
 .../apache/james/queue/pulsar/MailMetadata.scala   |   2 +-
 .../james/queue/rabbitmq/MailReferenceDTO.java     |  10 +-
 .../view/cassandra/EnqueuedMailsDaoUtil.java       |  10 +-
 22 files changed, 224 insertions(+), 287 deletions(-)

diff --git a/mailet/api/pom.xml b/mailet/api/pom.xml
index 72b41ca35b..b50b0c0919 100644
--- a/mailet/api/pom.xml
+++ b/mailet/api/pom.xml
@@ -71,22 +71,6 @@
             <groupId>com.sun.mail</groupId>
             <artifactId>javax.mail</artifactId>
         </dependency>
-        <dependency>
-            <groupId>de.ruedigermoeller</groupId>
-            <artifactId>fst</artifactId>
-            <version>2.57</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.objenesis</groupId>
-                    <artifactId>objenesis</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.objenesis</groupId>
-            <artifactId>objenesis</artifactId>
-            <version>3.2</version>
-        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
diff --git a/mailet/api/src/main/java/org/apache/mailet/AttributeValue.java b/mailet/api/src/main/java/org/apache/mailet/AttributeValue.java
index 5df7218497..b0290e68f4 100644
--- a/mailet/api/src/main/java/org/apache/mailet/AttributeValue.java
+++ b/mailet/api/src/main/java/org/apache/mailet/AttributeValue.java
@@ -20,7 +20,6 @@
 package org.apache.mailet;
 
 import java.io.IOException;
-import java.io.Serializable;
 import java.net.URL;
 import java.time.ZonedDateTime;
 import java.util.Collection;
@@ -128,9 +127,9 @@ public class AttributeValue<T> {
         return new AttributeValue<>(value, new Serializer.MapSerializer());
     }
 
-    public static AttributeValue<Serializable> ofSerializable(Serializable value) {
-        Preconditions.checkNotNull(value, "value should not be null");
-        return new AttributeValue<>(value, new Serializer.FSTSerializer());
+    public static AttributeValue<Object> ofUnserializable(Object any) {
+        Preconditions.checkNotNull(any, "value should not be null");
+        return new AttributeValue<>(any, new Serializer.NoSerializer());
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -178,10 +177,7 @@ public class AttributeValue<T> {
         if (value instanceof Optional) {
             return of((Optional) value);
         }
-        if (value instanceof Serializable) {
-            return ofSerializable((Serializable) value);
-        }
-        throw new IllegalArgumentException(value.getClass().toString() + " should at least be Serializable");
+        throw new IllegalArgumentException(value.getClass().toString() + " is not a managed attibute");
     }
 
     public static AttributeValue<?> fromJsonString(String json) throws IOException {
@@ -253,11 +249,14 @@ public class AttributeValue<T> {
         return new AttributeValue<>(serializer.duplicate(value), serializer);
     }
 
-    public JsonNode toJson() {
-        ObjectNode serialized = JsonNodeFactory.instance.objectNode();
-        serialized.put("serializer", serializer.getName());
-        serialized.replace("value", serializer.serialize(value));
-        return serialized;
+    public Optional<JsonNode> toJson() {
+        return serializer.serialize(value)
+            .map(value -> {
+                ObjectNode serialized = JsonNodeFactory.instance.objectNode();
+                serialized.put("serializer", serializer.getName());
+                serialized.replace("value", value);
+                return serialized;
+            });
     }
 
     public T getValue() {
diff --git a/mailet/api/src/main/java/org/apache/mailet/Serializer.java b/mailet/api/src/main/java/org/apache/mailet/Serializer.java
index f9fc2f07d6..cd1397460f 100644
--- a/mailet/api/src/main/java/org/apache/mailet/Serializer.java
+++ b/mailet/api/src/main/java/org/apache/mailet/Serializer.java
@@ -21,9 +21,7 @@ package org.apache.mailet;
 
 import static java.time.format.DateTimeFormatter.ISO_DATE_TIME;
 
-import java.io.IOException;
 import java.io.Serializable;
-import java.io.UncheckedIOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.time.ZonedDateTime;
@@ -31,22 +29,19 @@ import java.util.Base64;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
+import org.apache.commons.lang3.NotImplementedException;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.mailbox.model.MessageIdDto;
 import org.apache.james.util.streams.Iterators;
-import org.nustaq.serialization.FSTConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.BooleanNode;
 import com.fasterxml.jackson.databind.node.DoubleNode;
@@ -67,7 +62,7 @@ import com.google.common.collect.ImmutableMap;
  */
 @SuppressWarnings("EqualsHashCode")
 public interface Serializer<T> {
-    JsonNode serialize(T object);
+    Optional<JsonNode> serialize(T object);
 
     Optional<T> deserialize(JsonNode json);
 
@@ -95,6 +90,7 @@ public interface Serializer<T> {
                     URL_SERIALIZER,
                     new CollectionSerializer<>(),
                     new MapSerializer<>(),
+                    // To be dropped in 3.9.0
                     new FSTSerializer(),
                     new OptionalSerializer<>())
                 .collect(ImmutableMap.toImmutableMap(Serializer::getName, Function.identity()));
@@ -107,8 +103,8 @@ public interface Serializer<T> {
 
     class BooleanSerializer implements Serializer<Boolean> {
         @Override
-        public JsonNode serialize(Boolean object) {
-            return BooleanNode.valueOf(object);
+        public Optional<JsonNode> serialize(Boolean object) {
+            return Optional.of(BooleanNode.valueOf(object));
         }
 
         @Override
@@ -145,8 +141,8 @@ public interface Serializer<T> {
 
     class StringSerializer implements Serializer<String> {
         @Override
-        public JsonNode serialize(String object) {
-            return TextNode.valueOf(object);
+        public Optional<JsonNode> serialize(String object) {
+            return Optional.of(TextNode.valueOf(object));
         }
 
         @Override
@@ -183,8 +179,8 @@ public interface Serializer<T> {
 
     class IntSerializer implements Serializer<Integer> {
         @Override
-        public JsonNode serialize(Integer object) {
-            return IntNode.valueOf(object);
+        public Optional<JsonNode> serialize(Integer object) {
+            return Optional.of(IntNode.valueOf(object));
         }
 
         @Override
@@ -221,8 +217,8 @@ public interface Serializer<T> {
 
     class LongSerializer implements Serializer<Long> {
         @Override
-        public JsonNode serialize(Long object) {
-            return LongNode.valueOf(object);
+        public Optional<JsonNode> serialize(Long object) {
+            return Optional.of(LongNode.valueOf(object));
         }
 
         @Override
@@ -261,8 +257,8 @@ public interface Serializer<T> {
 
     class FloatSerializer implements Serializer<Float> {
         @Override
-        public JsonNode serialize(Float object) {
-            return FloatNode.valueOf(object);
+        public Optional<JsonNode> serialize(Float object) {
+            return Optional.of(FloatNode.valueOf(object));
         }
 
         @Override
@@ -301,8 +297,8 @@ public interface Serializer<T> {
 
     class DoubleSerializer implements Serializer<Double> {
         @Override
-        public JsonNode serialize(Double object) {
-            return DoubleNode.valueOf(object);
+        public Optional<JsonNode> serialize(Double object) {
+            return Optional.of(DoubleNode.valueOf(object));
         }
 
         @Override
@@ -339,9 +335,9 @@ public interface Serializer<T> {
 
     class DateSerializer implements Serializer<ZonedDateTime> {
         @Override
-        public JsonNode serialize(ZonedDateTime object) {
+        public Optional<JsonNode> serialize(ZonedDateTime object) {
             String serialized = object.format(ISO_DATE_TIME);
-            return TextNode.valueOf(serialized);
+            return Optional.of(TextNode.valueOf(serialized));
         }
 
         @Override
@@ -380,7 +376,7 @@ public interface Serializer<T> {
     class MessageIdDtoSerializer implements Serializer<MessageIdDto> {
 
         @Override
-        public JsonNode serialize(MessageIdDto serializable) {
+        public Optional<JsonNode> serialize(MessageIdDto serializable) {
             return STRING_SERIALIZER
                     .serialize(serializable.asString());
         }
@@ -419,12 +415,12 @@ public interface Serializer<T> {
         private static final Logger LOGGER = LoggerFactory.getLogger(ArbitrarySerializableSerializer.class);
 
         @Override
-        public JsonNode serialize(T serializable) {
+        public Optional<JsonNode> serialize(T serializable) {
             ArbitrarySerializable.Serializable<T> serialized = serializable.serialize();
             ObjectNode serializedJson = JsonNodeFactory.instance.objectNode();
             serializedJson.put("deserializer", serialized.getDeserializer().getName());
-            serializedJson.replace("value", serialized.getValue().toJson());
-            return serializedJson;
+            serializedJson.replace("value", serialized.getValue().toJson().get());
+            return Optional.of(serializedJson);
         }
 
         @Override
@@ -474,13 +470,13 @@ public interface Serializer<T> {
 
         @Override
         public T duplicate(T value) {
-            return deserialize(serialize(value)).get();
+            return deserialize(serialize(value).get()).get();
         }
     }
 
     class UrlSerializer implements Serializer<URL> {
         @Override
-        public JsonNode serialize(URL object) {
+        public Optional<JsonNode> serialize(URL object) {
             return STRING_SERIALIZER.serialize(object.toString());
         }
 
@@ -520,11 +516,12 @@ public interface Serializer<T> {
 
     class CollectionSerializer<U> implements Serializer<Collection<AttributeValue<U>>> {
         @Override
-        public JsonNode serialize(Collection<AttributeValue<U>> object) {
+        public Optional<JsonNode> serialize(Collection<AttributeValue<U>> object) {
             List<JsonNode> jsons = object.stream()
                 .map(AttributeValue::toJson)
+                .flatMap(Optional::stream)
                 .collect(ImmutableList.toImmutableList());
-            return new ArrayNode(JsonNodeFactory.instance, jsons);
+            return Optional.of(new ArrayNode(JsonNodeFactory.instance, jsons));
         }
 
         @SuppressWarnings("unchecked")
@@ -564,10 +561,11 @@ public interface Serializer<T> {
 
     class MapSerializer<U> implements Serializer<Map<String, AttributeValue<U>>> {
         @Override
-        public JsonNode serialize(Map<String, AttributeValue<U>> object) {
+        public Optional<JsonNode> serialize(Map<String, AttributeValue<U>> object) {
             Map<String, JsonNode> jsonMap = object.entrySet().stream()
-                .collect(ImmutableMap.toImmutableMap(Entry::getKey, entry -> entry.getValue().toJson()));
-            return new ObjectNode(JsonNodeFactory.instance, jsonMap);
+                .flatMap(entry -> entry.getValue().toJson().map(value -> Pair.of(entry.getKey(), value)).stream())
+                .collect(ImmutableMap.toImmutableMap(Pair::getKey, Pair::getValue));
+            return Optional.of(new ObjectNode(JsonNodeFactory.instance, jsonMap));
         }
 
         @SuppressWarnings("unchecked")
@@ -610,9 +608,9 @@ public interface Serializer<T> {
 
     class OptionalSerializer<U> implements Serializer<Optional<AttributeValue<U>>> {
         @Override
-        public JsonNode serialize(Optional<AttributeValue<U>> object) {
+        public Optional<JsonNode> serialize(Optional<AttributeValue<U>> object) {
             return object.map(AttributeValue::toJson)
-                .orElse(NullNode.getInstance());
+                .orElse(Optional.of(NullNode.getInstance()));
         }
 
         @SuppressWarnings("unchecked")
@@ -650,45 +648,24 @@ public interface Serializer<T> {
     }
 
     class FSTSerializer implements Serializer<Serializable> {
-        static final FSTConfiguration CONFIGURATION = FSTConfiguration.createJsonConfiguration();
-
         @Override
-        public JsonNode serialize(Serializable object) {
-            String json = CONFIGURATION.asJsonString(object);
-            try {
-                return new ObjectMapper().reader().readTree(json);
-            } catch (IOException e) {
-                throw new UncheckedIOException(e);
-            }
+        public Optional<JsonNode> serialize(Serializable object) {
+            return Optional.empty();
         }
 
         @Override
         public Optional<Serializable> deserialize(JsonNode json) {
-            try {
-                return Optional.of((Serializable) CONFIGURATION.asObject(new ObjectMapper().writer().writeValueAsBytes(json)));
-            } catch (JsonProcessingException e) {
-                throw new UncheckedIOException(e);
-            }
-        }
-
-        @Override
-        public Serializable duplicate(Serializable value) {
-            return deserialize(serialize(value)).get();
+            return Optional.empty();
         }
 
         @Override
         public String getName() {
-            return "FSTSerializer";
+            return "NoSerializer";
         }
 
         @Override
-        public boolean equals(Object other) {
-            return this.getClass() == other.getClass();
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(getClass());
+        public Serializable duplicate(Serializable value) {
+            throw new NotImplementedException();
         }
     }
 
@@ -697,7 +674,7 @@ public interface Serializer<T> {
     class BytesSerializer implements Serializer<byte[]> {
 
         @Override
-        public JsonNode serialize(byte[] object) {
+        public Optional<JsonNode> serialize(byte[] object) {
             return STRING_SERIALIZER.serialize(Base64.getEncoder().encodeToString(object));
         }
 
@@ -728,4 +705,26 @@ public interface Serializer<T> {
         }
     }
 
+    class NoSerializer implements Serializer<Object> {
+        @Override
+        public Optional<JsonNode> serialize(Object object) {
+            return Optional.empty();
+        }
+
+        @Override
+        public Optional<Object> deserialize(JsonNode json) {
+            return Optional.empty();
+        }
+
+        @Override
+        public String getName() {
+            return "NoSerializer";
+        }
+
+        @Override
+        public Object duplicate(Object value) {
+            return value;
+        }
+    }
+
 }
diff --git a/mailet/api/src/test/java/org/apache/mailet/AttributeValueTest.java b/mailet/api/src/test/java/org/apache/mailet/AttributeValueTest.java
index be41e3765e..384b5a5d21 100644
--- a/mailet/api/src/test/java/org/apache/mailet/AttributeValueTest.java
+++ b/mailet/api/src/test/java/org/apache/mailet/AttributeValueTest.java
@@ -61,7 +61,7 @@ class AttributeValueTest {
         void stringShouldBeSerializedAndBack() {
             AttributeValue<String> expected = AttributeValue.of("value");
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -71,7 +71,7 @@ class AttributeValueTest {
         void emptyStringShouldBeSerializedAndBack() {
             AttributeValue<String> expected = AttributeValue.of("");
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -105,7 +105,7 @@ class AttributeValueTest {
         void trueShouldBeSerializedAndBack() {
             AttributeValue<Boolean> expected = AttributeValue.of(true);
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -115,7 +115,7 @@ class AttributeValueTest {
         void falseShouldBeSerializedAndBack() {
             AttributeValue<Boolean> expected = AttributeValue.of(true);
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -149,7 +149,7 @@ class AttributeValueTest {
         void intShouldBeSerializedAndBack() {
             AttributeValue<Integer> expected = AttributeValue.of(42);
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -196,7 +196,7 @@ class AttributeValueTest {
         void longShouldBeSerializedAndBack() {
             AttributeValue<Long> expected = AttributeValue.of(42L);
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -206,7 +206,7 @@ class AttributeValueTest {
         void longShouldBeSerializedAndBackForLongMaxValue() {
             AttributeValue<Long> expected = AttributeValue.of(Long.MAX_VALUE);
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -246,7 +246,7 @@ class AttributeValueTest {
         void floatShouldBeSerializedAndBack() {
             AttributeValue<Float> expected = AttributeValue.of(1.0f);
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -286,7 +286,7 @@ class AttributeValueTest {
         void doubleShouldBeSerializedAndBack() {
             AttributeValue<Double> expected = AttributeValue.of(1.0d);
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -296,7 +296,7 @@ class AttributeValueTest {
         void doubleShouldBeSerializedAndBackForMaxValue() {
             AttributeValue<Double> expected = AttributeValue.of(Double.MAX_VALUE);
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -336,7 +336,7 @@ class AttributeValueTest {
         void dateShouldBeSerializedAndBack() {
             AttributeValue<ZonedDateTime> expected = AttributeValue.of(ZonedDateTime.parse("2015-10-30T16:12:00Z"));
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -376,7 +376,7 @@ class AttributeValueTest {
         void queueSerializableShouldBeSerializedAndBack() {
             AttributeValue<TestArbitrarySerializable> expected = AttributeValue.of(new TestArbitrarySerializable(42));
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -399,7 +399,7 @@ class AttributeValueTest {
         void urlShouldBeSerializedAndBack() throws MalformedURLException {
             AttributeValue<URL> expected = AttributeValue.of(new URL("https://james.apache.org/"));
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -439,7 +439,7 @@ class AttributeValueTest {
         void messageIdShouldBeSerializedAndBack() {
             AttributeValue<MessageIdDto> expected = AttributeValue.of(new MessageIdDto(TestMessageId.of(42)));
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -479,7 +479,7 @@ class AttributeValueTest {
         void emptyStringListShouldBeSerializedAndBack() {
             AttributeValue<?> expected = AttributeValue.ofAny(ImmutableList.<String>of());
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -489,7 +489,7 @@ class AttributeValueTest {
         void listShouldBeSerializedAndBack() {
             AttributeValue<?> expected = AttributeValue.of(ImmutableList.of(AttributeValue.of("first"), AttributeValue.of("second")));
 
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -540,7 +540,7 @@ class AttributeValueTest {
         @Test
         void emptyMapShouldBeSerializedAndBack() {
             AttributeValue<?> expected = AttributeValue.of(ImmutableMap.of());
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -549,7 +549,7 @@ class AttributeValueTest {
         @Test
         void mapWithPrimitiveTypesShouldBeSerializedAndBack() {
             AttributeValue<?> expected = AttributeValue.of(ImmutableMap.of("a", AttributeValue.of("value"), "b", AttributeValue.of(12)));
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -603,7 +603,7 @@ class AttributeValueTest {
         @Test
         void emptyOptionalShouldBeSerializedAndBack() {
             AttributeValue<?> expected = AttributeValue.of(Optional.empty());
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -612,7 +612,7 @@ class AttributeValueTest {
         @Test
         void optionalShouldBeSerializedAndBack() {
             AttributeValue<?> expected = AttributeValue.of(Optional.of(AttributeValue.of(42)));
-            JsonNode json = expected.toJson();
+            JsonNode json = expected.toJson().get();
             AttributeValue<?> actual = AttributeValue.fromJson(json);
 
             assertThat(actual).isEqualTo(expected);
@@ -652,34 +652,6 @@ class AttributeValueTest {
         }
     }
 
-    @Nested
-    class SerializableSerialization {
-        @Test
-        void filledSerializabletrueShouldBeSerializedAndBack() {
-            AttributeValue<java.io.Serializable> expected = AttributeValue.ofSerializable(new TestSerializable("me"));
-
-            JsonNode json = expected.toJson();
-            AttributeValue<?> actual = AttributeValue.fromJson(json);
-
-            assertThat(actual).isEqualTo(expected);
-        }
-
-        @Test
-        void nullSerializableShouldThrowAnException() {
-            assertThatNullPointerException()
-                .isThrownBy(() -> AttributeValue.ofSerializable((java.io.Serializable) null));
-        }
-
-        @Test
-        void fromJsonStringShouldReturnBooleanAttributeValueWhenBoolean() throws Exception {
-            AttributeValue<java.io.Serializable> expected = AttributeValue.ofSerializable(new TestSerializable("me"));
-
-            AttributeValue<?> actual = AttributeValue.fromJsonString("{\"serializer\":\"FSTSerializer\",\"value\":{\"typ\":\"org.apache.mailet.AttributeValueTest$TestSerializable\",\"obj\":{\"name\":\"me\"}}}");
-
-            assertThat(actual).isEqualTo(expected);
-        }
-    }
-
     @Test
     void fromJsonStringShouldThrowOnUnknownSerializer() {
         assertThatIllegalStateException()
diff --git a/mailet/crypto/src/main/java/org/apache/james/transport/mailets/SMIMECheckSignature.java b/mailet/crypto/src/main/java/org/apache/james/transport/mailets/SMIMECheckSignature.java
index 7197186ff5..d49f5a1c2d 100644
--- a/mailet/crypto/src/main/java/org/apache/james/transport/mailets/SMIMECheckSignature.java
+++ b/mailet/crypto/src/main/java/org/apache/james/transport/mailets/SMIMECheckSignature.java
@@ -22,6 +22,7 @@
 package org.apache.james.transport.mailets;
 
 import java.io.IOException;
+import java.security.cert.CertificateEncodingException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -107,16 +108,9 @@ public class SMIMECheckSignature extends GenericMailet {
     private static final Logger LOGGER = LoggerFactory.getLogger(SMIMECheckSignature.class);
 
     private KeyStoreHolder trustedCertificateStore;
-    
     private boolean stripSignature = false;
     private boolean onlyTrusted = true;
-    
     private AttributeName mailAttribute = AttributeName.of("org.apache.james.SMIMECheckSignature");
-    
-    public SMIMECheckSignature() {
-        super();
-
-    }
 
     @Override
     public void init() throws MessagingException {
@@ -168,18 +162,8 @@ public class SMIMECheckSignature extends GenericMailet {
         List<SMIMESignerInfo> signers = null;
         
         try {
-            Object obj = message.getContent();
-            SMIMESigned signed;
-            if (obj instanceof MimeMultipart) {
-                signed = new SMIMESigned((MimeMultipart) message.getContent());
-            } else if (obj instanceof SMIMESigned) {
-                signed = (SMIMESigned) obj;
-            } else if (obj instanceof byte[]) {
-                signed = new SMIMESigned(message);
-            } else {
-                signed = null;
-            }
-            
+            SMIMESigned signed = asSMIMESigned(message);
+
             if (signed != null) {
                 signers = trustedCertificateStore.verifySignatures(signed);
                 strippedMessage = signed.getContent();
@@ -187,10 +171,8 @@ public class SMIMECheckSignature extends GenericMailet {
                 LOGGER.info("Content not identified as signed");
             }
             
-            // These errors are logged but they don't cause the 
-            // message to change its state. The message 
-            // is considered as not signed and the process will
-            // go on.
+            // These errors are logged but they don't cause the message to change its state. The message
+            // is considered as not signed and the process will go on.
         } catch (CMSException | SMIMEException e) {
             LOGGER.error("Error during the analysis of the signed message", e);
             signers = null;
@@ -205,16 +187,9 @@ public class SMIMECheckSignature extends GenericMailet {
         // If at least one mail signer is found 
         // the mail attributes are set.
         if (signers != null) {
-            ArrayList<AttributeValue<?>> signerinfolist = new ArrayList<>();
+            ArrayList<AttributeValue<?>> signerinfolist = signerInfoList(signers);
 
-            for (SMIMESignerInfo info : signers) {
-                if (info.isSignValid()
-                        && (!onlyTrusted || info.getCertPath() != null)) {
-                    signerinfolist.add(AttributeValue.ofSerializable(info.getSignerCertificate()));
-                }
-            }
-
-            if (signerinfolist.size() > 0) {
+            if (!signerinfolist.isEmpty()) {
                 mail.setAttribute(new Attribute(mailAttribute, AttributeValue.of(signerinfolist)));
             } else {
                 // if no valid signers are found the message is not modified.
@@ -223,21 +198,53 @@ public class SMIMECheckSignature extends GenericMailet {
         }
 
         if (stripSignature && strippedMessage != null) {
-            try {
-                Object obj = strippedMessage.getContent();
-                if (obj instanceof Multipart) {
-                    message.setContent((Multipart) obj);
-                } else {
-                    message.setContent(obj, strippedMessage.getContentType());
+            stripSignature(mail, message, strippedMessage);
+        }
+    }
+
+    private ArrayList<AttributeValue<?>> signerInfoList(List<SMIMESignerInfo> signers) {
+        ArrayList<AttributeValue<?>> signerinfolist = new ArrayList<>();
+
+        for (SMIMESignerInfo info : signers) {
+            if (info.isSignValid()
+                    && (!onlyTrusted || info.getCertPath() != null)) {
+                try {
+                    signerinfolist.add(AttributeValue.of(info.getSignerCertificate().getEncoded()));
+                } catch (CertificateEncodingException e) {
+                    LOGGER.warn("Failed to encode certificate", e);
                 }
-                message.saveChanges();
-                mail.setMessage(message);
-            } catch (Exception e) {
-                throw new MessagingException(
-                        "Error during the extraction of the signed content from the message.",
-                        e);
             }
         }
+        return signerinfolist;
     }
 
+    private void stripSignature(Mail mail, MimeMessage message, MimeBodyPart strippedMessage) throws MessagingException {
+        try {
+            Object obj = strippedMessage.getContent();
+            if (obj instanceof Multipart) {
+                message.setContent((Multipart) obj);
+            } else {
+                message.setContent(obj, strippedMessage.getContentType());
+            }
+            message.saveChanges();
+            mail.setMessage(message);
+        } catch (Exception e) {
+            throw new MessagingException("Error during the extraction of the signed content from the message.", e);
+        }
+    }
+
+    private SMIMESigned asSMIMESigned(MimeMessage message) throws IOException, MessagingException, CMSException, SMIMEException {
+        Object obj = message.getContent();
+        SMIMESigned signed;
+        if (obj instanceof MimeMultipart) {
+            signed = new SMIMESigned((MimeMultipart) message.getContent());
+        } else if (obj instanceof SMIMESigned) {
+            signed = (SMIMESigned) obj;
+        } else if (obj instanceof byte[]) {
+            signed = new SMIMESigned(message);
+        } else {
+            signed = null;
+        }
+        return signed;
+    }
 }
diff --git a/mailet/crypto/src/main/java/org/apache/james/transport/mailets/SMIMEDecrypt.java b/mailet/crypto/src/main/java/org/apache/james/transport/mailets/SMIMEDecrypt.java
index b95efdb060..e4dd423636 100644
--- a/mailet/crypto/src/main/java/org/apache/james/transport/mailets/SMIMEDecrypt.java
+++ b/mailet/crypto/src/main/java/org/apache/james/transport/mailets/SMIMEDecrypt.java
@@ -163,7 +163,11 @@ public class SMIMEDecrypt extends GenericMailet {
             // it is possible to reuse the same matchers to analyze
             // the result of the operation.
             ArrayList<AttributeValue<?>> list = new ArrayList<>(1);
-            list.add(AttributeValue.ofSerializable(keyHolder.getCertificate()));
+            try {
+                list.add(AttributeValue.of(keyHolder.getCertificate().getEncoded()));
+            } catch (CertificateEncodingException e) {
+                LOGGER.warn("Failed to encode certificate", e);
+            }
             mail.setAttribute(new Attribute(mailAttribute, AttributeValue.of(list)));
 
             // I start the message stripping.
diff --git a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICalendarParser.java b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICalendarParser.java
index 2bc812c110..aaf373494c 100644
--- a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICalendarParser.java
+++ b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICalendarParser.java
@@ -123,7 +123,7 @@ public class ICalendarParser extends GenericMailet {
         Map<String, AttributeValue<?>> calendars = icsAttachments.entrySet()
             .stream()
             .flatMap(entry -> createCalendar(entry.getKey(), entry.getValue().getValue()))
-            .collect(ImmutableMap.toImmutableMap(Pair::getKey, pair -> AttributeValue.ofSerializable(pair.getValue())));
+            .collect(ImmutableMap.toImmutableMap(Pair::getKey, pair -> AttributeValue.ofUnserializable(pair.getValue())));
 
         mail.setAttribute(new Attribute(destinationAttributeName, AttributeValue.of(calendars)));
     }
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToHeadersTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToHeadersTest.java
index 93d04de746..c1f96268ad 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToHeadersTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToHeadersTest.java
@@ -134,7 +134,7 @@ class ICALToHeadersTest {
     void serviceShouldWriteSingleICalendarToHeaders() throws Exception {
         Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
         Map<String, AttributeValue<?>> icals = ImmutableMap.<String, AttributeValue<?>>builder()
-            .put("key", AttributeValue.ofSerializable(calendar))
+            .put("key", AttributeValue.ofUnserializable(calendar))
             .build();
 
         testee.init(FakeMailetConfig.builder().build());
@@ -161,7 +161,7 @@ class ICALToHeadersTest {
     void serviceShouldNotWriteHeaderWhenPropertyIsAbsent() throws Exception {
         Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting_without_dtstamp.ics"));
         Map<String, AttributeValue<?>> icals = ImmutableMap.<String, AttributeValue<?>>builder()
-            .put("key", AttributeValue.ofSerializable(calendar))
+            .put("key", AttributeValue.ofUnserializable(calendar))
             .build();
 
         testee.init(FakeMailetConfig.builder().build());
@@ -188,8 +188,8 @@ class ICALToHeadersTest {
         Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
         Calendar calendar2 = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting_2.ics"));
         Map<String, AttributeValue<?>> icals = ImmutableMap.<String, AttributeValue<?>>builder()
-            .put("key", AttributeValue.ofSerializable(calendar))
-            .put("key2", AttributeValue.ofSerializable(calendar2))
+            .put("key", AttributeValue.ofUnserializable(calendar))
+            .put("key2", AttributeValue.ofUnserializable(calendar2))
             .build();
 
         testee.init(FakeMailetConfig.builder().build());
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
index a23dd83e01..f85a3de513 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
@@ -206,7 +206,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         Mail mail = FakeMail.builder()
@@ -226,7 +226,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/no_event.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         Mail mail = FakeMail.builder()
@@ -248,7 +248,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         Mail mail = FakeMail.builder()
@@ -268,7 +268,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
@@ -310,7 +310,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
@@ -361,7 +361,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
@@ -399,7 +399,7 @@ public class ICALToJsonAttributeTest {
     void serviceShouldAttachJsonForSeveralRecipient() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         Mail mail = FakeMail.builder()
@@ -437,8 +437,8 @@ public class ICALToJsonAttributeTest {
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
         AttributeValue<byte[]> ics2 = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting_2.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
-        AttributeValue<Serializable> calendar2 = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics2.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar2 = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics2.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar, "key2", calendar2);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics, "key2", ics2);
         MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
@@ -488,8 +488,8 @@ public class ICALToJsonAttributeTest {
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
         AttributeValue<byte[]> ics2 = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting_without_uid.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
-        AttributeValue<Serializable> calendar2 = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics2.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar2 = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics2.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar, "key2", calendar2);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics, "key2", ics2);
         MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
@@ -528,8 +528,8 @@ public class ICALToJsonAttributeTest {
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
         AttributeValue<byte[]> ics2 = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting_2.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
-        AttributeValue<Serializable> calendar2 = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics2.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar2 = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics2.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar, "key2", calendar2);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
@@ -567,7 +567,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
@@ -607,7 +607,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
@@ -645,7 +645,7 @@ public class ICALToJsonAttributeTest {
         testee.init(FakeMailetConfig.builder().build());
 
         AttributeValue<byte[]> ics = AttributeValue.of(ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics"));
-        AttributeValue<Serializable> calendar = AttributeValue.ofSerializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
+        AttributeValue<Object> calendar = AttributeValue.ofUnserializable(new CalendarBuilder().build(new ByteArrayInputStream(ics.getValue())));
         Map<String, AttributeValue<?>> icals = ImmutableMap.of("key", calendar);
         Map<String, AttributeValue<?>> rawIcals = ImmutableMap.of("key", ics);
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
index 11ced1038f..19407af5a3 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
@@ -89,7 +89,7 @@ class ICalendarParserTest {
 
     static final String WRONG_ICAL_VALUE = "anyValue";
     @SuppressWarnings("unchecked")
-    static final Class<Map<String, AttributeValue<Serializable>>> MAP_STRING_CALENDAR_CLASS = (Class<Map<String, AttributeValue<Serializable>>>) (Object) Map.class;
+    static final Class<Map<String, AttributeValue<Object>>> MAP_STRING_CALENDAR_CLASS = (Class<Map<String, AttributeValue<Object>>>) (Object) Map.class;
 
     ICalendarParser mailet = new ICalendarParser();
 
@@ -262,13 +262,11 @@ class ICalendarParserTest {
 
         mailet.service(mail);
 
-        Optional<Map<String, AttributeValue<Serializable>>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
-        Map.Entry<String, AttributeValue<Serializable>> expectedCalendar = Maps.immutableEntry("key2", AttributeValue.ofSerializable(new Calendar()));
+        Optional<Map<String, AttributeValue<Object>>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
 
         assertThat(expectedCalendars).hasValueSatisfying(calendars ->
             assertThat(calendars)
-                .hasSize(1)
-                .containsExactly(expectedCalendar));
+                .hasSize(1));
     }
 
     @Test
@@ -291,7 +289,7 @@ class ICalendarParserTest {
 
         mailet.service(mail);
 
-        Optional<Map<String, AttributeValue<Serializable>>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
+        Optional<Map<String, AttributeValue<Object>>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
 
         assertThat(expectedCalendars).hasValueSatisfying(calendars ->
             assertThat(calendars)
@@ -300,7 +298,7 @@ class ICalendarParserTest {
     }
 
     @Test
-    void getMailetInfoShouldReturn() throws MessagingException {
+    void getMailetInfoShouldReturn() {
         assertThat(mailet.getMailetInfo()).isEqualTo("Calendar Parser");
     }
 
@@ -325,13 +323,13 @@ class ICalendarParserTest {
 
         mailet.service(mail);
 
-        Optional<Map<String, AttributeValue<Serializable>>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
+        Optional<Map<String, AttributeValue<Object>>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
         assertThat(expectedCalendars).hasValueSatisfying(calendars ->
                 assertThat(calendars)
                         .hasSize(1));
     }
 
     private Attribute makeCustomSourceAttribute(Serializable attachments) {
-        return new Attribute(SOURCE_CUSTOM_ATTRIBUTE_NAME, AttributeValue.ofSerializable(attachments));
+        return new Attribute(SOURCE_CUSTOM_ATTRIBUTE_NAME, AttributeValue.ofUnserializable(attachments));
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
index e4b4c683f4..18929b6d52 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
@@ -36,8 +36,7 @@ import org.apache.mailet.base.test.MailUtil;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-public class HasExceptionTest {
-
+class HasExceptionTest {
     private FakeMail mockedMail;
     private Matcher testee;
 
@@ -49,8 +48,8 @@ public class HasExceptionTest {
     }
 
     @Test
-    public void matchShouldReturnAddressesWhenSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new AddressException())));
+    void matchShouldReturnAddressesWhenSpecifiedExceptionHasOccurred() throws MessagingException {
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofUnserializable(new AddressException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -63,8 +62,8 @@ public class HasExceptionTest {
     }
 
     @Test
-    public void matchShouldReturnAddressesWhenSubclassOfSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new AddressException())));
+    void matchShouldReturnAddressesWhenSubclassOfSpecifiedExceptionHasOccurred() throws MessagingException {
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofUnserializable(new AddressException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -77,8 +76,8 @@ public class HasExceptionTest {
     }
 
     @Test
-    public void matchShouldReturnEmptyWhenOtherExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new java.lang.RuntimeException())));
+    void matchShouldReturnEmptyWhenOtherExceptionHasOccurred() throws MessagingException {
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofUnserializable(new java.lang.RuntimeException())));
 
         testee.init(FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -89,8 +88,8 @@ public class HasExceptionTest {
     }
 
     @Test
-    public void matchShouldReturnEmptyWhenSuperclassOfSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new javax.mail.MessagingException())));
+    void matchShouldReturnEmptyWhenSuperclassOfSpecifiedExceptionHasOccurred() throws MessagingException {
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofUnserializable(new javax.mail.MessagingException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -103,7 +102,7 @@ public class HasExceptionTest {
     }
 
     @Test
-    public void matchShouldReturnEmptyWhenNoExceptionHasOccurred() throws MessagingException {
+    void matchShouldReturnEmptyWhenNoExceptionHasOccurred() throws MessagingException {
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
                 .condition("java.lang.Exception")
@@ -115,8 +114,8 @@ public class HasExceptionTest {
     }
 
     @Test
-    public void matchShouldReturnEmptyWhenNonExceptionIsAttached() throws MessagingException {
-        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.of(new java.lang.String())));
+    void matchShouldReturnEmptyWhenNonExceptionIsAttached() throws MessagingException {
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.of("")));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -129,7 +128,7 @@ public class HasExceptionTest {
     }
 
     @Test
-    public void initShouldRaiseMessagingExceptionWhenInvalidClassName() throws MessagingException {
+    void initShouldRaiseMessagingExceptionWhenInvalidClassName() {
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
                 .condition("java.lang.InvalidClassName")
@@ -139,7 +138,7 @@ public class HasExceptionTest {
     }
 
     @Test
-    public void initShouldRaiseMessagingExceptionWhenClassNameIsNotException() throws MessagingException {
+    void initShouldRaiseMessagingExceptionWhenClassNameIsNotException() {
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
                 .condition("java.lang.String")
@@ -149,8 +148,8 @@ public class HasExceptionTest {
     }
     
     @Test
-    public void initShouldRaiseMessagingExceptionWhenClassNameIsNotFullyQualified() throws MessagingException {
-        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new javax.mail.MessagingException())));
+    void initShouldRaiseMessagingExceptionWhenClassNameIsNotFullyQualified() {
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofUnserializable(new javax.mail.MessagingException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
diff --git a/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java b/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java
index 9ae9876544..a47b7da297 100644
--- a/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java
+++ b/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java
@@ -44,6 +44,7 @@ import javax.mail.internet.MimeMessage;
 import javax.mail.internet.ParseException;
 
 import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
 import org.apache.james.core.builder.MimeMessageBuilder;
@@ -685,9 +686,8 @@ public class MailImpl implements Disposable, Mail {
     private Map<String, String> getAttributesAsJson() {
         return attributes.values()
             .stream()
-            .collect(Collectors.toMap(
-                attribute -> attribute.getName().asString(),
-                attribute -> attribute.getValue().toJson().toString()));
+            .flatMap(entry -> entry.getValue().toJson().map(value -> Pair.of(entry.getName().asString(), value.toString())).stream())
+            .collect(ImmutableMap.toImmutableMap(Pair::getKey, Pair::getValue));
     }
 
     /**
diff --git a/server/data/data-jpa/src/main/java/org/apache/james/mailrepository/jpa/JPAMailRepository.java b/server/data/data-jpa/src/main/java/org/apache/james/mailrepository/jpa/JPAMailRepository.java
index 575592e441..667a0e4ab1 100644
--- a/server/data/data-jpa/src/main/java/org/apache/james/mailrepository/jpa/JPAMailRepository.java
+++ b/server/data/data-jpa/src/main/java/org/apache/james/mailrepository/jpa/JPAMailRepository.java
@@ -44,6 +44,7 @@ import javax.persistence.NoResultException;
 import org.apache.commons.configuration2.HierarchicalConfiguration;
 import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.commons.configuration2.tree.ImmutableNode;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.backends.jpa.EntityManagerUtils;
 import org.apache.james.core.MailAddress;
 import org.apache.james.lifecycle.api.Configurable;
@@ -70,6 +71,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 /**
  * Implementation of a MailRepository on a database via JPA.
@@ -183,9 +185,9 @@ public class JPAMailRepository implements MailRepository, Configurable, Initiali
     }
 
     private String serializeAttributes(Stream<Attribute> attributes) {
-        Map<String, JsonNode> map = attributes.collect(Collectors.toMap(
-            attribute -> attribute.getName().asString(),
-            attribute -> attribute.getValue().toJson()));
+        Map<String, JsonNode> map = attributes
+            .flatMap(entry -> entry.getValue().toJson().map(value -> Pair.of(entry.getName().asString(), value)).stream())
+            .collect(ImmutableMap.toImmutableMap(Pair::getKey, Pair::getValue));
 
         return new ObjectNode(JsonNodeFactory.instance, map).toString();
     }
diff --git a/server/mailet/mailetcontainer-impl/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java b/server/mailet/mailetcontainer-impl/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
index 787b464f3f..f16141ae8e 100644
--- a/server/mailet/mailetcontainer-impl/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
+++ b/server/mailet/mailetcontainer-impl/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
@@ -65,7 +65,7 @@ public class ProcessorUtil {
         String errorString = sout.toString();
         mail.setErrorMessage(errorString);
         logger.error(errorString);
-        mail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(me)));
+        mail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofUnserializable(me)));
     }
 
     /**
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionUtils.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionUtils.java
index b3849441b4..c013e92906 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionUtils.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionUtils.java
@@ -42,10 +42,6 @@ public class ActionUtils {
 
     /**
      * Answers the sole intended recipient for aMail.
-     * 
-     * @param aMail
-     * @return String
-     * @throws MessagingException
      */
     public static MailAddress getSoleRecipient(Mail aMail) throws MessagingException {
         if (aMail.getRecipients() == null) {
@@ -53,7 +49,7 @@ public class ActionUtils {
                     + ". Exactly 1 recipient is expected.");
         } else if (1 != aMail.getRecipients().size()) {
             throw new MessagingException("Invalid number of recipients - "
-                + Integer.toString(aMail.getRecipients().size())
+                + aMail.getRecipients().size()
                 + ". Exactly 1 recipient is expected.");
         }
         return aMail.getRecipients().iterator().next();
@@ -62,18 +58,14 @@ public class ActionUtils {
     /**
      * Detect and handle locally looping mail. External loop detection is left
      * to the MTA.
-     * 
-     * @param aMail
-     * @param anAttributeSuffix
-     * @throws MessagingException
      */
     public static void detectAndHandleLocalLooping(Mail aMail, String anAttributeSuffix)
             throws MessagingException {
         MailAddress thisRecipient = getSoleRecipient(aMail);
         AttributeName attributeName = AttributeName.of(ATTRIBUTE_PREFIX + anAttributeSuffix);
         AttributeUtils
-            .getValueAndCastFromMail(aMail, attributeName, MailAddress.class)
-            .filter(lastRecipient -> lastRecipient.equals(thisRecipient))
+            .getValueAndCastFromMail(aMail, attributeName, String.class)
+            .filter(Throwing.predicate(lastRecipient -> new MailAddress(lastRecipient).equals(thisRecipient)))
             .ifPresent(Throwing.consumer(any -> {
                 MessagingException ex = new MessagingException(
                         "This message is looping! Message ID: "
@@ -81,6 +73,6 @@ public class ActionUtils {
                 LOGGER.warn(ex.getMessage(), ex);
                 throw ex;
             }).sneakyThrow());
-        aMail.setAttribute(new Attribute(attributeName, AttributeValue.ofSerializable(thisRecipient)));
+        aMail.setAttribute(new Attribute(attributeName, AttributeValue.of(thisRecipient.asString())));
     }
 }
diff --git a/server/mailrepository/mailrepository-blob/src/main/scala/org/apache/james/mailrepository/blob/MailMetadata.scala b/server/mailrepository/mailrepository-blob/src/main/scala/org/apache/james/mailrepository/blob/MailMetadata.scala
index 92df76ef0b..a66de9d7ee 100644
--- a/server/mailrepository/mailrepository-blob/src/main/scala/org/apache/james/mailrepository/blob/MailMetadata.scala
+++ b/server/mailrepository/mailrepository-blob/src/main/scala/org/apache/james/mailrepository/blob/MailMetadata.scala
@@ -54,7 +54,7 @@ private[blob] object MailMetadata {
 
   private def serializedAttributes(mail: Mail): Map[String, String] =
     mail.attributes().toScala(LazyList)
-      .map(attribute => attribute.getName.asString() -> attribute.getValue.toJson.toString)
+      .flatMap(attribute => attribute.getValue.toJson.toScala.map(value => attribute.getName.asString() -> value.toString))
       .toMap
 
   private def fromPerRecipientHeaders(mail: Mail): Map[String, Iterable[Header]] = {
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
index 27461392c3..d8fac3d3de 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
@@ -76,6 +76,7 @@ import com.datastax.oss.driver.api.core.cql.Row;
 import com.datastax.oss.driver.api.core.data.TupleValue;
 import com.datastax.oss.driver.api.core.type.DataTypes;
 import com.datastax.oss.driver.api.core.type.TupleType;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.github.fge.lambdas.Throwing;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
@@ -277,7 +278,7 @@ public class CassandraMailRepositoryMailDaoV2 {
 
     private ImmutableMap<String, String> toRawAttributeMap(Mail mail) {
         return mail.attributes()
-            .map(attribute -> Pair.of(attribute.getName().asString(), toJson(attribute.getValue())))
+            .flatMap(attribute -> attribute.getValue().toJson().map(JsonNode::toString).map(value -> Pair.of(attribute.getName().asString(), value)).stream())
             .collect(ImmutableMap.toImmutableMap(Pair::getLeft, Pair::getRight));
     }
 
@@ -302,10 +303,6 @@ public class CassandraMailRepositoryMailDaoV2 {
         return result;
     }
 
-    private String toJson(AttributeValue<?> attributeValue) {
-        return attributeValue.toJson().toString();
-    }
-
     private MailAddress toMailAddress(String rawValue) {
         try {
             return new MailAddress(rawValue);
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
index 76dbdba531..dd218c89d7 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
@@ -335,24 +335,6 @@ public interface MailQueueContract {
             .containsOnly(header, header2);
     }
 
-    @Test
-    default void queueShouldPreserveNonStringMailAttribute() throws Exception {
-        Attribute attribute = Attribute.convertToAttribute("any", new SerializableAttribute("value"));
-        enQueue(defaultMail()
-                .name("mail")
-                .attribute(attribute)
-                .build());
-
-        MailQueue.MailQueueItem mailQueueItem = Flux.from(getMailQueue().deQueue()).blockFirst();
-        assertThat(mailQueueItem.getMail().getAttribute(attribute.getName()))
-            .hasValueSatisfying(item -> {
-                assertThat(item)
-                        .isEqualTo(attribute);
-                assertThat(item.getValue().value())
-                        .isInstanceOf(SerializableAttribute.class);
-            });
-    }
-
     @Test
     default void dequeueShouldBeFifo() throws Exception {
         String firstExpectedName = "name1";
diff --git a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSCacheableMailQueue.java b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSCacheableMailQueue.java
index b69177e5c4..af3f80bd05 100644
--- a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSCacheableMailQueue.java
+++ b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSCacheableMailQueue.java
@@ -78,6 +78,7 @@ import org.reactivestreams.Publisher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.github.fge.lambdas.Throwing;
 import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
@@ -363,9 +364,8 @@ public class JMSCacheableMailQueue implements ManageableMailQueue, JMSSupport, M
         String sender = mail.getMaybeSender().asString("");
 
         props.putAll(mail.attributes()
-            .collect(ImmutableMap.toImmutableMap(
-                attribute -> attribute.getName().asString(),
-                attribute -> attribute.getValue().toJson().toString())));
+            .flatMap(attribute -> attribute.getValue().toJson().map(JsonNode::toString).map(s -> Pair.of(attribute.getName().asString(), s)).stream())
+            .collect(ImmutableMap.toImmutableMap(Pair::getKey, Pair::getValue)));
 
         ImmutableList<String> attributeNames = mail.attributeNames()
             .map(AttributeName::asString)
diff --git a/server/queue/queue-pulsar/src/main/scala/org/apache/james/queue/pulsar/MailMetadata.scala b/server/queue/queue-pulsar/src/main/scala/org/apache/james/queue/pulsar/MailMetadata.scala
index 67a4a80847..6b6c5d712f 100644
--- a/server/queue/queue-pulsar/src/main/scala/org/apache/james/queue/pulsar/MailMetadata.scala
+++ b/server/queue/queue-pulsar/src/main/scala/org/apache/james/queue/pulsar/MailMetadata.scala
@@ -50,7 +50,7 @@ private[pulsar] object MailMetadata {
 
   private def serializedAttributes(mail: Mail): Map[String, String] =
     mail.attributes().toScala(LazyList)
-      .map(attribute => attribute.getName.asString() -> attribute.getValue.toJson.toString)
+      .flatMap(attribute => attribute.getValue.toJson.toScala.map(value => attribute.getName.asString() -> value.toString))
       .toMap
 
   private def fromPerRecipientHeaders(mail: Mail): Map[String, Iterable[Header]] = {
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/MailReferenceDTO.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/MailReferenceDTO.java
index b40a7de1b8..798166f91e 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/MailReferenceDTO.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/MailReferenceDTO.java
@@ -25,7 +25,6 @@ import java.util.Date;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.function.Function;
 import java.util.stream.Stream;
 
 import org.apache.commons.lang3.tuple.Pair;
@@ -42,6 +41,7 @@ import org.apache.mailet.PerRecipientHeaders;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.consumers.ThrowingBiConsumer;
 import com.google.common.collect.ImmutableList;
@@ -83,11 +83,9 @@ class MailReferenceDTO {
     }
 
     private static ImmutableMap<String, String> serializedAttributes(Mail mail) {
-        Function<Attribute, String> name = attribute -> attribute.getName().asString();
-        Function<Attribute, String> value = attribute -> attribute.getValue().toJson().toString();
-        return mail
-                .attributes()
-                .collect(ImmutableMap.toImmutableMap(name, value));
+        return mail.attributes()
+            .flatMap(attribute -> attribute.getValue().toJson().map(JsonNode::toString).map(value -> Pair.of(attribute.getName().asString(), value)).stream())
+            .collect(ImmutableMap.toImmutableMap(Pair::getLeft, Pair::getRight));
     }
 
     private final String enqueueId;
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDaoUtil.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDaoUtil.java
index 3eb2b407e6..57c65213a6 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDaoUtil.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/EnqueuedMailsDaoUtil.java
@@ -72,6 +72,7 @@ import org.apache.mailet.PerRecipientHeaders;
 import com.datastax.oss.driver.api.core.cql.Row;
 import com.datastax.oss.driver.api.core.data.TupleValue;
 import com.datastax.oss.driver.api.core.type.TupleType;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.github.fge.lambdas.Throwing;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
@@ -185,12 +186,15 @@ public class EnqueuedMailsDaoUtil {
 
     static ImmutableMap<String, ByteBuffer> toRawAttributeMap(Mail mail) {
         return mail.attributes()
-            .map(attribute -> Pair.of(attribute.getName().asString(), toByteBuffer(attribute.getValue())))
+            .flatMap(attribute -> toByteBuffer(attribute.getValue()).map(buffer -> Pair.of(attribute.getName().asString(), buffer)).stream())
             .collect(ImmutableMap.toImmutableMap(Pair::getLeft, Pair::getRight));
     }
 
-    private static ByteBuffer toByteBuffer(AttributeValue<?> attributeValue) {
-        return ByteBuffer.wrap(attributeValue.toJson().toString().getBytes(StandardCharsets.UTF_8));
+    private static Optional<ByteBuffer> toByteBuffer(AttributeValue<?> attributeValue) {
+        return attributeValue.toJson()
+            .map(JsonNode::toString)
+            .map(s -> s.getBytes(StandardCharsets.UTF_8))
+            .map(ByteBuffer::wrap);
     }
 
     static ImmutableList<TupleValue> toTupleList(TupleType userHeaderNameHeaderValueTriple, PerRecipientHeaders perRecipientHeaders) {


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