9

Following code is giving me common.apex.runtime.impl.ExecutionException

String jsonText = '{"Data": {"attributes": {"type": "Contact"},"Id": "0036100000JUXKkAAP","Description": "","LastName": "Testing"}}';
Map<String, Object> cObjMap = (Map<String, Object>) JSON.deserializeUntyped(jsonText); String cObjJson = JSON.serialize(cObjMap.get('Data')); SObject customObject = (SObject)JSON.deserialize(cObjJson, SObject.class);

The problem is in fact that Map<String,Object> gets re-ordered during serialize/deserialize and "attributes" node is moved to last position.

That causes deserialize to SObject to fail as it requires "attributes" to be in first position, just like in jsonText example.

I know that defining separate class that would map all key/value pairs from JSON and deserializing to it would work, but I don't have exact structure as keys might vary.

Do you have any idea how to accomplish this?

Thank You!

  • I'm pretty sure that the order won't get switched - maps are deterministic now. Can you confirm that "attributes" ends up at the end? – Caspar Harmer Jan 21 '16 at 23:13
  • 2
    Hmm, it does seem to mix it up, actually - going into the map. However, execute anon has no problem with this. Where are you seeing the error? – Caspar Harmer Jan 21 '16 at 23:37
  • What type is cObjMap.get('Data')? If you try and cast it to sObject you get the error: Invalid conversion from runtime type Map<String,ANY> to SObject. So at best it is Map<String, Object>. Yes you can serialize it, but I don't think you can deserialize it as an sObject class instance. Nor can you deserialize a Map<String, Object> as Object isn't supported. – Daniel Ballinger Jan 22 '16 at 1:30
11

Well, this is how you can do it. Apex is made through Java!

String jsonText = '{"Data": {"attributes": {"type": "Contact","url":"/services/data/v35.0/sobjects/Contact/0036100000JUXKkAAP"},"Id": "0036100000JUXKkAAP","Description": "","LastName": "Testing"}}';

Map<String, Object> cObjMap = (Map<String, Object>) JSON.deserializeUntyped(jsonText);
String cObjJson = JSON.serialize(cObjMap.get('Data'));
// Why again :(
Map<String, Object> cObjMapFurious = (Map<String, Object>) JSON.deserializeUntyped(cObjJson);
String cObjJsonDrunk = JSON.serialize(cObjMapFurious);
try
{
    SObject customObject = (SObject)JSON.deserialize(cObjJsonDrunk, Sobject.class);
    System.debug(' Accomplished: '+customObject);
}
catch(Exception ex)
{
    System.debug(' @@@@@ Don\'t visible '+ex.getMessage());
}
  • Thanks Ashwani, it works! Anyway, this looks more like a workaround for something that should be supported initially. I assume that your logic was to deserialize/serialize once again so the key-value pairs gets reverted back to starting state, with 'attributes' at first position. – Nikola J. Jan 22 '16 at 10:30
  • @NikolaJ. We are doing this for years! Thats the object serialization algorithm behavior used by Salesforce Apex :) They day it will be modified , no impact would occur in this code. – Ashwani Jan 22 '16 at 10:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.