The hack looks okay for your situation.
The other option would be to use the method boolean isNull(String key) and then based on the returned boolean value proceed with your option. Something like:
public String getMessageFromServer(JSONObject response) {
return ((response.has("message") && !response.isNull("message"))) ? response.getString("message") : null;
}
But then, I don't think there's much of a difference between the your current implementation and this.
Answer from Sujay on Stack OverflowThe hack looks okay for your situation.
The other option would be to use the method boolean isNull(String key) and then based on the returned boolean value proceed with your option. Something like:
public String getMessageFromServer(JSONObject response) {
return ((response.has("message") && !response.isNull("message"))) ? response.getString("message") : null;
}
But then, I don't think there's much of a difference between the your current implementation and this.
This is easy to solve when using Kotlin class extensions:
fun JSONObject.optNullableString(name: String, fallback: String? = null) : String? {
return if (this.has(name) && !this.isNull(name)) {
this.getString(name)
} else {
fallback
}
}
Then e.g. name will be null in:
val name : String? = JSONObject("""{"id": "foo", "name":null}""").optNullableString("name")
In a JSON "object" (aka dictionary), there are two ways to represent absent values: Either have no key/value pair at all, or have a key with the JSON value null.
So you either use .add with a proper value what will get translated to null when you build the JSON, or you don't have the .add call.
It is a JSON-B design deficiency. They could have done something slick like:
Json.createObjectBuilder().addIfNotNull("address", this.getAddress());
Json.createObjectBuilder().add("address", this.getAddress(), defaultOnNull);
None of the other answers worked, and I ended up questioning whether the element was really null despite looking at the parsed json data via an online tool. In the end, JSONObject.IsNull(element mapping name) is the right approach.
you must check value with key is has in json object. Try below code:
JSONObject initial = new JSONObject(data);
if(initial.has(nextObjSTR)) {
String next = initial.getString(nextObjSTR);
if (next != null && !next.isEmpty()) {
makeConnection(Uri.parse(next));
}
}
You can use get() instead of getString(). This way an Object is returned and JSONObject will guess the right type. Works even for null.
Note that there is a difference between Java null and org.json.JSONObject$Null.
CASE 3 does not return "nothing", it throws an Exception. So you have to check for the key to exist (has(key)) and return null instead.
public static Object tryToGet(JSONObject jsonObj, String key) {
if (jsonObj.has(key))
return jsonObj.opt(key);
return null;
}
EDIT
As you commented, you only want a String or null, which leads to optString(key, default) for fetching. See the modified code:
package test;
import org.json.JSONObject;
public class Test {
public static void main(String[] args) {
// Does not work
// JSONObject jsonObj = {"a":"1","b":null};
JSONObject jsonObj = new JSONObject("{\"a\":\"1\",\"b\":null,\"d\":1}");
printValueAndType(getOrNull(jsonObj, "a"));
// >>> 1 -> class java.lang.String
printValueAndType(getOrNull(jsonObj, "b"));
// >>> null -> class org.json.JSONObject$Null
printValueAndType(getOrNull(jsonObj, "d"));
// >>> 1 -> class java.lang.Integer
printValueAndType(getOrNull(jsonObj, "c"));
// >>> null -> null
// throws org.json.JSONException: JSONObject["c"] not found. without a check
}
public static Object getOrNull(JSONObject jsonObj, String key) {
return jsonObj.optString(key, null);
}
public static void printValueAndType(Object obj){
System.out.println(obj + " -> " + ((obj != null) ? obj.getClass() : null));
}
}
you can use optString("c") or optString("c", null)
as stated in the documentation
Use .has(String) and .isNull(String)
A conservative usage could be;
if (record.has("my_object_name") && !record.isNull("my_object_name")) {
// Do something with object.
}
It might be little late(it is for sure) but posting it for future readers
You can use JSONObject optJSONObject (String name) which will not throw any exception and
Returns the value mapped by name if it exists and is a JSONObject, or null otherwise.
so you can do
JSONObject obj = null;
if( (obj = result.optJSONObject("ERROR"))!=null ){
// it's an error , now you can fetch the error object values from obj
}
or if you just want to test nullity without fetching the value then
if( result.optJSONObject("ERROR")!=null ){
// error object found
}
There is whole family of opt functions which either return null or you can also use the overloaded version to make them return any pre-defined values.
e.g
String optString (String name, String fallback)
Returns the value mapped by name if it exists, coercing it if necessary, or fallback if no such mapping exists.
where coercing mean, it will try to convert the value into String type
A modified version of the @TheMonkeyMan answer to eliminate redundant look-ups
public void processResult(JSONObject result) {
JSONObject obj = null;
if( (obj = result.optJSONObject("ERROR"))!=null ){
//^^^^ either assign null or jsonobject to obj
// if not null then found error object , execute if body
String error_detail = obj.optString("DESCRIPTION","Something went wrong");
//either show error message from server or default string as "Something went wrong"
finish(); // kill the current activity
}
else if( (obj = result.optJSONObject("STATISTICS"))!=null ){
String stats = obj.optString("Production Stats");
//Do something
}
else
{
throw new Exception("Could not parse JSON Object!");
}
}
IJsonValue idValue = itemObject.GetNamedValue("id");
if ( idValue.ValueType == JsonValueType.Null)
{
// is Null
}
else if (idValue.ValueType == JsonValueType.String)
{
string id = idValue.GetString();
}
If you do this too much, consider adding extension methods.
To do the opposite use:
IJsonValue value = JsonValue.CreateNullValue();
Read here more about null values.
http://msdn.microsoft.com/en-us/library/ms173224.aspx
The ?? operator is called the null-coalescing operator. It returns the left-hand operand if the operand is not null; otherwise it returns the right hand operand.
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);
}
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"
}