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/03/20 02:01:48 UTC

[james-project] 08/09: JAMES-2665 MailImpl should support any AttributeValue when being serialized

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 781b1dc8055a1cf1b62999208e795f4cabd4e75d
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Mar 11 11:30:49 2019 +0700

    JAMES-2665 MailImpl should support any AttributeValue when being serialized
    
    To ensure that, we should rely on Jsonable when serializing attributes.
    
    A fallback to java serialization upon failure ensures no compatibility issues are met.
---
 .../org/apache/james/server/core/MailImpl.java     | 47 +++++++++++++++++++++-
 .../org/apache/james/server/core/MailImplTest.java |  3 --
 2 files changed, 45 insertions(+), 5 deletions(-)

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 f6046d9..de17b86 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
@@ -20,6 +20,7 @@
 package org.apache.james.server.core;
 
 import java.io.IOException;
+import java.io.ObjectInputStream;
 import java.io.OptionalDataException;
 import java.io.OutputStream;
 import java.io.Serializable;
@@ -593,6 +594,36 @@ public class MailImpl implements Disposable, Mail {
         remoteHost = (String) in.readObject();
         remoteAddr = (String) in.readObject();
         setLastUpdated((Date) in.readObject());
+        try {
+            setAttributesUsingJsonable(in);
+        } catch (Exception e) {
+            setAttributesUsingJavaSerializable(in);
+        }
+        perRecipientSpecificHeaders = (PerRecipientHeaders) in.readObject();
+    }
+
+    /**
+     * Newest mailet API introduced {@link AttributeValue} which can encapsulate any class, possible not serializable.
+     *
+     * As such, algorithm relying on out of the box serialization can not handle non serializable attribute values as well as
+     * nested AttributeValue.
+     *
+     * Thus, rather than Java deserializing attributes we deserialize them as Json using AttributeValue capabilities.
+     */
+    private void setAttributesUsingJsonable(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        Map<String, String> attributesAsJson = (Map<String, String>) in.readObject();
+
+        this.attributes = attributesAsJson.entrySet().stream()
+            .map(Throwing.function(entry -> new Attribute(AttributeName.of(entry.getKey()), AttributeValue.fromJsonString(entry.getValue()))))
+            .collect(Collectors.toMap(
+                Attribute::getName,
+                Function.identity()));
+    }
+
+    /**
+     * Fallback to Java deserialization if {@link MailImpl#setAttributesUsingJsonable(ObjectInputStream)} fails.
+     */
+    private void setAttributesUsingJavaSerializable(ObjectInputStream in) throws IOException, ClassNotFoundException {
         // the following is under try/catch to be backwards compatible
         // with messages created with James version <= 2.2.0a8
         try {
@@ -604,7 +635,6 @@ public class MailImpl implements Disposable, Mail {
                 throw ode;
             }
         }
-        perRecipientSpecificHeaders = (PerRecipientHeaders) in.readObject();
     }
 
     /**
@@ -622,7 +652,7 @@ public class MailImpl implements Disposable, Mail {
         out.writeObject(remoteHost);
         out.writeObject(remoteAddr);
         out.writeObject(lastUpdated);
-        out.writeObject(getAttributesRaw());
+        out.writeObject(getAttributesAsJson());
         out.writeObject(perRecipientSpecificHeaders);
     }
 
@@ -654,6 +684,19 @@ public class MailImpl implements Disposable, Mail {
     }
 
     /**
+     * Newly serialized emails are serialized using {@link AttributeValue}.
+     *
+     * Upon deserialization, fallback to Java deserialization is handled to not introduce retro-compatibility issues.
+     */
+    private Map<String, String> getAttributesAsJson() {
+        return attributes.values()
+            .stream()
+            .collect(Collectors.toMap(
+                attribute -> attribute.getName().asString(),
+                attribute -> attribute.getValue().toJson().toString()));
+    }
+
+    /**
      * <p>
      * This method is necessary, when Mail repositories needs to deal explicitly
      * with retriving Mail attributes as a Serializable
diff --git a/server/container/core/src/test/java/org/apache/james/server/core/MailImplTest.java b/server/container/core/src/test/java/org/apache/james/server/core/MailImplTest.java
index 8dc8635..3e0811e 100644
--- a/server/container/core/src/test/java/org/apache/james/server/core/MailImplTest.java
+++ b/server/container/core/src/test/java/org/apache/james/server/core/MailImplTest.java
@@ -43,7 +43,6 @@ import org.apache.mailet.Mail;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.MailUtil;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import com.github.fge.lambdas.Throwing;
@@ -322,7 +321,6 @@ public class MailImplTest extends ContractMailTest {
             .isEqualToComparingFieldByField(mail);
     }
 
-    @Disabled("JAMES-2665: Throws java.io.NotSerializableException: java.util.Optional")
     @Test
     void mailImplShouldBeSerializableWithOptionalAttribute() throws Exception {
         MailImpl mail = MailImpl.builder()
@@ -344,7 +342,6 @@ public class MailImplTest extends ContractMailTest {
             .isEqualToComparingFieldByField(mail);
     }
 
-    @Disabled("JAMES-2665: Throws java.io.NotSerializableException: java.io.NotSerializableException: org.apache.mailet.AttributeValue")
     @Test
     void mailImplShouldBeSerializableWithCollectionAttribute() throws Exception {
         MailImpl mail = MailImpl.builder()


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