2013-10-03 27 views
1

我使用GSON庫解析服務器JSON響應。後端人有時會告訴我:「我們無法在某些情況下在JSON中指定變量類型」(舊的php,他們不知道如何去做,等等)。 GSON喜歡在其對象模型中強大的打字。所以我不能將Object解析爲字符串。GSON解析未指定的類型變量

GSON等待:

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

但它得到(空數據):

"service": "" 

我也得到

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

什麼是解析這樣的反應最好的做法是什麼?

另一個問題: 我該如何構建對象,它可以識別整數或作爲字符串時不時返回的Integer變量?相同的服務器端問題。

"data": "1" 

"data": 1 

我知道 - 我們應該在Java中使用特定類型。但有時這是值得做出讓步,
感謝

編輯:基於Java開發人員的回答 我的解決辦法。
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(); 
+0

您可以發表您正在使用的代碼反序列化這部分的JSON。 – David

回答

0

如果你想堅持嚴格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); 

我輸入這一切了,所以如果我錯過了一些語法我的道歉。

0

您的JSON是無效的,任何JSON分析器將無法解析一個語法不正確的JSON:這裏提到

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

應該在大括號封裝:

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

json結構包含在{}之內。你的迴應似乎沒有。您可以在字符串的開始和結尾手動追加{},使其成爲有效的json結構。

完成此操作後,您可以使用Gson來正常解析您的json響應。

解析此類響應的最佳做法是什麼?

使用足夠好的Json解析器。這已經足夠了。並嘗試讓一個類表示與響應完全相同的結構,以避免手動解析json響應級別。

+0

感謝您的評論,我的錯 - 我只提供了JSON的內部部分。但這不是問題。 – dimetil

1

在嘗試將它反序列化爲您的Response Java對象之前,您需要先刮掉JSON響應。您可以使用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