80

I'm developing an Android App which uses JSON for the server communication and I've got a weird problem when I'm trying to parse my json file.

This is my json from the server

{
    "street2": null,
    "province": null,
    "street1": null,
    "postalCode": null,
    "country": null,
    "city": null
}

I'm getting the value for City by calling String city = address.optString("city", "") on my address Json-object. For this situation I'm expecting city to be empty (that's what optString is here for isn't it?) but in fact it contains the String "null". So further null- or isEmpty-checks will return false as the String contains text. If I call address.isNull("city") it returns true which is correct. Only optString fails.

I couldn't find anything on Google or Stack Overflow for this problem. I don't really understand how it can happen as I thought optString would do exactly what I expected. Anybody knows what's going wrong here?

2
  • 2
    null is a valid value for a string in java (and every other programming language i know), so it makes sense that it doesnt choose the fallback, if it the key would simply not exist, it would take the fallback Commented Aug 14, 2013 at 8:09
  • Thanks. It's not the behaviour I expected from optString but it seems that the developer had something different in mind. Have to do the check by myself. Commented Aug 14, 2013 at 11:44

10 Answers 10

124

You're not alone in running into this problem and scratching your head, thinking "Could they really have meant this?" According to an AOSP issue, the Google engineers did consider this a bug, but they had to be compatible with the org.json implementation, even bug-compatible.

If you think about it, it makes sense, because if the same code which uses the same libraries run in other Java environments behaves differently in Android, there would be major compatibility problems when using 3rd party libraries. Even if the intentions were good and it truly fixed bugs, it would open up a whole new can of worms.

According to the AOSP issue:

The behavior is intentional; we went out of our way to be bug-compatible with org.json. Now that that's fixed, it's unclear whether we should fix our code as well. Applications may have come to rely on this buggy behavior.

If this is causing you grief, I recommend you workaround by using a different mechanism to test for null, such as json.isNull().

Here's a simple method to help you out:

/** Return the value mapped by the given key, or {@code null} if not present or null. */
public static String optString(JSONObject json, String key)
{
    // http://code.google.com/p/android/issues/detail?id=13830
    if (json.isNull(key))
        return null;
    else
        return json.optString(key, null);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Why call json.optString(key, null) and not just json.getString(key) in your custom method?
The helper method is a replacement for optString not getString. opt means optional and will not throw an exception if the key does not exist.
25

You basically have 2 choices:

1) Send a JSON payload with null values

{
"street2": "s2",
"province": "p1",
"street1": null,
"postalCode": null,
"country": null,
"city": null
}

You will have to check for null values and parse them accordingly:

private String optString_1(final JSONObject json, final String key) {
    return json.isNull(key) ? null : json.optString(key);
}

2) Do not send the keys with null values and use optString(key, null) directly (should save you bandwidth).

{
"street2": "s2",
"province": "p1"
}

2 Comments

+1 for json.isNull(key), cause if(json.get(key) == null) is not working properly
Be careful: json.optString(key) will return an empty string if the key isn't found.
1

Using Matt Quigley's answer as a basis, here is the code if you desire to mimic the full functionality of optString, including the fallback portion, written in Kotlin and Java.

Kotlin:

fun optString(json: JSONObject, key: String, fallback: String?): String? {
    var stringToReturn = fallback
    if (!json.isNull(key)) {
        stringToReturn = json.optString(key, null)
    }
    return stringToReturn
}

Java:

public static String optString(JSONObject json, String key, String fallback) {
    String stringToReturn = fallback;
    if (!json.isNull(key)) {
        stringToReturn = json.optString(key, null);
    }
    return stringToReturn;
 }

Simply pass in null for the fallback parameter if you don't need the fallback.

Comments

1

Got rid off this situation by simply replacing "null" with "".

String city = address.optString("city").replace("null", "");

3 Comments

simple and logical ;)
hopefully there is no city that contains the character sequence 'null'
This is a very wrong answer as can lead to many unseen consequences.
1

I ended up creating a utility class for this purpose:

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

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

final public class JsonUtil {
    
    @Nullable
    public static String optString(
            @NonNull JSONObject object,
            @NonNull String key
    ) throws JSONException {
        if (object.has(key) && !object.isNull(key)) {
            return object.getString(key);
        }
        
        return null;
    }
}

Comments

1

I do like this...

String value; 

 if(jsonObject.get("name").toString().equals("null")) {
  value = ""; 
 }else {
  value = jsonObject.getString("name"); 
 }

      

1 Comment

what if "name" in the jsonObject itself is absent as the key , if block will throw an exception. Assuming that is the case , OptString is being used here.
0
if (json != null && json.getString(KEY_SUCCESS) != null){
     // PARSE RESULT 
}else{
    // SHOW NOTIFICIATION: URL/SERVER NOT REACHABLE

}

that is for checking json null with there key word.

JSONObject json = new JSONObject("{\"hello\":null}");
json.getString("hello");

this you get is String "null" not null.

your shoud use

if(json.isNull("hello")) {
    helloStr = null;
} else {
    helloStr = json.getString("hello");
}

first check with isNull()....if cant work then try belows

and also you have JSONObject.NULL to check null value...

 if ((resultObject.has("username")
    && null != resultObject.getString("username")
    && resultObject.getString("username").trim().length() != 0)
    {
           //not null
    }

and in your case also check

resultObject.getString("username").trim().eqauls("null")

If you must parse json first and handle object later, let try this

Parser

Object data = json.get("username");

Handler

 if (data instanceof Integer || data instanceof Double || data instanceof Long) {
        // handle number ;
  } else if (data instanceof String) {
        // hanle string;               
  } else if (data == JSONObject.NULL) {
        // hanle null;                 
  }

Comments

0

My Josn parser was long and had to create a new class to fix that, then just had to add 1 extra line in each method and rename current JSONObject property name, so all other calls were referencing to my new class instead to JSONObject.

    public static ArrayList<PieceOfNews> readNews(String json) {
    if (json != null) {
        ArrayList<PieceOfNews> res = new ArrayList<>();
        try {
            JSONArray jsonArray = new JSONArray(json);
            for (int i = 0; i < jsonArray.length(); i++) {
                //before JSONObject jo = jsonArray.getJSONObject(i);
                JSONObject joClassic = jsonArray.getJSONObject(i);
                //facade
                FixJsonObject jo = new FixJsonObject(joClassic);
                PieceOfNews pn = new PieceOfNews();
                pn.setId(jo.getInt("id"));
                pn.setImageUrl(jo.getString("imageURL"));
                pn.setText(jo.getString("text"));
                pn.setTitle(jo.getString("title"));
                pn.setDate(jo.getLong("mills"));
                res.add(pn);
            }
            return res;
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    return null;
}

Here is my class with the methods I needed, you can add more

public class FixJsonObject {
private JSONObject jsonObject;

public FixJsonObject(JSONObject jsonObject) {
    this.jsonObject = jsonObject;
}

public String optString(String key, String defaultValue) {
    if (jsonObject.isNull(key)) {
        return null;
    } else {
        return jsonObject.optString(key, defaultValue);
    }
}

public String optString(String key) {
    return optString(key, null);
}

public int optInt(String key) {
    if (jsonObject.isNull(key)) {
        return 0;
    } else {
        return jsonObject.optInt(key, 0);
    }
}

public double optDouble(String key) {
    return optDouble(key, 0);
}

public double optDouble(String key, double defaultValue) {
    if (jsonObject.isNull(key)) {
        return 0;
    } else {
        return jsonObject.optDouble(key, defaultValue);
    }
}

public boolean optBoolean(String key, boolean defaultValue) {
    if (jsonObject.isNull(key)) {
        return false;
    } else {
        return jsonObject.optBoolean(key, defaultValue);
    }
}

public long optLong(String key) {
    if (jsonObject.isNull(key)) {
        return 0;
    } else {
        return jsonObject.optLong(key, 0);
    }
}

public long getLong(String key) {
    return optLong(key);
}

public String getString(String key) {
    return optString(key);
}

public int getInt(String key) {
    return optInt(key);
}

public double getDouble(String key) {
    return optDouble(key);
}

public JSONArray getJSONArray(String key) {
    if (jsonObject.isNull(key)) {
        return null;
    } else {
        return jsonObject.optJSONArray(key);
    }
}

}

Comments

0

If values for key is null like below

{

  "status": 200,

  "message": "",

  "data": {

    "totalFare": null,
  },

}

check with "isNull" , for Eg:

String strTotalFare;

if (objResponse.isNull("totalFare")) 

{

  strTotalFare = "0";

} else {

 strTotalFare = objResponse.getString("totalFare");

}

if value is "null" for key "totalFare", above function will enter in if and assign value zero else it will get actual value from key.

Comments

0

I recently encountered this and here is my Kotlin extension version of optString

fun JSONObject.optString1(key: String, fallback: String): String{
    if(isNull(key)){
        return fallback
    }
    return getString(key)
}

If the key is null, it would return the fallback string otherwise it would return the value of that key.

One certain advantage is you can directly replace your obj.optString method calls with obj.optString1

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.