2

I am consuming a REST service with APEX.

Here is a response sample:

{
  "createQuoteOutput": {
    "response": {
      "quoteNumber": 945,
      "temporaryQuoteNumber": "T8652"
    },
    "warningInfo": [
      {
        "warningCode": "W-600",
        "relatedItem": "ItemNumber:77982",
        "warningMessage": "Unit Price Not Set Up for Item"
      },
      {
        "warningCode": "W-600",
        "relatedItem": "ItemNumber:77983",
        "warningMessage": "Unit Price Not Set Up for Item"
      }
    ],
    "responseTime": 3
  }
}

I am generating my classes with https://json2apex.herokuapp.com/.

Here are part of those classes:

public class WarningInfo {
    public String warningCode;
    public String relatedItem;
    public String warningMessage;
}

public CreateQuoteOutput createQuoteOutput;

public class CreateQuoteOutput {
    public Response response;
    public List<WarningInfo> warningInfo;
    public Integer responseTime;
}

I am parsing the JSON into the class with JSON.deserialize function:

APISalesDAO apiresponse = (APISalesDAO) System.JSON.deserialize(requestor.sendRequest(), APISalesDAO.class);

So, the code works fine when the response is coming with 2 or more warnings, but when is coming with 1 or 0 I am getting next error:

Expected List<APISalesCreateQuoteResponse.WarningInfo> but found { 

Obviously this is related with the JSON format for arrays ([] vs {}). Because I am getting this error when the response is:

{
  "createQuoteOutput": {
    "response": {
      "quoteNumber": 945,
      "temporaryQuoteNumber": "T8652"
    },
    "warningInfo": {
        "warningCode": "W-600",
        "relatedItem": "ItemNumber:77982",
        "warningMessage": "Unit Price Not Set Up for Item"
      },
    "responseTime": 3
  }
}

What is the best way to fix this? Is there any way to parse the JSON data into an array or direct object depending of the context? Or should I implement workarounds with Maps and other stuff?

Thanks in advance

1

Pretty annoying that the service you are calling changes the structure when there are 0 or 1 elements. Worth suggesting to whoever provides the service that their approach makes it hard for consumers and that maybe they should change this in a v2 API...

There may be a more elegant approach, but if not for now I suggest you use JSON.deserializeUntyped into a map. You can then walk down through the map and manually transfer values into the classes. When it comes to the warningInfo field you can check if it contains a collection or not:

Object o = m.get('warningInfo');
if (o instanceof List<Object>) {
    // Multiple
    for (Object info : (List<Object>) o) {
        ...
    }
} else if (o != null) {
    // One
    Object info = o;
    ...
} else {
    // None
}

This works because in Apex instanceof List<Object> is true whatever the type of the list elements.

| improve this answer | |
  • I think the change is related with JSON language more than API implementation. – Edgar Aguilar Mar 7 '16 at 23:05
  • @EdgarAguilar JSON is simple and makes clear distinctions between arrays in [] and objects in {}. There is nothing in JSON that says a 1 object array should be automatically replaced by just the object. – Keith C Mar 7 '16 at 23:10
  • I think the difference is related with JSON language more than API implementation. JSON with one element: Element {"ParamA":"ValueA"} JSON with a list of elements of the same type: Element[ {"ParamA":"ValueA"}, {"ParamA":"ValueB"} ] Please feel free to correct me if I am wrong but I think is the way JSON works. About your possible solution, I think that could work but is going to be a nightmare to implement this kind of solution for each API operation. I would be very disappointed if there is no other easier solution. Is there any other possible approach? – Edgar Aguilar Mar 7 '16 at 23:11
  • Hi @Keith, but my question is regarding the JSON.deserialize operation and the APEX classes that we have. If the number of expected elements is known then you can create your classes with arrays, so in that way JSON.deserialize will create the elements automatically for you. If the number the elements is variable, what we can do? If I have a List the parsing function fails because is looking for '[' and is finding '{', and vice-versa. – Edgar Aguilar Mar 7 '16 at 23:19
  • @EdgarAguilar JSON.deserialize works great for arrays whether they have 0, 1 or many elements. Your problem is that whoever designed the service you are calling made a poor design decision to switch from object to array when there are 2 or more elements. I suggest you leave out the CreateQuoteOutput.warningInfo field and do most of the parsing using JSON.deserialize and write a separate utility method that parses out the warningInfo using JSON.deserializeUntyped (assuming you want to capture that information). – Keith C Mar 7 '16 at 23:30

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.