I have a Map<String,Object>() which I am trying to store in a text field for a subsequent asynchronous operation. My idea was for the following async operation to query for this map and re-use it.

I tried using JSON.serialize() for this purpose like so:

MyObj__c.MyField__c = JSON.serialize(myMap);

Then the async job would pick up the value of MyField__c and deserialize it like so:

Map<String, Object> myRestoredMap = (Map<String, Object>) JSON.deserializeUntyped(myObj.MyField__c);

However I found some discrepancies when system.debugging myMap and myRestoredMap.

Portion of myMap when system.debugged:

...detail=Account:{HealthCloudGA__SourceSystemId__c=123, Name=SomeName, RecordTypeId=012Ot0000002NR5IAM}...

Same portion but in myRestoredMap:

...detail={HealthCloudGA__SourceSystemId__c=123, Name=SomeName, > RecordTypeId=012Ot0000002NR5IAM, attributes={type=Account}...

I can see that serializing the map adds "attributes={type=Account}". How can I preserve the original state of the map?

  • 2
    Serializing anything that is/contains an SObject will cause that additional metadata to appear. It shouldn't present any trouble when you go to deserialize untyped (nor if you deserialize as a Map<Id, SObject>, which would probably end up being easier/less typing).
    – Derek F
    Oct 30, 2023 at 20:11

1 Answer 1


JSON doesn't know about Apex data types. The JSON library in Apex, therefore, has to be told if you want to use a specific DTO-like object. For example, if all the attributes were sObject entries, you could JSON.deserialize(someString, Map<String, sObject>.class) to get a map that contained records. In this case, the attributes property would be consumed to coerce each value into an sObject of the appropriate concrete type. In fact, if I were going to do what you're trying to do, I would indeed wrap the entire record into a map.

record.MyField__c = JSON.serialize(new Map<String, sObject> { 'record' => record });

Then for deserialization, I can use a helper class:

class RecordWrapper {
  sObject record;


RecordWrapper wrapper = (RecordWrapper)JSON.deserialize(record.MyField__c, RecordWrapper.class);

This will perfectly rehydrate all of your data in the asynchronous process.

Alternatively, you may want to create a wrapper that you serialize with, rather than using myMap. When you use a generic map, you get the default generic behavior, which may also be contributing to your problem. I strong recommend using a class to serialize/deserialize your data for repeatable results.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .