# HG changeset patch # User dl # Date 1502325051 25200 # Node ID 1a5028372b29c75431a26a94d37d8f8a9560b9d1 # Parent cfb94413b9a4ff6c33f7ad07a5eda6d1229f5521 8185830: ConcurrentSkipListSet.clone() fails with UnsupportedOperationException Reviewed-by: martin, psandoz, plevart diff -r cfb94413b9a4 -r 1a5028372b29 jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.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)m).new SubMapKeyIterator(); } - // Support for resetting map in clone + /** Initializes map field; for use in clone. */ private void setMap(ConcurrentNavigableMap map) { - MAP.setVolatile(this, map); - } - - // VarHandle mechanics - private static final VarHandle MAP; - static { + Field mapField = java.security.AccessController.doPrivileged( + (java.security.PrivilegedAction) () -> { + 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); } } diff -r cfb94413b9a4 -r 1a5028372b29 jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java --- 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);