【问题标题】:GSON parsing unspecified type variableGSON解析未指定的类型变量
【发布时间】:2013-10-03 16:34:10
【问题描述】:

我使用 GSON 库解析服务器 JSON 响应。后端人员有时会告诉我:“由于某种原因,我们无法在 JSON 中指定变量类型”(旧的 php,他们不知道该怎么做等等)。 GSON 喜欢在其对象模型中使用强类型。所以我无法将 Object 解析为 String。

GSON 等待:

{
    "service":{
        "description":null,
        "name":"Base",
        "id":"4c7a90410529"
    }
}

但它得到(空数据):

"service": ""

我得到了

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1396

解析此类响应的最佳做法是什么?

另一个问题: 如何构建对象,它可以将不时返回的整数变量识别为整数或字符串?同样的服务器端问题。

"data": "1"

"data": 1

我知道 - 我们应该在 Java 中使用特定类型。但有时做出让步是值得的,
谢谢

编辑: 我的解决方案基于 Java Developer's answer。
ServiceDeserializer 类根据其内部值反序列化每个对象。

public class ServiceDeserializer implements JsonDeserializer<ServiceState>{

    @Override
    public ServiceState deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        String name = "";
        String uuid = "";
        String description = "";

        if (json.isJsonObject()) {
            JsonObject obj = json.getAsJsonObject();

            if (!obj.get("name").isJsonNull()) {
                name = obj.get("name").getAsString();
            }
            if (!obj.get("uuid").isJsonNull()) {
                uuid = obj.get("uuid").getAsString();
            }
            if (!obj.get("description").isJsonNull()) {
                description = obj.get("description").getAsString();
            }
        }
        return new ServiceState(name, uuid, description);
    }

}

还有我的带有 ServiceState 类型适配器的 GSON 构造函数。

Gson gson = new GsonBuilder()
    .registerTypeAdapter(ServiceState.class, new ServiceDeserializer())
    .create();

【问题讨论】:

  • 能否请您发布您用于反序列化这部分 JSON 的代码。

标签: java android json parsing gson


【解决方案1】:

您需要先抓取 JSON 响应,然后再尝试将其反序列化为您的 Response Java 对象。您可以使用 Java org.json 解析器来验证 service 对象是否确实存在并修复它。

String json = "{\"service\":{\r\n" + 
        "    \"description\":null,\r\n" + 
        "    \"name\":\"Base\",\r\n" + 
        "    \"id\":\"4c7a90410529\"\r\n" + 
        "}}";
String json2 = "{\"service\":\"\"}";

JSONObject root = new JSONObject(json);
// JSONObject root = new JSONObject(json2);
if (root.optJSONObject("service") == null) {
    root.put("service", new JSONObject());
}

Gson gson = new Gson();
Response response = gson.fromJson(root.toString(), Response.class);

System.out.println(response.getService());

输出

// for JSONObject root = new JSONObject(json);
Service [id=4c7a90410529, name=Base, description=null]

// for JSONObject root = new JSONObject(json2);
Service [id=null, name=null, description=null]

其次,Gson 足够聪明,可以进行简单的转换,例如 StringInteger 等。因此,反序列化此类 JSON 属性应该不会给您带来任何麻烦。

System.out.println(gson.fromJson("10", Integer.class)); // 10
System.out.println(gson.fromJson("\"20\"", Integer.class)); // 20

【讨论】:

    【解决方案2】:

    如果您想严格遵守gson,您可以提供自定义deserializer。由于我们知道service 要么是基本json 字符串的属性,要么嵌入在其他一些property 中,我们可以使用反序列化器逐步解析出有问题的组件并相应地处理它们。

     public class MyJsonDeserializer implements JsonDeserializer<YourParsedData> {
    
       @Override 
       public YourParsedData deserialize(final JsonElement je, final Type type, final JsonDeserialization Context jdc) throws JsonParseException
       {
          final JsonObject obj = je.getAsJsonObject(); //our original full json string
          final JsonElement serviceElement = obj.get("service");
    
    
         //here we provide the functionality to handle the naughty element. It seems emtpy string is returned as a JsonPrimitive... so one option
         if(serviceElement instanceOf JsonPrimitive)
         {
           //it was empty do something
         }
    
         return YourParsedData.create(); //provide the functionality to take in the parsed data
       }
     }
    

    自定义反序列化器的调用方式如下:

     final Gson gson = new GsonBuilder().registerTypeAdapter(YourParsedData.class, new MyJsonDeserializer()).create();
     gson.fromJson("{service: ''}", YourParsedData.class);
    

    所有这些都是我输入的,所以如果我错过了一些语法,我深表歉意。

    【讨论】:

      【解决方案3】:

      您的 json 无效,任何 Json 解析器都无法解析语法错误的 json:

         "service": {
              "description": null,
              "name": "Base",
              "id": "4c7a90410529"
          }
      

      应封装在大括号中,如此处所述:

      {
          "service": {
              "description": null,
              "name": "Base",
              "id": "4c7a90410529"
          }
      }
      

      【讨论】:

        【解决方案4】:

        一个 json 结构包含在 {} 中。您的回复似乎缺少这一点。您可以在字符串的开头和结尾手动追加{},使其成为有效的json结构。

        完成此操作后,您可以使用 Gson 正常解析您的 json 响应。

        解析此类响应的最佳做法是什么?

        使用足够好的 Json 解析器。这绰绰有余。并尝试让一个类表示与响应完全相同的结构,以避免手动逐级解析 json 响应。

        【讨论】:

        • 感谢您的评论,我的错 - 我只提供了 JSON 的内部部分。但这不是问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-30
        相关资源
        最近更新 更多