JSON jsonObject.optString() returns String "null"

JavaAndroidJson

Java Problem Overview


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 cityto 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 Stackoverflow 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?

Java Solutions


Solution 1 - Java

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);
}

Solution 2 - Java

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

Solution 3 - Java

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

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

Solution 4 - Java

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.

Solution 5 - Java

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

Solution 6 - Java

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.

Solution 7 - Java

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);
    }
}

}

Solution 8 - Java

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

Solution 9 - Java

I do like this...

String value; 

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

      

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjoschplusaView Question on Stackoverflow
Solution 1 - JavaMatt QuigleyView Answer on Stackoverflow
Solution 2 - Javadev.serghiniView Answer on Stackoverflow
Solution 3 - JavaSunit Kumar SamantaView Answer on Stackoverflow
Solution 4 - JavaBret SmithView Answer on Stackoverflow
Solution 5 - Javabhanu Prakash DaveView Answer on Stackoverflow
Solution 6 - JavaDigvijay MachaleView Answer on Stackoverflow
Solution 7 - JavaGaleenView Answer on Stackoverflow
Solution 8 - JavaVPZView Answer on Stackoverflow
Solution 9 - JavabsgdragaoView Answer on Stackoverflow