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
 
     /**

Reply via email to