1

I am trying to deserialize below JSON . Problem is that sometimes message is returned as an object and sometimes as an array .

In this JSON , I have combined three HTTP responses into one so as to get a complete set. It is a valid json per JSONLint.

{
  "LineStatus": [
    {
      "line": "1.00",
      "ConfigStatus": "E",
      "ConfiguratorMessages": {
        "message": {
          "MessageType": "E",
          "message": "PRODUCT REQUIRED."
        }
      }
    },
    {
      "line": "2.00",
      "ConfigStatus": ""
    },
    {
      "line": "3.00",
      "ConfigStatus": "W",
      "ConfiguratorMessages": {
        "message": [
          {
            "message": "COUPON EXPIRED",
            "MessageType": "W"
          }
        ]
      }
    },
    {
      "line": "4.00",
      "ConfigStatus": "W",
      "ConfiguratorMessages": {
        "message": [
          {
            "message": "COUPON EXPIRED",
            "MessageType": "W"
          }
        ]
      }
    },
    {
      "line": "5.00",
      "ConfigStatus": "W",
      "ConfiguratorMessages": {
        "message": [
          {
            "message": "COUPON EXPIRED",
            "MessageType": "W"
          },
          {
            "message": "COUPON RESTRICTED FOR ANOTHER PRODUCT",
            "MessageType": "W"
          }
        ]
      }
    }
  ]
}

Below is the apex to deserialize the above JSON but I don't know how to check when the data type of message changes from {} to [].

public class ConfigMessages {

    public List<LineStatus> LineStatus;

    public class LineStatus {
        public String line;
        public String ConfigStatus;
        public ConfiguratorMessages ConfiguratorMessages;
    }

    public class ConfiguratorMessages {
        public Message message;
    }

    public class Message {
        public String MessageType;
        public String message;
    }

    public static ConfigMessages parse(String json) {
        return (ConfigMessages) System.JSON.deserialize(json, ConfigMessages.class);
    }
}

//I have further tried to go the deserialize/serialize/deserialize again route as below but I have no clue how to take this further.

Map<String, Object> responseMap = (Map<String, Object>) JSON.deserializeUntyped(JsonString);   
List<Object> lineStatusObjectList = (List<Object>) responseMap.get('LineStatus');
List<Map<String, Object>> lineStatusResponseMapList = new List<Map<String, Object>>();

for (Object obj : lineStatusObjectList) {
    lineStatusResponseMapList.add((Map<String, Object>)obj);
}//for

String serializedLineStatusJson = JSON.serializePretty(lineStatusResponseMapList);
 for( Map<String, Object> mapObj : lineStatusResponseMapList ){
     for (String attributeName : mapObj.keyset()) {
         Map<String, Object> configuratorMessagesResponseMap =(Map<String, Object>) mapObj.get('ConfiguratorMessages'); 
         System.debug('** configuratorMessagesResponseMap ' + configuratorMessagesResponseMap);
      }          
}   
4
  • Instead of writing what amounts to unintelligible code in comments, please edit your question to include any additional details.
    – sfdcfox
    May 20, 2019 at 3:38
  • 1
    Also, is this JSON flexible? This is not a well-designed JSON object. Ideally, ConfiguratorMessages should always be an array of Message, as the name of it implies it is an array. Of course, you can parse this either way, but it would be a lot easier if there was a reliable design to begin with.
    – sfdcfox
    May 20, 2019 at 3:41
  • thanks @sfdcfox . I edited the question with additional info. On your 2nd comment, I wish I had control on the external system responding this JSON . However ,as I noted earlier, this is a valid JSON.
    – user66468
    May 20, 2019 at 4:39
  • @user66468 what external system is this? May 21, 2019 at 18:06

3 Answers 3

6

Pretty ugly, but less work than blank's approach:

Object o = JSON.deserializeUntyped(JsonString);
try {
    // See if an object
    Map<String, Object> m = (Map<String, Object>) o;
    ...
} catch(TypeException e) {
    // Not an object, must be an array
    List<Object> a = (List<Object>) o;
    ...
}
2

A colleague of mine, Kalyani Vairagade solved this problem with below approach. Combining this with isObject() method of JSONParse Class (https://github.com/open-force/jsonparse) gave what is needed. For interest of others , below is the raw code :-

Object deserializedSalesOrder= orderResponseMap.get('line-status');
system.debug('deserializedSalesOrder'+deserializedSalesOrder);
if (deserializedSalesOrder != null) {
    String serializedSalesOrder= JSON.serialize(deserializedSalesOrder);
    system.debug('serializedSalesOrder'+serializedSalesOrder);
    List<Object> salesOrderResponse = (List<Object>) JSON.deserializeUntyped(serializedSalesOrder);
    Map<Integer,Object> objMap=new Map<Integer,Object>();
    for(Integer i=0;i<salesOrderResponse.size();i++) {
        system.debug('salesOrderResponse'+salesOrderResponse[i]);
        objMap.put(i+1,salesOrderResponse[i]);
        String strLine = JSON.serialize(salesOrderResponse[i]);
        Map<String, Object> responseMapLine = (Map<String, Object>) JSON.deserializeUntyped(strLine);
        system.debug('responseMapLine : '+responseMapLine);
        if(responseMapLine.containsKey('configurator-messages')){
            Object configMsg = responseMapLine.get('configurator-messages');
            system.debug('configurator-messages : '+configMsg);
            String configMsgStr = JSON.serialize(configMsg);
            Map<String, Object> responseMapConfigMsg= (Map<String, Object>) JSON.deserializeUntyped(configMsgStr);
            System.debug('configMsgStr : '+responseMapConfigMsg.get('message'));
            Object bo=responseMapConfigMsg.get('message');
            String co = JSON.serialize(bo);
            if(co.startsWith('[')){
                String JsonString1=Utils.mogrifyJSON(JsonString,'ItemStatusjsonArray');
                system.debug('JsonString'+JsonString1);
                FrOmgJSONProcessor.FrItemsStatusResponseJSONProcessor objFGORJP= (FrOmgJSONProcessor.FrItemsStatusResponseJSONProcessor) System.JSON.deserialize(JsonString1, FrOmgJSONProcessor.FrItemsStatusResponseJSONProcessor.class);
                system.debug('objFGORJP'+objFGORJP);
            }else{
                String JsonString1=Utils.mogrifyJSON(JsonString,'ItemStatusjsonObject');
                system.debug('JsonString'+JsonString1);
                FrOmgJSONProcessor.FrItemsStatusResponseJSONProcessor objFGORJP= (FrOmgJSONProcessor.FrItemsStatusResponseJSONProcessor) System.JSON.deserialize(JsonString1, FrOmgJSONProcessor.FrItemsStatusResponseJSONProcessor.class);
                system.debug('objFGORJP'+objFGORJP);
            }
        }
    }

}
1

As @sfdcfox mentioned the API returning this JSON is not well architected. But as you have no way to influence it, unfortunately, you have no other option but to write your own parser using this documentation. In that parser you'll be able to handle the format change by just sending values to different properties of your class.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .