1

I'd like to ask everyone their input on the preferred way to parse a JSON response where the structure varies.

I created a class using the json2apex service and it looks very solid. However I have found that service we are consuming alters their structure depending on what is returned. Specifically, sometimes an element comes over as a json object, sometimes it comes over as an array.

Here is an example of the JSON section where it's coming as an object:

            "adjustments": {
              "adjustment_detail": {
                "desc": "    $1500001 and greater",
                "price_adj": "-0.125",
                "rate_adj": "0.000",
                "margin_adj": "0.000",
                "applied": "true"
              },
              "total_price_adj": "-0.125",
              "total_rate_adj": "0.000",
              "total_margin_adj": "0.000"
            },

Here is the response if the "adjustments" element has an array

            "adjustments": [
              {
                "desc": "LTV > 75 to 80% FICO 740 to FICO 759 ",
                "price_adj": "-0.375",
                "rate_adj": "0.000",
                "margin_adj": "0.000",
                "applied": "true"
              },
              {
                "desc": "CA   ",
                "price_adj": "0.250",
                "rate_adj": "0.000",
                "margin_adj": "0.000",
                "applied": "true"
              },
              {
                "desc": "    $1000000 and greater",
                "price_adj": "0.125",
                "rate_adj": "0.000",
                "margin_adj": "0.000",
                "applied": "true"
              }
            ],
            "total_price_adj": "0.000",
            "total_rate_adj": "0.000",
            "total_margin_adj": "0.000",
            "special_bonuses": {
              "total_special_bonus_adj": "0.000"
            },

Here is apex portion of my json parser logic

    public class Adjustments {
        public Adjustment_detail adjustment_detail {get;set;} 
        public String total_price_adj {get;set;} 
        public String total_rate_adj {get;set;} 
        public String total_margin_adj {get;set;} 

        public Adjustments(JSONParser parser) {
            while (parser.nextToken() != System.JSONToken.END_OBJECT) {
                if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
                    String text = parser.getText();
                    if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
                        if (text == 'adjustment_detail') {
                            adjustment_detail = new Adjustment_detail(parser);
                        } else if (text == 'total_price_adj') {
                            total_price_adj = parser.getText();
                        } else if (text == 'total_rate_adj') {
                            total_rate_adj = parser.getText();
                        } else if (text == 'total_margin_adj') {
                            total_margin_adj = parser.getText();
                        } else {
                            System.debug(LoggingLevel.WARN, 'Adjustments consuming unrecognized property: '+text);
                            consumeObject(parser);
                        }
                    }
                }
            }
        }
    }

How could I alter my logic to adjust for a missing Adjustment_detail section when an array is provided instead? Currently it doesn't expect an array.

My code works when the element is provided as an single object, but breaks if an array is returned.

Thanks

  • 2
    Using untyped JSON would allow for either an object or an array, which you can test using instanceof in the Apex code. It's not very nice in that you don't get POTATO objects, just maps of strings to objects, but it would suit your scenario. The only alternative I can think if is to semi-parse the JSON to determine the type then deserialize using an appropriate type for your (strict) parsing. – Phil W Feb 23 at 16:53
  • The method Phil is most likely referring to is JSON.deserializeUntyped (that we use a lot). – Keith C Feb 23 at 17:10
  • Thank you and no thank you :) I'm not looking forward to coding an untyped solution, but if it's my best option, so be it. Thanks for the input – Belacyrf Feb 23 at 17:41
  • 1
    Like I said, you could semi-parse the JSON, using a regex for example that matches the start of the text, and select one of two different deserialization options based on whether you found an array "[" or object "{". (Yes, I was referring to JSON.deserializeUntyped) – Phil W Feb 23 at 18:20
  • Yup, I understood, I could also check for the existence of "adjustment_detail" and then deserialize it to an array at if it doesn't exist. Just a bit ugly. But I appreciate the untyped option. – Belacyrf Feb 23 at 19:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.