Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8217972

IdentityHashMap.entrySet().toArray() doesn't return actual entries

XMLWordPrintable

      A DESCRIPTION OF THE PROBLEM :
      Introduced by the fix for JDK-4485486 / JDK-6197726, though probably did not work properly before either because these bugs blocked it.

      The toArray() / toArray(T[]) methods of the Set returned by IdentityHashMap.entrySet() break the contract of the documentation of this method:
      "containing all of the elements in this set"
      with emphasis on "elements in this set"

      toArray() actually returns different Entry objects, which are not even a valid substitute for the proper Entry objects because:
      - They have no relation to the map anymore, calling setValue() has no effect
      - They compare the stored key and value using `equals` instead of comparing references

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      import java.util.IdentityHashMap;
      import java.util.Map.Entry;
      import java.util.Set;

      public class MapTest {
          public static void main(String[] args) {
              IdentityHashMap<String, String> identityHashMap = new IdentityHashMap<>();
              final String key = "key";
              final String oldValue = "oldValue";
              final String newValue = "newValue";
              
              identityHashMap.put(key, oldValue);
              Set<Entry<String, String>> entrySet = identityHashMap.entrySet();
              
              @SuppressWarnings("unchecked")
              Entry<String, String> arrayEntry = (Entry<String, String>) entrySet.toArray()[0];
              // Expecting that this changes value in map
              arrayEntry.setValue(newValue);
              // -> !! Did not change value
              System.out.println("Expecting true: " + (identityHashMap.get(key) == newValue));
              
              Entry<String, String> iteratorEntry = entrySet.iterator().next();
              // Expecting that this changes value in map
              iteratorEntry.setValue(newValue);
              // -> Changed value
              System.out.println("Expecting true: " + (identityHashMap.get(key) == newValue));
              
              /*
               * Set.toArray() contract is violated because here it does not return
               * "all of the elements in this set", it actually returns different elements
               */
          }
      }



      FREQUENCY : always


            smarks Stuart Marks
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: