4

I need to parse a JSON string like this into an APEX Map object, where I only want to go through the objects in the "results" array. How can I do this?

{  
   "count":6176,
   "next":"https://example.herokuapp.com/objects/recaptures/?page=2",
   "previous":null,
   "results":[  
      {  
         "id":"101009",
         "annual_savings":"96613.91",
         "cost":1,
      },
      {  
         "id":"101116",
         "annual_savings":"40851.75",
         "cost":1,
      }, ...

I need to put this into a Map like this:

public Map<String, String> myMap { get; set; }

I've found a method called JSON.deserialize but how can I get it to just parse the "results" array?

  • What do you expect the key and value to be? – sfdcfox Jun 16 '16 at 14:56
10

Edit: I have a year more experience as a developer now and I realize my answer here was a bit too simplistic.

If you are looking to deserialize untyped without custom classes (so basically assume the data has the right structure at runtime) you can do it but it requires some steps. My original answer looked like this:

Map<String, Object> meta = (Map<String, Object>) JSON.deserializeUntyped(JsonString);
List<Map<String, String>> myMaps = (List<Map<String, String>>) meta.get('results');

I don't think that actually works. You basically have to cast one level at a time, like so:

Map<String, Object> meta = (Map<String, Object>) JSON.deserializeUntyped(JsonString);
List<Map<String, Object>> myMaps = new List<Map<String, Object>>();
List<Object> myMapObjects = (List<Object>) meta.get('results');
for (Object obj : myMapObjects) {
    myMaps.add((Map<String, Object>)obj);
}

And then if you wanted to end up with a Map<String, String> you'd need to iterate through the Map<String,Object> and cast each value to a String and construct a new Map. It's a bit tiresome but it can be done.

More info here with example of error catching: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_class_System_Json.htm#apex_System_Json_deserializeUntyped

10

You can use normal classes to parse the data:

public class ResponseResult {
    public Integer count;
    public String next, previous;
    public Result[] results;
    public class Result {
        public String id, annual_savings;
        public Integer cost;
    }
    public static ResponseResult parse(String jsonString) {
        return (ResponseResult)JSON.deserialize(jsonString, ResponseResult.class);
    }
}

After this, you can iterate over the results member variable to build a map if you'd like:

ResponseResult r = ResponseResult.parse(someJsonString);
Map<String, String> myMap = new Map<String, String>();
for(ResponseResult.Result result: r.results) {
    myMap.put(result.id, result.annual_savings);
}
  • Can we use class typed deserialization when there is a variation in JSON structure .. see body attribute in SF composite API response where it could be an array or an object : { "compositeResponse": [ { "body": { "id": "001R00000033I6AIAU", "success": true, "errors": [ ] } }, { "body": [ { "message": "Email: invalid email address.", "errorCode": "INVALID_EMAIL_ADDRESS", "fields": [ "Email" ] } ] } ] } – balinder singh Apr 17 '19 at 13:14
  • @balindersingh You'd create a combined structure that has the attributes of both. You can't use different classes, but as long as the overlapping members are of the same type, you can combine them. – sfdcfox Apr 17 '19 at 13:58
  • Yeah I know, if for example we have following fields: fields,success and then message,error i can create one object adding all these but my question here is 'body' in above mentioned json where it could be an array and same time it could be an object in other item response – balinder singh Apr 17 '19 at 14:14

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.