The reason I asked to see all of the code is because sometimes when working with large sets of code, passing variables in and out of methods can have unexpected side effects. Is it possible you are having an issue with passing variables into and back out of methods? Apex uses pass by value for primitive data types (such as a Map or String). If at any point you set jsonAsMap = <something>
you could be running into this issue. Here is a perfect example from the reference:
We’ll illustrate this with some code samples. But first, let’s step
back and define these terms.
“Pass by value” means when a method is called, a second copy of the parameter variable is made in memory, and this copy is passed to
the method as a parameter. This copy can be modified in the method,
but the original variable in the caller is unchanged, and the changes
to the copy are lost upon return.
“Pass by reference” means when a method is called, that actual variable is passed to the method.
As described in the new developer’s guide text, Apex is not passing
anything by reference. It is passing the reference (i.e., the memory
address) by value, which allows the developer to change fields on the
object and call methods (like list.add()) on the object.
Let’s illustrate with some code. First, an example where we get
apparent pass-by-reference behavior:
List fillMe = new List();
PassByWhatNow.reference(fillMe);
System.assertEquals(fillMe.size(),5); //five items, as expected
/* calls this method
public static void reference(List m) {
List la = [select id, name from Account limit 5];
for (Account a : la) m.add(a);
}
*/
In this example, the parameter passed to the function, behind the
scenes, is a pointer to the fillMe collection, passed by value. That
is to say, we took the memory address and copied it – but it is the
same memory address number in both places. When the add() function is
called on the copy, that same memory location is modified by adding
the specified items to the list. So when we return to the calling
program, the modifications made in the static function are visible.
So far, so good.
Now let’s look at an example where things break down.
List createMe = new List();
PassByWhatNow.referenceNew(createMe);
System.assertEquals(createMe.size(),0); //nothing in the list
/* calls this method
public static void referenceNew(List m) {
m = new List([select id, name from Account limit 5]);
}
*/
Again, we pass a copy of the list’s memory address to the function.
However, this time, the function is initializing the variable anew.
When the “new” function is called, new memory is allocated. This is
the big difference.
The copy of the memory address passed as a parameter is
overwritten with the address of the newly allocated memory. The
original, however, is not overwritten. That change in address is not known to the caller!
Any subsequent actions done in the method are on that new memory
address rather than the original object address. These changes,
including the addition of the Accounts to the list, can not be
available to the caller, since it only knows of the original address.
No actions were done on this address; the list on the caller is
therefore unchanged, still empty as it was when the call was made.
While Apex usually does behave as if we’re passing variables by
reference, we’re not truly passing by reference. There are a few
situations where the distinction is important, as detailed here. Now
you know more, and you are a stronger developer.
Best Answer
tl;dr
This is just an artifact of the data you're using and how you've chosen to write it to the debug log.
longer version
As the comments have noted, the Map collection type in Apex behaves pretty much exactly the same as a Map/Dictionary does in any other language (a language being statically vs dynamically typed really doesn't matter here).
.put()
into a map, and that key doesn't yet exist, the key and value are added to the map.put()
into a map, and the key you use does exist, the value stored by the key is overwrittenAlso as noted in the comments,
System.debug()
only provides limited output. It'll stop printing data to the debug log after some ill-defined point, truncating it unceremoneously. Under certain circumstances, it can appear that data is missing or being overwritten, but that's not what's actually happening. The data is still there, you just can't view all of it at once using a singleSystem.debug()
.If you want to make sure that you see at least a little bit of data for every item in a collection (a List, Set, or Map), then you should loop over the collection one item at a time, and
System.debug()
individual items.Following your example, that'd be
Note that while you will see some data for each map key, the serialized data for a single SObject instance coming from a Trigger Context Variable is still quite long and liable to itself be truncated. Even moreso considering you're trying to serialize the entirety of
Trigger.new
andTrigger.old
instead of a single record from each.In the end, if you want to guarantee that certain data is output to the log, you should use individual
System.debug()
calls. Iterate over collections, and debug every field you're interested in.