5

I am trying to avoid having to do a JSON deserialized untyped, but not sure if I can... I get back a response of contact data from a third party that looks something like this:

{"data": {
"1500":{"id":"1500","last_name":"Test1"},
"298":{"id":"298","last_name":"Test2"}
},
"status_code":200}

So if you use JSONtoApex, you get a class like this:

public class jContactsDemo {

    public class Data {
        public 1500 1500;
        public 1500 298;
    }

    public class 1500 {
        public String id;
        public String last_name;
    }

    public Data data;
    public Integer status_code;

Which makes sense - but of course, 1500 and 298 are both contacts with the same structure - so is there some way I am not thinking of to just let me use JSON.deserialize into a Apex Class that can recognize that each entry in the array is the same type?

I had tried to use an initial conversion using JSON.deserializeUntyped, and then loop through results of Map, convert to String, and deserialize each record one at a time:

Map<String, Object> m = (Map<String,Object>)JSON.deserializeUntyped(s);

 for (String s: m.keyset()){
     Map<String, Object> mData = (Map<String, Object>)m.get('data');
     for (String s2: mData.keyset()){
         String sJSON = String.ValueOf(mData.get(s2));
        system.debug(sJSON);
     }   
}

But when I look at the value I get out of the Map, all the double quotes have been removed, which throws a different error...

System.JSONException: Unexpected character ('a' (code 97)): was expecting double-quote to start field name at [line:1, column:3]

  • Hi, have you tried my method? I've tested and verified that you can indeed deserialise into the object of your choice, provided you do a little fiddling beforehand. – Caspar Harmer May 8 '15 at 0:11
11

You are going to laugh at this, but it turns out that REENCODING as JSON at each step gets you your quoted values. Strange but true!! Try this:

String jsonData = '{"data": {"1500":{"id":"1500","last_name":"Test1"},"298":{"id":"298","last_name":"Test2"}},"status_code":200}';

//get top level map
Map<String,Object> jsonMap = (Map<String, Object>)JSON.deserializeUntyped(jsonData);

//extract data as JSON
String jsonSubset = JSON.serialize(jsonMap.get('data'));

//re-encode as a Map
Map<String,Object> jsonSubsetMap = (Map<String, Object>)JSON.deserializeUntyped(jsonSubset);

MyContact[] contacts = new MyContact[]{};
for (Object obj : jsonSubsetMap.values()){
    //re-encode as json, again!
    String jsonObj = JSON.serialize(obj);
    //deserialize that b@#$ard!!
    MyContact contact = (EBTestDeleteMe.MyContact)JSON.deserialize(jsonObj, MyContact.class);
    contacts.add(contact);
}

System.debug(contacts);

This outputs:

DEBUG|(MyContact:[id=298, last_name=Test2], MyContact:[id=1500, last_name=Test1])

This assumes you have a class called MyContact that looks like this:

public class MyContact {
    public String id;
    public String last_name;
}
  • That is genius...though I feel like I need to take a shower after so much hackery... :) – BritishBoyinDC May 8 '15 at 0:20
  • Hahah. Yes, it is a bit hackish :) – Caspar Harmer May 8 '15 at 0:28
  • like that code comment statement b@#$ard!!! – Mohith Shrivastava May 8 '15 at 0:45
  • @CaspNZ This is called nailed it .... – Mohith Shrivastava May 8 '15 at 0:45
  • Haha, I was pretty pleased with the outcome too... That comment wouldn't have made to production code ;) – Caspar Harmer May 8 '15 at 1:27
1

Good question and very easy to get confused with format you have. As per JSON Syntax, format should be Key : Value.

Eventhough 1500 and 298 in your case has same structure but it has different key names. Thats why Salesforce or any other programming language will consider it as different node.

To answer your question - Did you tried something like this ?

Map<String, Object> m = (Map<String, Object>) JSON.deserializeUntyped(s);
List<Object> lstNode = (List<Object>) m.get('1500');

If not, Can you please post sample code.

  • Thing is, I won't know the Ids until I get back the response - so see sample above - I have to loop through the results of the 'data' object in the initial map to get each entry I need - but when I use that syntax, it seems to strip my "" from the JSON, and I can't deserialize it? – BritishBoyinDC May 7 '15 at 23:30
  • You can, check my answer out! – Caspar Harmer May 7 '15 at 23:34

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.