0

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"} }

Community
  • 1
  • 1
Ravi G
  • 859
  • 1
  • 8
  • 21
  • So.. You want to parse JSON string in java?? – codeMan Aug 06 '13 at 05:37
  • 1
    In any above example each is JSON.. how did you say `{"name":"Adam"}` is string – Pankaj Kumar Aug 06 '13 at 05:38
  • what exactly you are looking for?? your question is not clear – hemantsb Aug 06 '13 at 05:40
  • You say that ur facing a typical scenario and u dont say what that typical scenario is.. please edit you question to make more sense. – codeMan Aug 06 '13 at 05:40
  • @PankajKumar, Completely agree. But what he wants is, if there is no first name or middle name, he likes to further take those values by creating another json object. – Chintan Rathod Aug 06 '13 at 05:41
  • http://stackoverflow.com/questions/13576676/how-to-parse-complex-json-file-in-android/13576784#13576784 – Abhishek Nandi Aug 06 '13 at 05:45
  • He's just dealing with an API with a terrible spec... If there is only one name it seems to give back a String for that key whereas if there are multiple values, he gets an Object containing all of them... That type of dumb stuff is what SOAP was made for... – Tonithy Aug 06 '13 at 06:02
  • @Pankaj - I referred to the content of the attribute "name", not the whole response. The content of the "name" varies and it can be either String or JSONObject – Ravi G Aug 06 '13 at 06:17

4 Answers4

3

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
}
Heiko Rupp
  • 30,426
  • 13
  • 82
  • 119
2

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;
}
Tonithy
  • 2,300
  • 1
  • 20
  • 20
1

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
Chintan Rathod
  • 25,864
  • 13
  • 83
  • 93
1

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.

onler
  • 63
  • 8