+ Start a Discussion
Brian Newbold 18Brian Newbold 18 

Can you deserializeUntyped with JSON arrays?

Can you deserializeUntyped with JSON arrays?
I'm finding it difficult to get down into the "client" level so that I can retrieve ID and Status. 
results.get('items') was easy enough at the top level, but attempting results.get('client') fails.

Using this JSON:
{
    "items": [
        {
            "client": {
                "id": "xyz65240-a8e0-4184-8aaa-8b381ea83ce5",
                "status": "enabled"
            }
        },
        {
            "client": {
                "id": "8b265241-3662-4a49-b7dd-97f948ca9bb6",
                "status": "enabled"
            }
        }
    ]
}

Using this code:
Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());

List<Object> items = (List<Object>) results.get('items');
    System.debug('Received the following items:');
    for (Object item: items) {
        System.debug('Item:');
        System.debug(item);
    }
MTBRiderMTBRider
The easiest way to do this is to deserialize into attributes of a class that you create. 
 
public class myJson{
     public List<String> items;
}

myJson deser = (myJson) JSON.deserialize( response.getBody(), myJson.Class );

Then loop over the list and deserializeUntyped each "items" element created.
 
JSON.deserializeUntyped( deser.items[0] );
JSON.deserializeUntyped( deser.items[1] );
... etc.

 
Brian Newbold 18Brian Newbold 18

I like the idea MTBRider..however I was getting Illegal value for primitive on the myJson.Class line though.



FYI I resolved my issue but found some good resources along the way.

In depth json parsing article :: https://www.lopau.com/demystifying-json-parsing-in-apex/ 

JSON2Apex is highly useful, http://json2apex.herokuapp.com/

What I found was that JSON2Apex writes your parser for you. However it tended to use Object types, throwing errors. Converting the Object(s) to strong types (String) it worked fine.

JSON2Apex handled the arrays making things much easier.

So for the above example

//
// Generated by JSON2Apex http://json2apex.herokuapp.com/
//

public class api_ClientServiceClientHandler {

	public List<Items> items;

	public class Items {
		public Client client;
	}

    //KEEP IN MIND the class types must be concrete. JSON2Apex generates "Object"s which JSON parsing doesn't like
	public class Client {
		public String id;
		public String status;
	}

	
	public static Api_ClientServiceClientHandler parse(String json) {
		return (Api_ClientServiceClientHandler) System.JSON.deserialize(json, Api_ClientServiceClientHandler.class);
	}
}
Then fed the handler class by calling the parse method with my JSON response and ripped apart the array by looping over the returned object:
api_ClientServiceClientHandler myList = api_ClientServiceClientHandler.parse(response.getbody());

            for (api_ClientServiceClientHandler.Items item: myList.Items) {
                System.debug('Client:');
                System.debug('id: ' + item.Client.id);
                System.debug('Status: ' + item.Client.Status);      
    		}

This returns the 2 client records, and then all the client details are listed out.

Thanks MTBRider.. you helped me find the path to the solution!

 
MTBRiderMTBRider
The JSON that you are deserializing passes as valid JSON, but it is very oddly formed with a lot of redundant & unnecessary labels and there is no label to deserialize the array into.  Do you have any control over the format of the JSON?  If so, I would streamline it like this:

{ "items": [ ["xyz65240-a8e0-4184-8aaa-8b381ea83ce5", "enabled"], ["8b265241-3662-4a49-b7dd-97f948ca9bb6", "enabled"] ] }

Then, this code will process it:
 
public class myJson{
    public List<List<String>> items;
}
String jStr = '{"items": [["xyz65240-a8e0-4184-8aaa-8b381ea83ce5","enabled"],["8b265241-3662-4a49-b7dd-97f948ca9bb6","enabled"]]}';

myJson deserial = (myJson) JSON.deserialize( jStr, myJson.Class );
system.debug('Id ' + deserial.items[0][0] + ' is ' + deserial.items[0][1]);