Hi,
this patch makes sure that the UnmodifiableMap.entrySet() result can't
be used to change the wrapped map using toArray() or toArray(Object[]).
It does so by recreating a resulting array using UnmodifiableMapEntry,
which has been extracted from the inner class used as return value in
the iterator method of UnmodifableEntrySet.
However, I find this solution quite bulky and inelegant. If anyone is
thinking of a cleaner way, please shout on me.
Cheers
+Olivier
2006-04-23 Olivier Jolly <[EMAIL PROTECTED]>
* java/util/Collections.java(UnmodifiableMap.UnmodifiableEntrySet.
UnmodifiableMapEntry): New Map.Entry implementation which is immutable.
(UnmodifiableMap.UnmodifiableEntrySet.iterator,
UnmodifiableMap.UnmodifiableEntrySet.toArray,
UnmodifiableMap.UnmodifiableEntrySet.toArray(Object[])): Used
UnmodifiableMapEntry
as part of their return value.
Index: Collections.java
===================================================================
RCS file: /sources/classpath/classpath/java/util/Collections.java,v
retrieving revision 1.39
diff -u -r1.39 Collections.java
--- Collections.java 25 Dec 2005 11:06:38 -0000 1.39
+++ Collections.java 23 Apr 2006 16:46:17 -0000
@@ -4817,6 +4817,87 @@
private static final class UnmodifiableEntrySet extends UnmodifiableSet
implements Serializable
{
+ // Unmodifiable implementation of Map.Entry used as return value for
+ // UnmodifiableEntrySet accessors (iterator, toArray, toArray(Object[]))
+ private static final class UnmodifiableMapEntry
+ implements Map.Entry
+ {
+ private final Entry e;
+
+ private UnmodifiableMapEntry(Entry e)
+ {
+ super();
+ this.e = e;
+ }
+
+ /**
+ * Returns <code>true</code> if the object, o, is also a map entry
+ * with an identical key and value.
+ *
+ * @param o the object to compare.
+ * @return <code>true</code> if o is an equivalent map entry.
+ */
+ public boolean equals(Object o)
+ {
+ return e.equals(o);
+ }
+
+ /**
+ * Returns the key of this map entry.
+ *
+ * @return the key.
+ */
+ public Object getKey()
+ {
+ return e.getKey();
+ }
+
+ /**
+ * Returns the value of this map entry.
+ *
+ * @return the value.
+ */
+ public Object getValue()
+ {
+ return e.getValue();
+ }
+
+ /**
+ * Computes the hash code of this map entry. The computation is
+ * described in the <code>Map</code> interface documentation.
+ *
+ * @return the hash code of this entry.
+ * @see Map#hashCode()
+ */
+ public int hashCode()
+ {
+ return e.hashCode();
+ }
+
+ /**
+ * Blocks the alteration of the value of this map entry. This method
+ * never returns, throwing an exception instead.
+ *
+ * @param value The new value.
+ * @throws UnsupportedOperationException as an unmodifiable map entry
+ * does not support the <code>setValue()</code> operation.
+ */
+ public Object setValue(Object value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns a textual representation of the map entry.
+ *
+ * @return The map entry as a <code>String</code>.
+ */
+ public String toString()
+ {
+ return e.toString();
+ }
+ }
+
/**
* Compatible with JDK 1.4.
*/
@@ -4846,80 +4927,45 @@
public Object next()
{
final Map.Entry e = (Map.Entry) super.next();
- return new Map.Entry()
- {
- /**
- * Returns <code>true</code> if the object, o, is also a map entry with an
- * identical key and value.
- *
- * @param o the object to compare.
- * @return <code>true</code> if o is an equivalent map entry.
- */
- public boolean equals(Object o)
- {
- return e.equals(o);
- }
-
- /**
- * Returns the key of this map entry.
- *
- * @return the key.
- */
- public Object getKey()
- {
- return e.getKey();
- }
+ return new UnmodifiableMapEntry(e);
+ }
+ };
+ }
- /**
- * Returns the value of this map entry.
- *
- * @return the value.
- */
- public Object getValue()
- {
- return e.getValue();
- }
+ // The array returned is an array of UnmodifiableMapEntry instead of
+ // Map.Entry
+ public Object[] toArray()
+ {
+ Object[] mapEntryResult = super.toArray();
+ UnmodifiableMapEntry result[] = null;
- /**
- * Computes the hash code of this map entry.
- * The computation is described in the <code>Map</code>
- * interface documentation.
- *
- * @return the hash code of this entry.
- * @see Map#hashCode()
- */
- public int hashCode()
+ if (mapEntryResult != null)
+ {
+ result = new UnmodifiableMapEntry[mapEntryResult.length];
+ for (int i = 0; i < mapEntryResult.length; i++)
{
- return e.hashCode();
+ result[i] = new UnmodifiableMapEntry((Entry) mapEntryResult[i]);
}
+ }
+ return result;
+ }
- /**
- * Blocks the alteration of the value of this map entry.
- * This method never returns, throwing an exception instead.
- *
- * @param value The new value.
- * @throws UnsupportedOperationException as an unmodifiable
- * map entry does not support the <code>setValue()</code>
- * operation.
- */
- public Object setValue(Object value)
- {
- throw new UnsupportedOperationException();
- }
+ // The array returned is an array of UnmodifiableMapEntry instead of
+ // Map.Entry
+ public Object[] toArray(Object[] array)
+ {
+ super.toArray(array);
- /**
- * Returns a textual representation of the map entry.
- *
- * @return The map entry as a <code>String</code>.
- */
- public String toString()
+ if (array != null)
+ {
+ for (int i = 0; i < array.length; i++)
{
- return e.toString();
+ array[i] = new UnmodifiableMapEntry((Entry) array[i]);
}
- };
}
- };
+ return array;
}
+
} // class UnmodifiableEntrySet
/**