【问题标题】:Deserialize nested object with GSON使用 GSON 反序列化嵌套对象
【发布时间】:2016-12-01 20:38:48
【问题描述】:

我正在尝试反序列化以下结构

{ meta: { keywords:  [a, b, c, d]}  ...  }

其他有效结构是

{ meta: { keywords: "a,b,c,d"}  ... }

{ meta: {keywords: "a"}  ...}

我有这门课

public class Data {
   @PropertyName("meta")
   MetaData meta;
   ...
}


public class  MetaData {
    List<String> keywords;
    ...
}

还有一个自定义的反序列化器

public static class CustomDeserilizer implements JsonDeserializer<MetaData>{
    @Override
    public MetaData deserialize(JsonElement json, Type typeOfT,  JsonDeserializationContext context) throws JsonParseException {
        List<String> keywords = null;
        Gson gson = new Gson();
        MetaData metaData = gson.fromJson(json, AppMetaData.class);
        JsonObject jsonObject = json.getAsJsonObject();

        if (jsonObject.has("keywords")) {
            JsonElement elem = jsonObject.get("keywords");
            if (elem != null && !elem.isJsonNull()) {

                if (jsonObject.get("keywords").isJsonArray()) {
                    keywords = gson.fromJson(jsonObject.get("keywords"),   new TypeToken<List<String>>() {
                    }.getType());
                } else {
                    String keywordString = gson.fromJson(jsonObject.get("keywords"), String.class);
                    keywords = new ArrayList<String>();
                    list.addAll(Arrays.asList(keywordString.split(",")));
                }
            }
        }
       metaData.setKeywords(keywords);
}

然后我尝试应用脱硫剂:

Gson gson = new GsonBuilder()              
        .registerTypeAdapter(Data.class,new CustomDeserilizer())               
        .create();

但是我得到一个解析错误,因为我试图反序列化数据而不是元数据,我怎样才能应用这个反序列化器使它正常工作?

【问题讨论】:

    标签: java gson json-deserialization android


    【解决方案1】:

    我解决了这个问题,为我的数据类创建了一个反序列化器。

    public static class DataDeserilizer implements JsonDeserializer {
        @Override
        public Data deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    
            Gson gson = new Gson();
            Data data = gson.fromJson(json, Data.class);
            JsonObject jsonObject = json.getAsJsonObject();
            if (jsonObject.has("meta")) {
                JsonElement elem = jsonObject.get("meta");
                if (elem != null && !elem.isJsonNull()) {
    
                    Gson gsonDeserializer = new GsonBuilder()
                            .registerTypeAdapter(MetaData.class, new CustomDeserilizer())
                            .create();
                    gsonDeserializer.fromJson(jsonObject.get("meta"), Data.class);
                }
            }
    
            return data;
        }
    
    
    
    }
    

    还有

    Gson gson = new GsonBuilder()              
        .registerTypeAdapter(Data.class,new DataDeserilizer())               
        .create();
    

    很明显,但有更优雅的解决方案吗?

    【讨论】:

      【解决方案2】:

      首先,将您的类重命名为 meta 而不是 metadata 并使用关键字 String 而不是 List。然后使用以下内容将您的 JSonString 映射到您的对象中。

      Gson gson = new GsonBuilder().create();
      Meta meta = gson.from(yourJsonString,Meta.class);
      

      为了只获取关键字,你需要这个。

      JsonObject jsonObject = new JsonObject(yourJSonString);
      String data = jsonObject.getJsonObject("meta").getString("keywords");
      

      keywords 是 JsonObject 而不是 JsonArray 所以你不能直接映射它 到列表中。您可以拆分字符串以获取数组中的关键字。

      String keywords[] = data.split(",");
      

      【讨论】:

      • String keywords[] = data.split(","); 是一个非常糟糕的想法,您应该永远使用它。如果数据有新行或多余的空格怎么办?您应该始终使用与 JSON 标准完全兼容的方法对数据进行解码。此方法将无法解码(或更糟的是,解码不正确)有效 JSON 的数据。
      【解决方案3】:

      这是一个简洁的解决方案,它利用 Java 继承来表示嵌套结构;因此不需要提供任何实际的实例成员字段(映射等)来捕获 GSON 映射的嵌套 String 数据。

      第 1 步:为了便于阅读,创建一个空对象来表示嵌套映射

      public class StateRegionCitiesMap extends HashMap<String, List<String>> {
      
      }
      

      第二步:添加一行实际代码做映射; 没有其他需要管理的序列化/反序列化逻辑

      protected void loadContent(JsonObject stateRegionsJsonObject) {
      
          HashMap<String, StateRegionCitiesMap> stateRegionCitiesMap =
                  mGson.fromJson(
                          stateRegionsJsonObject,
                          new TypeToken<HashMap<String, StateRegionCitiesMap>>() {
                          }.getType()
                  );
      }
      

      或者,您可以完全跳过包装类,直接将&lt;String, List&lt;String&gt;&gt; 放入 GSON 调用中。但是,我发现一个明确的对象有助于告知/提醒正在阅读代码的人,目的是什么。


      示例 JSON:

      StateRegionCitiesMap 类表示多层映射结构:

      [US State] -> [State-Region Key] -> [Sub-Region Key] -> CitiesArray[]

      "CA": {
        "Central CA": {
          "Central Valley": [
            "FRESNO",
            "VISALIA"
          ],
          "Sacramento Area": [
            "SACRAMENTO",
            "EL DORADO HILLS"
          ]
        },
      

      【讨论】:

        猜你喜欢
        • 2013-09-05
        • 2023-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多