简体   繁体   中英

Java - Parsing JSON Response - Content is either String or JSONObject

I am facing a typical scenario while parsing JSON Response for one of the Service calls.

The content for one of the attributes (from below example, consider "name" as a attribute) coming as either String or JSONObject.

How to handle these kind of scenarios through code. Also, please consider that json content need not be consistent with same set of attributes.

Example:

String Response

{"name":"Adam"}

JSON Response

{"name":{"FirstName":"Adam", "MiddleName":"Don"} }

OR

{"name":{"FirstName":"Adam", "LastName":"Don"} }

OR

{"name":{"MiddleName":"Adam", "LastName":"Don"} }

You can ask the root JSONObject with the method optJSONObject(name) to return a JSONObject for the given name if it exists and is an JsonObject. Otherwise you can also test with optString(name) for a String.

So something like:

JSONObject root = new JSONObject(... data from server ... );
JSONObject obj = root.optJSONObject("name");
if (obj != null) {
   // Do something with the object
} else {
   String name = root.getString("name");
   // Do something with the string
}

Parse your response JSON as a JSONObject, then get another JSONObject for the "name" key, if it throws a JSONException then your object is probably a String in with case you can call get String for the "name" key in your catch block.

String name = "";
JSONObject serverJSON = new JSONObject(YOUR_JSON_RESPONSE_STRING_FROM_SERVER);

try {
     JSONObject nameObject = serverJSON.getJSONObject("name");
     if (nameObject.has("first_name")) {
         name = nameObject.getString("first_name") + " ";
     }

     if (nameObject.has("middle_name")) {
         name += nameObject.getString("middle_name") + " ";
     }

     if (nameObject.has("last_name")) {
         name += nameObject.getString("last_name");
     }

     name = name.trim();
} catch (JSONException e) {
     // Probably a String, try again...
     try { 
          name = serverJSON.getString("name");
     catch (JSONException e) {
          // Not a String or a JSONObject... figure out what's wrong...
          e.printStackTrace();
     }
}

I would really recommend though, that if you have any control of the server that you make sure that the name key choose one type and sticks to it; a JSONObject... You would be able to use the has(String key) member function in if statements to properly find all of your data without knowing what existed at runtime...

EDIT: Thought of a different idea... Parse the String to the first colon and see if the next non-whitespace character is a quotation mark, if it is, then your key belongs to a String, if it is a curly brace then it's a JSONObject. (If neither, then you have an error, because you aren't expecting an array or number or null or anything else...)

boolean jsonIsString = true;
String searchString = json.substring(json.indexOf(":")).trim();
if ("{".equals(searchString.charAt(0)) {
    jsonIsString = false;
}

Tonity's solution is good. You can also use this solution.

In my solution, there will be no any Exception fired until JSON is wrong . What I am doing is following.

  1. Search for number of ":" in string.
  2. If it returns 1, then we sure that there is "name" value.
  3. Otherwise, we need to check, whether there is "FirstName","MiddleName" or "LastName" exist in string or not.

Just go through this snippet and you will find solution for your problem.

// String str = "{\"name\":\"chintan\"}";
String str = "{\"name\":{\"FirstName\":\"Chintan\",\"LastName\":\"Rathod\"}}";

try {
    //we will check how many ":" are there in string, if it is one, then
    // we are going to get "name" field.
    if ((str.split(":").length - 1) == 1) 
    {
        Log.d("Home", "1");
        JSONObject json = new JSONObject(str);
        Log.d("Home", "Name : " + json.get("name"));
    } 
    else
    {
        Log.d("Home", "more then 2");

        JSONObject jName = new JSONObject(str);

        JSONObject jTemp = jName.getJSONObject("name");

        if (jTemp.toString().contains("FirstName"))
            Log.d("Home", "FirstName :" + jTemp.getString("FirstName"));

        if (jTemp.toString().contains("MiddleName"))
            Log.d("Home","MiddleName :" +jTemp.getString("MiddleName"));

        if (jTemp.toString().contains("LastName"))
            Log.d("Home", "LastName :" + jTemp.getString("LastName"));
    }
} catch (JSONException e) {
    e.printStackTrace();
}

Output

08-06 11:52:34.060: D/Home(1439): more then 2
08-06 11:52:34.060: D/Home(1439): FirstName :Chintan
08-06 11:52:34.070: D/Home(1439): LastName :Rathod

I faced a problem like this as well. I didn't want to parse the JSON manually. Do this if firstName exists otherwise do that. I didn't want to mess up my structure because I only define java object and my client handles the parsing. So, I came up with following:

@Getter
@Setter
@ToString
class Response {
    private Name name;

    @Getter
    @Setter
    @NoArgsConstructor
    @ToString
    public static class Name {
        private String name;
        private String firstName;
        private String middleName;
        private String lastName;

        public Name(String name) {
            this.name = name;
        }
    }
}

Then, parse the json;

ObjectMapper objectMapper = new ObjectMapper();
Response response = objectMapper.readValue(json, Response.class);

Now, string response and JSON response can be parsed with the same class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM