0

I have an APEX callout that makes a call to a REST API and returns an object, in this case I am calling /services/data/v48.0/sobjects/Case/describe. I was trying to use this same APEX class to call out to another 3rd party endpoint, however, that endpoint is returning a list.

This causes an error of FATAL_ERROR System.TypeException: Invalid conversion from runtime type List<ANY> to Map<String,ANY>.

Is there a way I can adapt this callout to be able to handle both situations? I'm not really going to know what the response type will always be.

Code:

public static map<String, Object> GetCallout(string namedCredential, string endpoint) {
    HTTPRestService_EnterpriseCaseCreation caseService = new HTTPRestService_EnterpriseCaseCreation();
    HttpResponse calloutResponse = caseService.makeGetCallout(namedCredential, endpoint);
    map<String, Object> mapJsonData = new map<String, Object>();
    String strResponse = null;

    try {
        if (calloutResponse.getStatusCode() == 200) {
            strResponse = calloutResponse.getBody();
        } else {
            throw new CalloutException(calloutResponse.getBody() );
        }
    } catch (Exception ex) {
        throw ex;
    }

    if (!String.isBlank(strResponse) ) {
        mapJsonData = (map<String, Object>) JSON.deserializeUntyped(strResponse);
    }

    if (!mapJsonData.isEmpty() ) {
        return mapJsonData;
    } else {
        return null;
    }
}

map<String, Object> test = GetCallout('SF_Enterprise', '/services/data/v48.0/sobjects/Case/describe');
map<String, Object> test2 = GetCallout('Mule_ESB_Crosswalk_Service', '?guid=9C7E57CF-2DC7-4C89-B476-11166DED34DC'); // Invalid conversion from runtime type List<ANY> to Map<String,ANY>

System.debug(test); // Line 46 
System.debug(test2); // Line 47 

The image shows what the responses look like before I try to use map and just see the response as a string.

enter image description here

Is there a more dynamic way to handle these various scenarios?

1

You can check the type with instanceOf:

Object result = JSON.deserializeUntyped(strResponse);
if(result instanceOf Map<String, Object>) {
  // This is a Map
} else if(result instanceOf List<Object>) {
  // This is a List
}

This allows you to determine what the type is before you try to cast, avoiding the need for try-catch blocks.

Note that the return type for the method would still need to be an Object, as these types are incompatible with each other.

Most likely, the caller will need to do this cast in order to utilize the data within.

0

You can always try return type Object and convert afterwards.

public static Object GetCallout(string namedCredential, string endpoint) {

And then:

Object test = GetCallout('SF_Enterprise', '/services/data/v48.0/sobjects/Case/describe');
Object test2 = GetCallout('Mule_ESB_Crosswalk_Service', '?guid=9C7E57CF-2DC7-4C89-B476-11166DED34DC');
Map<String, Object> testMap = (Map<String, Object>)test;
List<Object> testList = (List<Object>)test2;
  • Thanks, the only problem I think is that this class is used for my LWC as an imperative call. All I do is return the result from the callout, so I wouldn't have a way to manipulate it at the end like this. Can this be put into some type of if/else where it checks to see if the response is an object, and returns it as the map, or if its a list, returns it as such? That way it returns it based on the format its in rather than me needing to manually cast it. – SBB Jul 30 '20 at 17:53
  • 1
    You can have a try catch with casting to Map, and then if fails, to List. Not sure there's other ways. But ideologically you should know what format of data to expect and make those separate calls with appropriate DTOs. – ipetrovych Jul 30 '20 at 18:04

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.