0

I am trying to dynamically deserialize a jsonstring (fieldmaplevels wil also be in custom metadata settings) but get the error:

Error: Invalid conversion from runtime type List to Map<String,ANY>

this is at line:

Map<String, Object> fieldMapLevel_0 = (Map<String, Object>)fieldMap.get('Accts');

I also tried:

 Map<String, Object> fieldMapLevel_0 = new Map<String, Object>(fieldMap.get('Accts'));

But get : expected a Map with the same key and value types, or a valid SObject List

Apex

public  with sharing class DynamicJSON{
    public Map<String, Object> fieldMap;
    public static void DynamicJSONmethod()
    {
        sObject newSobject;
        List<sObject> sObjectList;  
        String jsonPayLoad = '{"Accts":[{"Name":"ABC","Exp":25,"Languages":[{"Name":"Apex","version": []},{"Name":"Java","versions":[{"version":1.8,"certification":true,"placeholder":{"target":"reached"}}]}]}]}';
        Map<String, Object> fieldMap = (Map<String, Object>)JSON.deserializeUntyped(jsonPayLoad);
        List<Data_Maps__mdt> mappings = [SELECT QualifiedApiName, label, Object__c , JSON_Object__c,sObjectApiNameLevel_0__c,  sObjectApiNameLevel_1__c,sObjectApiNameLevel_2__c,sObjectApiNameLevel_3__c,
                                         sObjectApiNameLevel_4__c FROM Data_Maps__mdt];
        //level-0
        if(mappings[0].sObjectApiNameLevel_0__c != null) {   
            sobject newSobjLevel_0 = (sObject)Type.forName('Schema',mappings[0].sObjectApiNameLevel_0__c).newInstance();//Account  
            Map<String, Object> fieldMapLevel_0 = (Map<String, Object>)fieldMap.get('Accts');
            GetSobjectFields(newSobjLevel_0, fieldMapLevel_0);
            //level-1
            if(mappings[1].sObjectApiNameLevel_1__c != null) { 
                sobject newSobjLevel_1 = (sObject)Type.forName('Schema',mappings[1].sObjectApiNameLevel_1__c).newInstance();//Languages__c 
                Map<String, Object> fieldMapLevel_1 = (Map<String, Object>)fieldMap.get('Languages');
                GetSobjectFields(newSobjLevel_1, fieldMapLevel_1);
                //level-2
                if(mappings[2].sObjectApiNameLevel_2__c != null) { 
                    sobject newSobjLevel_2 = (sObject)Type.forName('Schema',mappings[0].sObjectApiNameLevel_2__c).newInstance();//versions__c 
                    Map<String, Object> fieldMapLevel_2 = (Map<String, Object>)fieldMap.get('versions');
                    GetSobjectFields(newSobjLevel_2, fieldMapLevel_2);
                    //level-3
                    if(mappings[3].sObjectApiNameLevel_3__c != null) { 
                        sobject newSobjLevel_3 = (sObject)Type.forName('Schema',mappings[0].sObjectApiNameLevel_3__c).newInstance();//placeholder__c 
                        Map<String, Object> fieldMapLevel_3 = (Map<String, Object>)fieldMap.get('placeholder');
                        GetSobjectFields(newSobjLevel_3, fieldMapLevel_3);
                        //level-4
                        if(mappings[4].sObjectApiNameLevel_4__c != null) { 
                            sobject newSobjLevel_4 = (sObject)Type.forName('Schema',mappings[4].sObjectApiNameLevel_4__c).newInstance();//target__c 
                            Map<String, Object> fieldMapLevel_4 = (Map<String, Object>)fieldMap.get('target');
                            GetSobjectFields(newSobjLevel_4, fieldMapLevel_4);                                
                        }
                    }
                }
            }
        }  
    }
    public static sobject GetSobjectFields(sObject newSobj, Map<String,Object> fieldMap ){
        Map<String,String> fieldsMap = new Map<String,String>();
        Map<String, Schema.sObjectField> targetFields = newSobj.getSObjectType().getDescribe().fields.getMap();
        system.debug('[UploadDocuments]targetFields: ' + targetFields);
        for (String key : fieldMap.keySet()) {
            Object value = fieldMap.get(key);
            value = value == ''? null: value;
            switch on targetFields.get(key)?.getDescribe().getType() {
                when DATE {
                    value = Date.valueOf((String)value);
                }
                when DATETIME {
                    value = DateTime.valueOf((String)value);
                }
                when PERCENT, CURRENCY {
                    value = (Decimal)value;
                }
                when DOUBLE {
                    value = Double.valueOf(value);
                }
                when INTEGER {
                    value = (Integer)value;
                }
                when BASE64 {
                    value = Blob.valueOf((String)value);
                }
            }
            newSobj.put(fieldsMap.get(key), value);
        } 
        insert newSobj; 
        system.debug('[DynamicJSON]newSobj: ' + newSobj);
        return newSobj;
    }  
}
7
  • Have you tried List<Object> fieldMapLevel_0 = fieldMap.get('Accts'); ? – Nick Cook Jan 24 at 22:26
  • @NickCook my class GetSobjectFields(sObject newSobj, Map<String,Object> fieldMap ) is expecting a map. – Thomas Jan 24 at 22:29
  • 1
    Your JSON doesn't contain a map for the key Accts. It contains a list. Either your code is incorrect or your JSON is incorrect, but the nature of the error is unambiguous. – David Reed Jan 24 at 22:34
  • @Thomas Just because your method expects a map does not mean a list of objects must be a map – Nick Cook Jan 24 at 22:36
  • @Thomas, JSON deserialization (untyped) turns JSON objects to Map<String, Object> and JSON arrays into List<Object>. Since the JSON has 'Accts' as an array, this means you get a List and that is how you must process it. – Phil W Jan 24 at 22:37
2
Map<String, Object> fieldMapLevel_0 = (Map<String, Object>)fieldMap.get('Accts');

The value of the key Accts in your JSON is a List, not a Map:

    String jsonPayLoad = '{"Accts":[{"Name":"ABC","Exp":25,"Languages":[{"Name":"Apex","version": []},{"Name":"Java","versions":[{"version":1.8,"certification":true,"placeholder":{"target":"reached"}}]}]}]}';

The runtime type is List<Object>.

This syntax

Map<String, Object> fieldMapLevel_0 = new Map<String, Object>(fieldMap.get('Accts'));

only works on lists of sObjects to create a Map keyed on the Id field; your data does not have Ids present and it's not clear what the unique identifier is, if any. You'd have to iterate to create a Map from this List, but if the key you select from your data is not unique, you'll have to be prepared to handle that in a way appropriate to your business requirements.

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.