From db020f4567034b5186b14e46906a7e147356ec89 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 9 Oct 2015 23:44:47 +0300 Subject: [PATCH] Do not modify state while serializing (#19090) Serializing an object should never modify its internal state. It should be possible to serialize an object multiple times and get the same result Change-Id: I79502274179a646f8b0cd8d1fc4cbfd84867299d --- .../vaadin/server/ClientMethodInvocation.java | 9 ++++-- .../server/ClientMethodSerializationTest.java | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/server/src/com/vaadin/server/ClientMethodInvocation.java b/server/src/com/vaadin/server/ClientMethodInvocation.java index 33b88a168b..77849c83df 100644 --- a/server/src/com/vaadin/server/ClientMethodInvocation.java +++ b/server/src/com/vaadin/server/ClientMethodInvocation.java @@ -38,7 +38,7 @@ public class ClientMethodInvocation implements Serializable, private final ClientConnector connector; private final String interfaceName; private final String methodName; - private final Object[] parameters; + private transient Object[] parameters; private Type[] parameterTypes; // used for sorting calls between different connectors in the same UI @@ -102,6 +102,7 @@ public class ClientMethodInvocation implements Serializable, // that is Serializable. On deserialization (readObject-method below) // the process should be reversed. + Object[] serializedParameters = new Object[parameters.length]; // Easy way for implementing serialization & deserialization is by // writing/parsing the object's content as string. for (int i = 0; i < parameterTypes.length; i++) { @@ -109,12 +110,15 @@ public class ClientMethodInvocation implements Serializable, if (type instanceof Class) { Class clazz = (Class) type; if (JsonArray.class.isAssignableFrom(clazz)) { - parameters[i] = JsonUtil + serializedParameters[i] = JsonUtil .stringify((JsonArray) parameters[i]); + } else { + serializedParameters[i] = parameters[i]; } } } stream.defaultWriteObject(); + stream.writeObject(serializedParameters); } private void readObject(ObjectInputStream stream) throws IOException, @@ -122,6 +126,7 @@ public class ClientMethodInvocation implements Serializable, // Reverses the serialization done in writeObject. Basically just // parsing the serialized type back to the non-serializable type. stream.defaultReadObject(); + parameters = (Object[]) stream.readObject(); for (int i = 0; i < parameterTypes.length; i++) { Type type = parameterTypes[i]; if (type instanceof Class) { diff --git a/server/tests/src/com/vaadin/tests/server/ClientMethodSerializationTest.java b/server/tests/src/com/vaadin/tests/server/ClientMethodSerializationTest.java index da6bc76a0f..1ec19724d8 100644 --- a/server/tests/src/com/vaadin/tests/server/ClientMethodSerializationTest.java +++ b/server/tests/src/com/vaadin/tests/server/ClientMethodSerializationTest.java @@ -24,13 +24,16 @@ import java.lang.reflect.Method; import junit.framework.TestCase; +import com.vaadin.server.ClientConnector; import com.vaadin.server.ClientMethodInvocation; import com.vaadin.server.JavaScriptCallbackHelper; +import com.vaadin.server.JsonCodec; import com.vaadin.ui.JavaScript.JavaScriptCallbackRpc; import com.vaadin.util.ReflectTools; import elemental.json.Json; import elemental.json.JsonArray; +import elemental.json.JsonValue; import elemental.json.impl.JsonUtil; public class ClientMethodSerializationTest extends TestCase { @@ -112,4 +115,31 @@ public class ClientMethodSerializationTest extends TestCase { return output; } + public void testSerializeTwice() { + String name = "javascriptFunctionName"; + String[] arguments = { "1", "2", "3" }; + JsonArray args = (JsonArray) JsonCodec.encode(arguments, null, + Object[].class, null).getEncodedValue(); + ClientConnector connector = null; + + ClientMethodInvocation original = new ClientMethodInvocation(connector, + "interfaceName", JAVASCRIPT_CALLBACK_METHOD, new Object[] { + name, args }); + + ClientMethodInvocation copy = (ClientMethodInvocation) serializeAndDeserialize(original); + assertEquals(copy.getMethodName(), original.getMethodName()); + assertEquals(copy.getParameters().length, + original.getParameters().length); + for (int i = 0; i < copy.getParameters().length; i++) { + Object originalParameter = original.getParameters()[i]; + Object copyParameter = copy.getParameters()[i]; + if (originalParameter instanceof JsonValue) { + assertEquals(((JsonValue) originalParameter).toJson(), + ((JsonValue) copyParameter).toJson()); + } else { + assertEquals(originalParameter, copyParameter); + } + } + } + } -- 2.39.5