2017-06-13 59 views
0

我的客戶端檢索JSON內容如下:Gson:如果屬性名稱不固定,我如何將內部JSON對象反序列化爲映射?

{ 
    "table": "tablename", 
    "update": 1495104575669, 
    "rows": [ 
     {"column5": 11, "column6": "yyy"}, 
     {"column3": 22, "column4": "zzz"} 
    ] 
} 

rows陣列內容,關鍵是不固定的。我想檢索密鑰和值並使用Gson 2.8.x保存到Map

如何配置Gson以簡單地使用反序列化?

這裏是我的想法:

public class Dataset { 

    private String table; 
    private long update; 
    private List<Rows>> lists; <-- little confused here. 
     or private List<HashMap<String,Object> lists 

    Setter/Getter 
} 
public class Rows { 

    private HashMap<String, Object> map; 

    .... 
} 

Dataset k = gson.fromJson(jsonStr, Dataset.class); 
log.info(k.getRows().size()); <-- I got two null object 

感謝。

回答

1

Gson不支持這種東西。如果你可以修改屬性名稱,那將很好。如果沒有,那麼你可以有幾個選項可能會幫助你。

  • Dataset.lists場只需重命名爲Dataset.rows,如果屬性名是固定的,rows
  • 如果事先知道可能的名稱集,建議Gson使用@SerializedName選擇替代名稱。
  • 如果可能的名稱集是真的未知並且將來可能會更改,則可能需要嘗試使用自定義TypeAdapter(流式傳輸模式;需要更少內存但更難使用)或自定義JsonDeserializer(對象模式;需要更多的內存來存儲中間樹視圖,但它很容易使用)註冊到GsonBuilder

對於選項#2,你可以簡單地添加名字命名的替代品:

@SerializedName(value = "lists", alternate = "rows") 
final List<Map<String, Object>> lists; 

對於選項#3,綁定下游List<Map<String, Object>>類型的適配器試圖動態檢測的名字。請注意,爲了簡單起見,我省略了類的反序列化策略(我相信您可能希望刪除Rows類,轉而使用簡單的Map<String, Object>(另請注意:使用Map,儘量不要指定集合實現 - 散列映射是無序的,但會告訴Gson你要處理Map會讓它選擇一個有序的地圖,如LinkedTreeMap(Gson內部)或LinkedHashMap,這對數據集可能很重要))。

// Type tokens are immutable and can be declared constants 

private static final TypeToken<String> stringTypeToken = new TypeToken<String>() { 
}; 

private static final TypeToken<Long> longTypeToken = new TypeToken<Long>() { 
}; 

private static final TypeToken<List<Map<String, Object>>> stringToObjectMapListTypeToken = new TypeToken<List<Map<String, Object>>>() { 
}; 

private static final Gson gson = new GsonBuilder() 
     .registerTypeAdapterFactory(new TypeAdapterFactory() { 
      @Override 
      public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) { 
       if (typeToken.getRawType() != Dataset.class) { 
        return null; 
       } 
       // If the actual type token represents the Dataset class, then pick the bunch of downstream type adapters 
       final TypeAdapter<String> stringTypeAdapter = gson.getDelegateAdapter(this, stringTypeToken); 
       final TypeAdapter<Long> primitiveLongTypeAdapter = gson.getDelegateAdapter(this, longTypeToken); 
       final TypeAdapter<List<Map<String, Object>>> stringToObjectMapListTypeAdapter = stringToObjectMapListTypeToken); 
       // And compose the bunch into a single dataset type adapter 
       final TypeAdapter<Dataset> datasetTypeAdapter = new TypeAdapter<Dataset>() { 
        @Override 
        public void write(final JsonWriter out, final Dataset dataset) { 
         // Omitted for brevity 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public Dataset read(final JsonReader in) 
          throws IOException { 
         in.beginObject(); 
         String table = null; 
         long update = 0; 
         List<Map<String, Object>> lists = null; 
         while (in.hasNext()) { 
          final String name = in.nextName(); 
          switch (name) { 
          case "table": 
           table = stringTypeAdapter.read(in); 
           break; 
          case "update": 
           update = primitiveLongTypeAdapter.read(in); 
           break; 
          default: 
           lists = stringToObjectMapListTypeAdapter.read(in); 
           break; 
          } 
         } 
         in.endObject(); 
         return new Dataset(table, update, lists); 
        } 
       }.nullSafe(); // Making the type adapter null-safe 
       @SuppressWarnings("unchecked") 
       final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) datasetTypeAdapter; 
       return typeAdapter; 
      } 
     }) 
     .create(); 
final Dataset dataset = gson.fromJson(jsonReader, Dataset.class); 
System.out.println(dataset.lists); 

上面的代碼將打印則:

[{column5 = 11.0,column6 = YYY},{欄3 = 22.0,column4 = ZZZ}]

+0

由於爲了您的回覆,我會盡量按照您的建議解決我的問題。 – user1418973

相關問題