Why Mutating SObject Keys in Maps Can Cause Null Values in Apex.

In Apex, a Map is an essential data structure that stores key-value pairs internally by hash codes. When retrieving a value using the get method, the Map uses the hash code to determine the correct area in storage to search for the value. However, if you modify the hash code of the key, the value cannot be found in the original bucket, resulting in lost data within the Map.

Here’s an example of how the Map stores data by hash codes:

{

  “12345” => [value1],

  “23456” => [value2],

  “34567” => [value3, value4]

}

When retrieving a value using the get method, the Map searches for the hash code of the key and then iterates through the corresponding bucket to find the value. Here’s a simplified version of the code:

List<Object> valuesInBucket = this.storage[hashCode];

for (Object value : valuesInBucket) {

  if (value.hashCode.equals(hashCode) && value.equals(key)) {

      return value;

  }

}

return null;As you can see, the hash code is essential for locating the correct area in storage. However, modifying the hash code of the key can cause the Map to be unable to find the value in the original bucket, leading to lost data within the internal structure of the Map.

Note that the values are still in the map, they’re just unaccessible via normal methods, including keySet(), values(), get(), and put().

Example: 

Map<Case,List<Case>> parentChildMap = new Map<Case,List<Case>>();
 List<Case> parentCases = new List<Case>();
        for(CaseWrapper wrap: caseWrapperList){
            parentChildMap.put(wrap.parentCase,wrap.childCases);
        }
        System.debug('map before insert==>'+parentChildMap);
        if(parentChildMap.keySet() !=null){
           parentCases.addAll(parentChildMap.keySet());
           insert parentCases ; 
           System.debug('map after insert==>'+parentChildMap);
        }

Workaround:

You can use JSON.serialize() method to get the values from a Map in Apex. The JSON.serialize() method converts an Apex object into its equivalent JSON format.

Debugs:

map before insert==> {Case:{Subject=1}=(Case:{Subject=1.1}), Case:{Subject=2}=(Case:{Subject=2.2})}

map after insert==> {Case:{Subject=1, Id=5000K00002cxQsWQAU}=null, Case:{Subject=2, Id=5000K00002cxQsXQAU}=null}

map after serialization==> {“Case:{Subject=2, Id=5000K00002cxQybQAE}”:[{“attributes”:{“type”:”Case”},”Subject”:”2.2″}],”Case:{Subject=1, Id=5000K00002cxQyaQAE}”:[{“attributes”:{“type”:”Case”},”Subject”:”1.1″}]}

Article Information