8142924: ES6 symbols created with Symbol.for should deserialize to canonical instances
authorattila
Fri, 13 Nov 2015 16:21:22 +0100
changeset 33884 e534af80b09b
parent 33883 5b2c96df2e1e
child 33887 eada6f25df36
8142924: ES6 symbols created with Symbol.for should deserialize to canonical instances Reviewed-by: hannesw, lagergren, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Symbol.java
nashorn/test/src/jdk/nashorn/internal/runtime/test/JDK_8142924_Test.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Symbol.java	Thu Nov 12 14:14:37 2015 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Symbol.java	Fri Nov 13 16:21:22 2015 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.runtime;
 
 import java.io.Serializable;
+import jdk.nashorn.internal.objects.NativeSymbol;
 
 /**
  * This class represents a unique, non-String Object property key as defined in ECMAScript 6.
@@ -56,4 +57,29 @@
     public final String getName() {
         return name;
     }
+
+    private Object writeReplace() {
+        // If this symbol is a globally registered one, replace it with a
+        // GlobalSymbol in serialized stream.
+        return NativeSymbol.keyFor(null, this) == name ? new GlobalSymbol(name) : this;
+    }
+
+    /**
+     * Represents a globally registered (with NativeSymbol._for) symbol in the
+     * serialized stream. Upon deserialization, it resolves to the globally
+     * registered symbol.
+     */
+    private static class GlobalSymbol implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private final String name;
+
+        GlobalSymbol(final String name) {
+            this.name = name;
+        }
+
+        private Object readResolve() {
+            return NativeSymbol._for(null, name);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/test/JDK_8142924_Test.java	Fri Nov 13 16:21:22 2015 +0100
@@ -0,0 +1,43 @@
+package jdk.nashorn.internal.runtime.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import jdk.nashorn.internal.objects.NativeSymbol;
+import jdk.nashorn.internal.runtime.Symbol;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @bug 8142924
+ * @summary ES6 symbols created with Symbol.for should deserialize to canonical instances
+ */
+@SuppressWarnings("javadoc")
+public class JDK_8142924_Test {
+    @Test
+    public static void testNonGlobal() throws Exception {
+        final String name = "testNonGlobal";
+        final Symbol symbol1 = (Symbol)NativeSymbol.constructor(false, null, name);
+        final Symbol symbol2 = serializeRoundTrip(symbol1);
+        Assert.assertNotSame(symbol1, symbol2);
+        Assert.assertEquals(symbol2.getName(), name);
+        Assert.assertNotSame(symbol1, NativeSymbol._for(null, name));
+    }
+
+    @Test
+    public static void testGlobal() throws Exception {
+        final String name = "testGlobal";
+        final Symbol symbol1 = (Symbol)NativeSymbol._for(null, name);
+        final Symbol symbol2 = serializeRoundTrip(symbol1);
+        Assert.assertSame(symbol1, symbol2);
+    }
+
+    private static Symbol serializeRoundTrip(final Symbol symbol) throws Exception {
+        final ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        final ObjectOutputStream out = new ObjectOutputStream(bout);
+        out.writeObject(symbol);
+        out.close();
+        return (Symbol) new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray())).readObject();
+    }
+}