8185830: ConcurrentSkipListSet.clone() fails with UnsupportedOperationException
Reviewed-by: martin, psandoz, plevart
--- 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);