【问题标题】:JSON jsonObject.optString() returns String "null"JSON jsonObject.optString() 返回字符串“null”
【发布时间】:2013-08-16 02:01:17
【问题描述】:

我正在开发一个使用 JSON 进行服务器通信的 Android 应用程序,当我尝试解析我的 json 文件时遇到了一个奇怪的问题。

这是我来自服务器的 json

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

我通过在我的地址 Json 对象上调用 String city = address.optString("city", "") 来获取 City 的值。对于这种情况,我希望 city 为空(这就是 optString 的用途,不是吗?)但实际上它包含字符串“null”。因此,进一步的 null 或 isEmpty 检查将返回 false,因为 String 包含文本。如果我打电话给address.isNull("city"),它会返回 true,这是正确的。只有optString 失败。

我在 Google 或 Stackoverflow 上找不到任何关于此问题的信息。我真的不明白它是如何发生的,因为我认为optString 会完全符合我的预期。有人知道这里出了什么问题吗?

【问题讨论】:

  • null 是 java 中字符串的有效值(以及我知道的所有其他编程语言),所以它不选择后备是有道理的,如果它的键根本不存在,它会采取后备措施
  • 谢谢。这不是我对 optString 的预期行为,但开发人员似乎有不同的想法。必须自己检查。

标签: java android json


【解决方案1】:

遇到这个问题并挠头想“他们真的是这个意思吗?”的不止你一个人。根据 AOSP 问题,Google 工程师确实 认为这是一个错误,但他们必须与 org.json 实现兼容,即使错误兼容。

如果您考虑一下,这是有道理的,因为如果使用相同库的相同代码在其他 Java 环境中运行时在 Android 中的行为不同,则在使用 3rd 方库时会出现严重的兼容性问题。即使意图是好的并且它确实修复了错误,它也会打开一个全新的蠕虫罐。

根据AOSP issue

行为是故意的;我们竭尽全力与 org.json 兼容。现在已经解决了,我们是否也应该修复我们的代码还不清楚。应用程序可能已经开始依赖这种错误的行为。

如果这让您感到悲伤,我建议您使用不同的机制来测试 null,例如 json.isNull()。

这里有一个简单的方法可以帮助你:

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

【讨论】:

  • 为什么在您的自定义方法中调用json.optString(key, null) 而不仅仅是json.getString(key)
  • 辅助方法是optString 的替代品,而不是getStringopt 表示可选,如果key不存在不会抛出异常。
【解决方案2】:

你基本上有两个选择:

1) 发送带有空值的 JSON 负载

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

您必须检查空值并相应地解析它们:

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

2) 不要发送带有空值的键,直接使用 optString(key, null) (应该可以节省带宽)。

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

【讨论】:

  • +1 for json.isNull(key),导致 if(json.get(key) == null) 无法正常工作
  • 注意:如果找不到密钥,json.optString(key) 将返回一个空字符串。
【解决方案3】:

只需将"null" 替换为"",即可摆脱这种情况。

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

【讨论】:

  • 简单而合乎逻辑;)
  • 希望没有包含字符序列'null'的城市
【解决方案4】:

使用 Matt Quigley 的回答作为基础,如果您想模仿 optString 的全部功能,包括后备部分,这里是代码,用 Kotlin 和 Java 编写。

科特林:

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

如果不需要回退,只需为回退参数传入 null。

【讨论】:

    【解决方案5】:
    if (json != null && json.getString(KEY_SUCCESS) != null){
         // PARSE RESULT 
    }else{
        // SHOW NOTIFICIATION: URL/SERVER NOT REACHABLE
    

    }

    那是用there关键字检查json null。

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

    你得到的是 String "null" not null。

    你应该使用

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

    首先检查 isNull()....如果无法正常工作,请尝试以下操作

    你还有 JSONObject.NULL 来检查空值...

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

    在你的情况下还要检查

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

    如果你必须先解析json,然后再处理对象,试试这个

    解析器

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

    处理程序

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

    【讨论】:

      【解决方案6】:

      我的 Josn 解析器很长,必须创建一个新类来解决这个问题, 然后只需要在每个方法中添加 1 行并重命名当前 JSONObject 属性名称,因此所有其他调用都引用我的新类而不是 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;
      }
      

      这是我的课程,里面有我需要的方法,你可以添加更多

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

      }

      【讨论】:

        【解决方案7】:

        如果 key 的值为 null,如下所示

        {
        
          "status": 200,
        
          "message": "",
        
          "data": {
        
            "totalFare": null,
          },
        
        }
        
        check with "isNull" , for Eg:
        
        String strTotalFare;
        
        if (objResponse.isNull("totalFare")) 
        
        {
        
          strTotalFare = "0";
        
        } else {
        
         strTotalFare = objResponse.getString("totalFare");
        
        }
        

        如果键“totalFare”的值为“null”,上述函数将输入 if 并赋值为零,否则它将从键中获取实际值。

        【讨论】:

          【解决方案8】:

          我最终为此创建了一个实用程序类:

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

          【讨论】:

            【解决方案9】:

            我喜欢这样...

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

            【讨论】:

              猜你喜欢
              • 2012-10-09
              • 2015-02-12
              • 1970-01-01
              • 1970-01-01
              • 2020-10-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-07-28
              相关资源
              最近更新 更多