8185830: ConcurrentSkipListSet.clone() fails with UnsupportedOperationException
authordl
Wed, 09 Aug 2017 17:30:51 -0700
changeset 46145 1a5028372b29
parent 46144 cfb94413b9a4
child 46146 b3e220a04d3f
8185830: ConcurrentSkipListSet.clone() fails with UnsupportedOperationException Reviewed-by: martin, psandoz, plevart
jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java
jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Wed Aug 09 15:39:50 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Wed Aug 09 17:30:51 2017 -0700
@@ -35,8 +35,7 @@
 
 package java.util.concurrent;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
 import java.util.AbstractSet;
 import java.util.Collection;
 import java.util.Collections;
@@ -506,19 +505,21 @@
             : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
     }
 
-    // Support for resetting map in clone
+    /** Initializes map field; for use in clone. */
     private void setMap(ConcurrentNavigableMap<E,Object> map) {
-        MAP.setVolatile(this, map);
-    }
-
-    // VarHandle mechanics
-    private static final VarHandle MAP;
-    static {
+        Field mapField = java.security.AccessController.doPrivileged(
+            (java.security.PrivilegedAction<Field>) () -> {
+                try {
+                    Field f = ConcurrentSkipListSet.class
+                        .getDeclaredField("m");
+                    f.setAccessible(true);
+                    return f;
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }});
         try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            MAP = l.findVarHandle(ConcurrentSkipListSet.class, "m",
-                                  ConcurrentNavigableMap.class);
-        } catch (ReflectiveOperationException e) {
+            mapField.set(this, map);
+        } catch (IllegalAccessException e) {
             throw new Error(e);
         }
     }
--- a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java	Wed Aug 09 15:39:50 2017 -0700
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java	Wed Aug 09 17:30:51 2017 -0700
@@ -553,7 +553,25 @@
     }
 
     /**
-     * A deserialized serialized set has same elements
+     * A cloned set equals original
+     */
+    public void testClone() {
+        ConcurrentSkipListSet x = populatedSet(SIZE);
+        ConcurrentSkipListSet y = x.clone();
+
+        assertNotSame(x, y);
+        assertEquals(x.size(), y.size());
+        assertEquals(x, y);
+        assertEquals(y, x);
+        while (!x.isEmpty()) {
+            assertFalse(y.isEmpty());
+            assertEquals(x.pollFirst(), y.pollFirst());
+        }
+        assertTrue(y.isEmpty());
+    }
+
+    /**
+     * A deserialized/reserialized set equals original
      */
     public void testSerialization() throws Exception {
         NavigableSet x = populatedSet(SIZE);