From 7da59277e59a7a6fdf559e422aa07bb89af97404 Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Mon, 15 Jul 2013 08:54:44 -0600 Subject: [PATCH 1/3] This solves a class cast exception from a call to .values() from an UnmodifiableMap. It also solves an issue where you can modify an unmodifiable collection through the Iterator or ListIterator (depending on the structure type). --- classpath/java/util/Collections.java | 138 ++++++++++++++++++++------- 1 file changed, 105 insertions(+), 33 deletions(-) diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 788e083f5e..4a950e3b11 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -168,7 +168,7 @@ public class Collections { } public Iterator iterator() { - return new SynchronizedIterator(lock, collection.iterator()); + return new SynchronizedIterator(lock, collection.iterator()); } public boolean containsAll(Collection c) { @@ -355,7 +355,7 @@ public class Collections { } public Iterator iterator() { - return inner.iterator(); + return new UnmodifiableIterator(inner.iterator()); } public int indexOf(Object value) { @@ -371,11 +371,11 @@ public class Collections { } public ListIterator listIterator(int index) { - return inner.listIterator(index); + return new UnmodifiableListIterator(inner.listIterator(index)); } public ListIterator listIterator() { - return inner.listIterator(); + return new UnmodifiableListIterator(inner.listIterator()); } public int size() { @@ -471,64 +471,136 @@ public class Collections { } public Collection values() { - return unmodifiableSet((Set)inner.values()); + return unmodifiableCollection(inner.values()); } } - - static class UnmodifiableSet implements Set { - private Set inner; - - UnmodifiableSet(Set inner) { + + static class UnmodifiableIterator implements Iterator { + private static final String EXCEPTION_MESSAGE = "not supported in unmodifiable collection"; + + private final Iterator inner; + + UnmodifiableIterator(Iterator inner) { this.inner = inner; } - - public boolean add(T element) { - throw new UnsupportedOperationException("not supported"); + + @Override + public T next() { + return inner.next(); } - public boolean addAll(Collection collection) { - throw new UnsupportedOperationException("not supported"); + @Override + public boolean hasNext() { + return inner.hasNext(); } - public void clear() { - throw new UnsupportedOperationException("not supported"); + @Override + public void remove() { + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + } + + + static class UnmodifiableListIterator extends UnmodifiableIterator + implements ListIterator { + private final ListIterator innerListIterator; + + UnmodifiableListIterator(ListIterator listIterator) { + super(listIterator); + + this.innerListIterator = listIterator; } - public boolean contains(Object element) { - return inner.contains(element); + @Override + public boolean hasPrevious() { + return innerListIterator.hasPrevious(); } - public boolean isEmpty() { - return inner.isEmpty(); + @Override + public T previous() { + return innerListIterator.previous(); } - + } + + static class UnmodifiableCollection implements Collection { + private static final String EXCEPTION_MESSAGE = "not supported in unmodifiable collection"; + + private final Collection inner; + + UnmodifiableCollection(Collection inner) { + this.inner = inner; + } + + @Override public Iterator iterator() { - return inner.iterator(); - } - - public boolean remove(Object element) { - throw new UnsupportedOperationException("not supported"); + return new UnmodifiableIterator(inner.iterator()); } + @Override public int size() { return inner.size(); } - public Object[] toArray() { - return toArray(new Object[size()]); + @Override + public boolean isEmpty() { + return inner.isEmpty(); } - public S[] toArray(S[] array) { - return inner.toArray(array); + @Override + public boolean contains(Object element) { + return inner.contains(element); } + @Override public boolean containsAll(Collection c) { return inner.containsAll(c); } + @Override + public boolean add(T element) { + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override + public boolean addAll(Collection collection) { + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override + public boolean remove(Object element) { + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override public boolean removeAll(Collection c) { - throw new UnsupportedOperationException("not supported"); - } + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override + public Object[] toArray() { + return inner.toArray(); + } + + @Override + public S[] toArray(S[] array) { + return inner.toArray(array); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + } + + public static UnmodifiableCollection unmodifiableCollection(Collection collection) { + return new UnmodifiableCollection(collection); + } + + static class UnmodifiableSet extends UnmodifiableCollection + implements Set { + UnmodifiableSet(Set inner) { + super(inner); + } } public static Set unmodifiableSet(Set hs) { From bfe7b9110a735892c0a97826d4fa06b7feb39fc4 Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Wed, 17 Jul 2013 11:52:48 -0600 Subject: [PATCH 2/3] Removed exception message based on Josh's recommendation --- classpath/java/util/Collections.java | 42 +++++++++++++--------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 4a950e3b11..c57c190a06 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -335,23 +335,23 @@ public class Collections { } public T set(int index, T value) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public T remove(int index) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public boolean remove(Object o) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public boolean add(T element) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public void add(int index, T element) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public Iterator iterator() { @@ -387,7 +387,7 @@ public class Collections { } public boolean addAll(Collection collection) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public Object[] toArray() { @@ -399,15 +399,15 @@ public class Collections { } public void clear() { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public boolean removeAll(Collection c) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public boolean addAll(int startIndex, Collection c) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public boolean containsAll(Collection c) { @@ -427,7 +427,7 @@ public class Collections { } public void clear() { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public boolean containsKey(Object key) { @@ -455,15 +455,15 @@ public class Collections { } public V put(K key, V value) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public void putAll(Map t) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public V remove(Object key) { - throw new UnsupportedOperationException("not supported"); + throw new UnsupportedOperationException(); } public int size() { @@ -476,8 +476,6 @@ public class Collections { } static class UnmodifiableIterator implements Iterator { - private static final String EXCEPTION_MESSAGE = "not supported in unmodifiable collection"; - private final Iterator inner; UnmodifiableIterator(Iterator inner) { @@ -496,7 +494,7 @@ public class Collections { @Override public void remove() { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + throw new UnsupportedOperationException(); } } @@ -523,8 +521,6 @@ public class Collections { } static class UnmodifiableCollection implements Collection { - private static final String EXCEPTION_MESSAGE = "not supported in unmodifiable collection"; - private final Collection inner; UnmodifiableCollection(Collection inner) { @@ -558,22 +554,22 @@ public class Collections { @Override public boolean add(T element) { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + throw new UnsupportedOperationException(); } @Override public boolean addAll(Collection collection) { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + throw new UnsupportedOperationException(); } @Override public boolean remove(Object element) { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection c) { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + throw new UnsupportedOperationException(); } @Override @@ -588,7 +584,7 @@ public class Collections { @Override public void clear() { - throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + throw new UnsupportedOperationException(); } } From 2e921b803da0a2e9835be00f976fd306ab70fd98 Mon Sep 17 00:00:00 2001 From: Mike Jensen Date: Wed, 17 Jul 2013 11:53:35 -0600 Subject: [PATCH 3/3] Added a simple test to show the original issue --- test/Collections.java | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/Collections.java diff --git a/test/Collections.java b/test/Collections.java new file mode 100644 index 0000000000..d175318a4f --- /dev/null +++ b/test/Collections.java @@ -0,0 +1,26 @@ +import java.util.Collection; +import java.util.Map; + +public class Collections { + public static void main(String[] args) { + testValues(); + } + + @SuppressWarnings("rawtypes") + private static void testValues() { + Map testMap = java.util.Collections.unmodifiableMap(java.util.Collections.emptyMap()); + Collection values = testMap.values(); + + if (values == null) { + throw new NullPointerException(); + } + + try { + values.clear(); + + throw new IllegalStateException("Object should be immutable, exception should have thrown"); + } catch (Exception e) { + // expected + } + } +}