[SalesForce] the correct JSON to deserialize a map of sObjects

I'm trying to store a map of sObjects in a static resource. I want to be able to store default values for test setup methods. I was able to get it working with the following JSON in the static resource:

{ 
"Account" : "{\"attributes\":{\"type\":\"Account\"},\"BillingCity\" : \"testCity\"}",
"Opportunity" : "{\"attributes\":{\"type\":\"Opportunity\"},\"Name\" : \"testOpp\"}"
}

and here's the code:

String strJson = [SELECT body, name from StaticResource where Name =: myresource].body.toString();
mapJsonObjects = (Map<String, object>)JSON.deserializeUntyped(strJson);
Account objAccount = (Account) JSON.deserialize((String) mapJsonObjects.get('Account'),Sobject.Class);

The JSON I would actually like to have in the static resource is:

{
   "Account":{
      "attributes":{
         "type":"Account"
      },
      "BillingCity":"testCity"
   }
   ...
}

but there is no way to deserialize this into an sObject as far as I can tell.

Best Answer

You need to use the typed deserialize method as follows...

String jsondata = '{ "Account" : { "attributes":{"type":"Account"},"BillingCity" : "testCity"}, "Opportunity" : { "attributes":{"type":"Opportunity"},"Name" : "testOpp"}}';
Map<String, SObject> mapJsonObjects = (Map<String, SObject>)
    JSON.deserialize(jsondata, Map<String, SObject>.class);
Account objAccount = (Account) mapJsonObjects.get('Account');
System.debug('Account BillingCity is ' + objAccount.BillingCity);
Opportunity objOpportunity = (Opportunity) mapJsonObjects.get('Opportunity');
System.debug('Opportunity Name is ' + objOpportunity.Name);

The trick is using the .class property to get the class type of the typed Map.

Map<String, SObject>.class 

Results in

DEBUG|Account BillingCity is testCity

DEBUG|Opportunity Name is testOpp