2013-01-24 24 views
11

我想修改json內容而不將其轉換爲POJO。我正在使用GSON Library。使用GSON修改json而不使用POJO

以下是用例:

String jsonString = "[{\"key1\":\"Hello\",\"key2\":\"World\"},{\"key1\":\"Nice\",\"key2\":\"Town\"}]"; 

JsonElement jsonElement = gson.fromJson(jsonString, JsonElement.class);  

有什麼辦法,我可以每個數組中設置爲key1值在一定值(比方說「測試」),無需轉換東西放進POJO

回答

1

一種方法是將JSON轉換爲java.util.Map,修改Map並從那裏開始(這可能意味着將Map序列化回JSON)。

這種方法符合我的偏好,使用正確的API處理正確的工作,最大限度地減少像Gson這樣的工具的使用,以處理序列化/反序列化(這正是我所理解的目的)。也就是說,不要將Gson API用作替代數據結構。

+0

如何將JSON轉換爲Map? – linuxeasy

0

GSON有兩個獨立的API(可以合併):一個用於序列化和反序列化,另一個用於流式傳輸。如果要處理JSON流沒有內存開銷或使用動態結構(而不​​是靜態的POJO),你可以這樣做:

  • 創建JsonWriter(在我的例子中,我使用的StringWriter);
  • 創建一個JsonReader;
  • 做一個循環,從讀者消費事件,並將其反饋給作家,有可能更改,添加,刪除等

循環將包括一個switch語句中必須有一個情況下,所有的可能的事件(其中10個)。即使最簡單的例子也必須包含所有這些,所以下面的代碼看起來很冗長。但擴展很容易,進一步的擴展不會讓時間更長。

該追加「測試」的一個例子:1對每個對象看起來像:

public class Whatever { 

static void streamandmodify(JsonReader reader, JsonWriter writer) throws IOException { 
    while (true) { 
     JsonToken token = reader.peek(); 
     switch (token) { 
     // most cases are just consume the event 
     // and pass an identical one to the writer 
     case BEGIN_ARRAY: 
      reader.beginArray(); 
      writer.beginArray(); 
      break; 
     case END_ARRAY: 
      reader.endArray(); 
      writer.endArray(); 
      break; 
     case BEGIN_OBJECT: 
      reader.beginObject(); 
      writer.beginObject(); 

      // this is where the change happens: 
      writer.name("test"); 
      writer.value(1); 
      break; 
     case END_OBJECT: 
      reader.endObject(); 
      writer.endObject(); 
      break; 
     case NAME: 
      String name = reader.nextName(); 
      writer.name(name); 
      break; 
     case STRING: 
      String s = reader.nextString(); 
      writer.value(s); 
      break; 
     case NUMBER: 
      String n = reader.nextString(); 
      writer.value(new BigDecimal(n)); 
      break; 
     case BOOLEAN: 
      boolean b = reader.nextBoolean(); 
      writer.value(b); 
      break; 
     case NULL: 
      reader.nextNull(); 
      writer.nullValue(); 
      break; 
     case END_DOCUMENT: 
      return; 
     } 
    } 
} 


public static void main(String[] args) throws IOException { 
    // just for test: 
    JsonReader jr = new JsonReader(new StringReader("{\"a\":1, \"b\":{\"c\":[1,2,3,{},{}]}}")); 
    StringWriter sw = new StringWriter(); 
    JsonWriter jw = new JsonWriter(sw); 
    streamandmodify(jr, jw); 
    System.out.println(sw.getBuffer().toString()); 
} 
} 
+0

JsonWriter可以做的很好的例子,這是肯定的。但是對於OP的任務,沒有理由通過流重新創建JSON對象,而不是使用經過良好測試的gson.fromJson()。看傑夫的答案。 – teejay

+0

@teejay:「沒理由」?你怎麼知道的?爲什麼這樣評論?我可以找到一些非常好的理由,不建立一個任意大的JSON文檔的完整內存表示,只是爲了添加一些屬性,比如將整個事件序列化迴文件。我們都不瞭解這個問題的背景,所以流水和粗野的做法似乎可能會更好。 – fdreger

+0

嗯,我認爲這個頁面的人想要解決他們的問題 - 即從已經完全可用的字符串中修改JSON(=沒有流式傳輸的理由)。你的答案「有效」,但在另一方面更合適。沒有冒犯:) – teejay

0

的jsonString是一個普通的,通常的Java的字符串;所以你可以修改爲任何你喜歡使用Java的標準字符串函數與Test1替換子key1

jsonString = "[{\"key1\":\"Test\",\"key2\":\"World\"},{\"key1\":\"Nice\",\"key2\":\"Town\"}]"; 

當然,串在Java中是不可變的那麼首先將其轉換成一個StringBuilder將可能給你一個在內存使用方面性能更好。

+2

在測試代碼中,這是一個體面的,如果是hacky的策略,但是如果原始或字符串或替換是用戶提供的,則在生產時要小心。 JavaScript(以及擴展的JSON)在處理轉義和特殊字符方面非常複雜。您可能想要讓經過良好測試的庫在生產中編輯您的JSON。 –

+0

也許你有錯的問題。我有興趣修改key1的值而不是key1本身。所以在第一種情況下,key1的值是Hello,我希望修改它。 – linuxeasy

+0

哦,答案依舊;這只是必須改變的例子。 – SylvainL

1

您總是可以獲取與JsonElement不同的類型,或者使用JsonElement.getAsJsonObject將其轉換爲Object(如果可能)。

String jsonString = "[{\"key1\":\"Hello\",\"key2\":\"World\"}, ...]"; 

JsonArray jsonArray = gson.fromJson(jsonString, JsonElement.class).getAsJsonArray(); 
JsonObject firstObject = jsonArray.get(i).getAsJsonObject(); 
firstObject.addProperty("key1", "Test"); 

我以前錯了;似乎沒有JsonArray適配器;你必須得到一個JsonElement並使用這個工具。

6

這是我想出的最短的。

JsonElement je = gson.fromJson(jsonString, JsonElement.class); 
JsonObject jo = je.getAsJsonObject(); 
jo.add("key", value); 

一旦你有了JsonObject,gson就有很多方法來操作它。