changeset 17458:2b13d1849a95

8185830: ConcurrentSkipListSet.clone() fails with UnsupportedOperationException Reviewed-by: martin, psandoz, plevart
author dl
date Wed, 09 Aug 2017 17:30:51 -0700
parents cd6d176690e7
children 645defa9e6e3
files src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java
diffstat 2 files changed, 33 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Mon Aug 14 17:19:31 2017 -0700
+++ b/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;
@@ -507,19 +506,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/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java	Mon Aug 14 17:19:31 2017 -0700
+++ b/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);