[SalesForce] Error: Invalid conversion from runtime type List to List>

This seems similar to other "Can not cast List to List" questions, except in the other cases the culprit tended to be custom sObjects, whereas nothing like that is relevant here.

Why is this cast illegal? What additional checks do I have to add?

I do this after I make an API call to a 3rd party service, and I get back some JSON, which is a string, and then I pass the string into this function, to transform it into what I want:

public List<Map<String, Object>> deserializeJson(String privcoDataString) {
boolean badApiCall = false;
List<Map<String, Object>> deserializedResults = new List<Map<String, Object>>(); 
    Object objResponse = JSON.deserializeUntyped(privcoDataString);

    if (objResponse instanceof Map<String, Object>) {
        Map<String, Object> mapResponse = (Map<String, Object>)objResponse;

    System.debug('mapResponse.get(data)'); 
    System.debug(mapResponse.get('data')); 

        List<Map<String, Object>> possibledeserializedResults = (List<Map<String, Object>>)mapResponse.get('data');

    if(possibledeserializedResults == null) {
    badApiCall = true; 
        } else if (possibledeserializedResults.isEmpty()) {
    badApiCall = true; 
        } else {
    deserializedResults = possibledeserializedResults;
    }

    } else {
    badApiCall = true; 
}

if (badApiCall) {
    System.debug(objResponse);
    ApexPages.Message msgErr = new ApexPages.Message(ApexPages.Severity.ERROR, 'Search Failed! Sorry!');
    ApexPages.addmessage(msgErr);
    Map<String, Object> errorMap = new Map<String, Object>();
    errorMap.put('bad_api_call', true); 
    deserializedResults.add(errorMap); 
}

    return deserializedResults;
}

This line gives me an error:

List<Map<String, Object>> possibledeserializedResults = (List<Map<String, Object>>)mapResponse.get('data');

The error is:

Invalid conversion from runtime type List to List>

And yet, as you can see, I have not declared data to be a List yet. It should be an Object and then in this line I narrow cast it. But it doesn't work.

Where would the code get the idea that "data" is List, and even if that is true, why can't I then narrow cast that to List<Map<String, Object>>?

In this case, data is a List full of Map instances. So the conversion should be valid.

Best Answer

I agree with Rahul's comment that the following is probably the best you can do:

String payload = '{"data": [{"s": "a", "i": 1}]}';
Map<String, Object> deserialized = (Map<String, Object>)JSON.deserializeUntyped(payload);
List<Map<String, Object>> data = new List<Map<String, Object>>();
for (Object instance : (List<Object>)deserialized.get('data'))
    data.add((Map<String, Object>)instance);    
Related Topic