2

We have been receiving JSON updates from one of our third parties for updates on deliveries, and they bulkify them in batches of up to 100 updates (example below).

{
  "item": [
    {
      "id": "1",
      "status": "delivered",
      "datetime": "2021-03-25T12:00:00Z"
    },
    {
      "id": "2",
      "status": "delivered",
      "datetime": "2021-03-25T14:00:00Z"
    },
    {
      "id": "3",
      "status": "delivered",
      "datetime": "2021-03-25T13:00:00Z"
    }
  ],
  "Account": "CompanyId"
}

However, we have been running into the following issue if there is only 1 update for delivery, they do not send the array brackets [] with it, so it looks like the below.

{
  "item":
    {
      "id": "1",
      "status":"delivered",
      "datetime": "2021-03-25T12:00:00Z"
    },
  "Account": "CompanyId"
}

This causes the JSON deserializer to kick out the following error:

System.JSONException: Expected List<DeliveryItems> but found { at [line:6, column:22]

Any thoughts would be much appreciated. We expect the issue is happening due to the 3rd parties back end actual runs under XML, and they are doing an on the fly conversion with no context.

EDIT: Our Current workaround is that we try-catch the exception then run deserialization against a different class without a list for items. This is fine for things with 1 list, but we have some further work where there could be up to 5 lists which makes this not scaleable.

3

Because of the limits of how JSON works in Apex, you're limited to either JSON.deserializeUntyped or JSONParser.

With the former, you'll have to inspect the items property to determine if it is an array or not, and take the appropriate steps.

Map<String, Object> parsedJson = (Map<String, Object>)JSON.deserializeUntyped(jsonBody);
Object itemsElement = parsedJson.get('items');
if(itemsElement instanceOf Map<String, Object>) {
  // Handle as an object
}
if(itemsElement instanceOf List<Object>) {
  // Handle as an array
}

For the JSONParser code, you'll have to examine each token one at a time. It takes a decent bit of time to learn how to use it, and I never bothered, as I find JSON.deserializeUntyped to be a lot easier to manage.

3
  • The issue is that this works fine if there is only 1 list we have some messages we have yet to do that could contain up to 5 lists meaning we would need 5! classes. Mar 20 at 17:08
  • @KarlLivesey Actually, it'd be 2^5 (32) classes to explore all permutations. However, deserializeUntyped uses only built-in classes. You would then be able to have just one class that always uses lists, and just convert a non-list to a list. It's more code, but far fewer classes.
    – sfdcfox
    Mar 20 at 17:14
  • Well, It's not the ideal solution, but I can't think of anything better my main concern is maintenance if they add/remove fields, but I suppose we'll have to cross that bridge as we get there. @sfdcfox Mar 20 at 17:27

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.