141

I am going to receive either a JSON Object or Array from server, but I have no idea which it will be. I need to work with the JSON, but to do so, I need to know if it is an Object or an Array.

I am working with Android.

Does any one have a good way of doing this?

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
Greg
  • 3,086
  • 3
  • 26
  • 39
  • If using Gson with Android and when it comes to deserialing one way to do it is like [this](https://stackoverflow.com/q/52456821/6413377). – pirho Oct 12 '18 at 21:32

9 Answers9

261

I found better way to determine:

String data = "{ ... }";
Object json = new JSONTokener(data).nextValue();
if (json instanceof JSONObject)
  //you have an object
else if (json instanceof JSONArray)
  //you have an array

tokenizer is able to return more types: http://developer.android.com/reference/org/json/JSONTokener.html#nextValue()

neworld
  • 7,757
  • 3
  • 39
  • 61
  • 1
    nice job. hope it will check for both JsonObject and Json Array – Shreyash Mahajan Dec 20 '12 at 05:05
  • 2
    @neworld but what if I am in the middle of a loop. trying to get a data.getJSONArray() or data.getJSONObject() will potentially throw a JSONEXception!! – P-RAD Dec 02 '15 at 03:48
  • Hi my objectdata is middle of response so how can i detect that? to check whether its a JSONObject or JSONArray??? and In your answer String data = "{ ... }"; is having value of whole response??? – amit pandya Dec 30 '17 at 10:54
  • To accomplish that, you have to parse your JSON using `JSONTokener`. I didn't do that, but I suppose you should [skipPast("your_key")](https://developer.android.com/reference/org/json/JSONTokener.html#skipPast(java.lang.String)). But I am not sure. However, you should consider using json mapper: Gson, Jackson, Moshi and ton of others. – neworld Dec 30 '17 at 14:06
55

There are a couple ways you can do this:

  1. You can check the character at the first position of the String (after trimming away whitespace, as it is allowed in valid JSON). If it is a {, you are dealing with a JSONObject, if it is a [, you are dealing with a JSONArray.
  2. If you are dealing with JSON (an Object), then you can do an instanceof check. yourObject instanceof JSONObject. This will return true if yourObject is a JSONObject. The same applies to JSONArray.
nicholas.hauschild
  • 42,483
  • 9
  • 127
  • 120
  • 3
    That definitely worked. In the end though, I put the string into a JSONObject and if it threw an error, then I knew it was a JSONArray. try { return new JSONObject(json); } catch (Exception e) { } try { return new JSONArray(json); } catch (Exception e) { } – Greg Jun 23 '11 at 23:43
14

This is the simple solution I'm using on Android:

JSONObject json = new JSONObject(jsonString);

if (json.has("data")) {

    JSONObject dataObject = json.optJSONObject("data");

    if (dataObject != null) {

        //Do things with object.

    } else {

        JSONArray array = json.optJSONArray("data");

        //Do things with array
    }
} else {
    // Do nothing or throw exception if "data" is a mandatory field
}
sourcerebels
  • 5,140
  • 1
  • 32
  • 52
  • 1
    Not Android specific and I like this version best because it uses no character checks, but the `json.has("data")` supposes the whole thing is optional (not asked for). – Christophe Roussy Feb 02 '16 at 10:54
8

Presenting an another way :

if(server_response.trim().charAt(0) == '[') {
    Log.e("Response is : " , "JSONArray");
} else if(server_response.trim().charAt(0) == '{') {
    Log.e("Response is : " , "JSONObject");
}

Here server_response is a response String coming from server

Bhargav Thanki
  • 4,924
  • 2
  • 37
  • 43
2

A more fundamental way of doing this is the following.

JsonArray is inherently a List

JsonObject is inherently a Map

if (object instanceof Map){
    JSONObject jsonObject = new JSONObject();
    jsonObject.putAll((Map)object);
    ...
    ...
}
else if (object instanceof List){
    JSONArray jsonArray = new JSONArray();
    jsonArray.addAll((List)object);
    ...
    ...
}
Pankaj Singhal
  • 15,283
  • 9
  • 47
  • 86
  • Note, this does not work with org.json (not inherited from List or Map), works only with javax.json (jakarta.json-api). An approach here is to try an array, if it fails, catch and try object. – Boris Krassi Jul 28 '23 at 10:06
0

For those tackling this issue in JavaScript, the following did the job for me (not sure how efficient it is).

if(object.length != undefined) {
   console.log('Array found. Length is : ' + object.length); 
} else {
 console.log('Object found.'); 
}
Raf
  • 7,505
  • 1
  • 42
  • 59
0

instanceof

Object.getClass().getName()

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • I think the question assumes that you will be working with a plain string so using the instanceof or getClass().getName() wont work. – gamerson Sep 07 '12 at 10:22
  • @gamerson -- That's odd -- it's worked for me many times. You just have to have the parser return either object, vs specifying which. – Hot Licks Sep 07 '12 at 11:44
  • 1
    Clearly folks don't understand this. Pretty much every parser I've seen has a parse option to return a "JSONInstance" or simply "Object", or whatever. Parse the JSON and then ask it what it is. A parser which doesn't have this ability is broken. – Hot Licks Apr 05 '14 at 11:05
  • (This is, in fact, Neworld's answer, more or less.) – Hot Licks Apr 05 '14 at 11:10
0
JsonNode jsonNode=mapper.readTree(patchBody);

jsonNode has two method:
isObject();
isArray();

frank_liu
  • 31
  • 6
-1

My approach would be a total abstraction from this. Maybe someone finds this useful...

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class SimpleJSONObject extends JSONObject {


    private static final String FIELDNAME_NAME_VALUE_PAIRS = "nameValuePairs";


    public SimpleJSONObject(String string) throws JSONException {
        super(string);
    }


    public SimpleJSONObject(JSONObject jsonObject) throws JSONException {
        super(jsonObject.toString());
    }


    @Override
    public JSONObject getJSONObject(String name) throws JSONException {

        final JSONObject jsonObject = super.getJSONObject(name);

        return new SimpleJSONObject(jsonObject.toString());
    }


    @Override
    public JSONArray getJSONArray(String name) throws JSONException {

        JSONArray jsonArray = null;

        try {

            final Map<String, Object> map = this.getKeyValueMap();

            final Object value = map.get(name);

            jsonArray = this.evaluateJSONArray(name, value);

        } catch (Exception e) {

            throw new RuntimeException(e);

        }

        return jsonArray;
    }


    private JSONArray evaluateJSONArray(String name, final Object value) throws JSONException {

        JSONArray jsonArray = null;

        if (value instanceof JSONArray) {

            jsonArray = this.castToJSONArray(value);

        } else if (value instanceof JSONObject) {

            jsonArray = this.createCollectionWithOneElement(value);

        } else {

            jsonArray = super.getJSONArray(name);

        }
        return jsonArray;
    }


    private JSONArray createCollectionWithOneElement(final Object value) {

        final Collection<Object> collection = new ArrayList<Object>();
        collection.add(value);

        return (JSONArray) new JSONArray(collection);
    }


    private JSONArray castToJSONArray(final Object value) {
        return (JSONArray) value;
    }


    private Map<String, Object> getKeyValueMap() throws NoSuchFieldException, IllegalAccessException {

        final Field declaredField = JSONObject.class.getDeclaredField(FIELDNAME_NAME_VALUE_PAIRS);
        declaredField.setAccessible(true);

        @SuppressWarnings("unchecked")
        final Map<String, Object> map = (Map<String, Object>) declaredField.get(this);

        return map;
    }


}

And now get rid of this behaviour forever...

...
JSONObject simpleJSONObject = new SimpleJSONObject(jsonObject);
...
oopexpert
  • 767
  • 7
  • 12