【问题标题】:Gson custom deseralizer for one variable in an object对象中一个变量的 Gson 自定义解串器
【发布时间】:2011-05-16 08:15:12
【问题描述】:

我的问题示例:

我们有一个 Apple 的对象类型。苹果有一些成员变量:

String appleName; // The apples name
String appleBrand; // The apples brand
List<Seed> seeds; // A list of seeds the apple has

种子对象如下所示。

String seedName; // The seeds name
long seedSize; // The size of the seed

现在当我得到一个苹果对象时,一个苹果可能有多个种子,或者它可能有一个种子,或者可能没有种子!

带有一个种子的 JSON 苹果示例:

{
"apple" : {
   "apple_name" : "Jimmy", 
   "apple_brand" : "Awesome Brand" , 
   "seeds" : {"seed_name":"Loopy" , "seed_size":"14" }
  }
}

带有两个种子的 JSON 苹果示例:

{
"apple" : {
   "apple_name" : "Jimmy" , 
   "apple_brand" : "Awesome Brand" , 
   "seeds" : [ 
      { 
         "seed_name" : "Loopy",
         "seed_size" : "14"
      },
      {
         "seed_name" : "Quake",
         "seed_size" : "26"
      } 
  ]}
}

现在这里的问题是第一个示例是用于种子的 JSONObject,第二个示例是用于种子的 JSONArray。现在我知道它不一致的 JSON 并且修复它的最简单方法是修复 JSON 本身,但不幸的是我从其他人那里获取 JSON,所以我无法修复它。解决此问题的最简单方法是什么?

【问题讨论】:

  • 您在哪里找到了用于苹果和种子的 JSON api? :P

标签: java json gson


【解决方案1】:

您需要为Apple 类型注册一个自定义类型适配器。在类型适配器中,您将添加逻辑以确定是否给您一个数组或单个对象。使用该信息,您可以创建 Apple 对象。

除了下面的代码,修改您的 Apple 模型对象,以便不会自动解析 seeds 字段。将变量声明更改为:

private List<Seed> seeds_funkyName;

代码如下:

GsonBuilder b = new GsonBuilder();
b.registerTypeAdapter(Apple.class, new JsonDeserializer<Apple>() {
    @Override
    public Apple deserialize(JsonElement arg0, Type arg1,
        JsonDeserializationContext arg2) throws JsonParseException {
        JsonObject appleObj = arg0.getAsJsonObject();
        Gson g = new Gson();
        // Construct an apple (this shouldn't try to parse the seeds stuff
        Apple a = g.fromJson(arg0, Apple.class);
        List<Seed> seeds = null;
        // Check to see if we were given a list or a single seed
        if (appleObj.get("seeds").isJsonArray()) {
            // if it's a list, just parse that from the JSON
            seeds = g.fromJson(appleObj.get("seeds"),
                    new TypeToken<List<Seed>>() {
                    }.getType());
        } else {
            // otherwise, parse the single seed,
            // and add it to the list
            Seed single = g.fromJson(appleObj.get("seeds"), Seed.class);
            seeds = new ArrayList<Seed>();
            seeds.add(single);
        }
        // set the correct seed list
        a.setSeeds(seeds);
        return a;
    }
});

有关更多信息,请参阅Gson guide

【讨论】:

  • 我遇到了同样的问题,我尝试了上面的代码,但我在这一行遇到了一个异常 "// 构造一个苹果(这不应该尝试解析种子苹果 a = g.fromJson(arg0, Apple.class);”,错误是“预期 BEGIN_ARRAY 但是 BEGIN_OBJECT”,你能帮我解决这个问题吗
  • 非常好的答案,但我得到了与@Sam 相同的错误。我通过创建new() Apple、设置seeds 以及之后的其他字段来绕过它。
  • @SatelliteSD 你能分享你的sn-p吗?
  • 这节省了我几个小时的工作时间。如果可以的话,会给+10票:)
  • 不要在适配器内部初始化 Gson!改用 arg2.fromJson(...) !
【解决方案2】:

我遇到了同样的问题。我认为我的解决方案更简单,更通用:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(List.class, new JsonSerializer<List<?>>() {
            @Override
            public JsonElement serialize(List<?> list, Type t,
                    JsonSerializationContext jsc) {
                if (list.size() == 1) {
                    // Don't put single element lists in a json array
                    return new Gson().toJsonTree(list.get(0));
                } else {
                    return new Gson().toJsonTree(list);
                }
            }
        }).create();

当然,我同意原发帖者,最好的办法是改json。大小为 1 的数组没有任何问题,它会使序列化和反序列化变得更加简单!不幸的是,有时这些更改是您无法控制的。

【讨论】:

  • 不知道谁给这篇文章 1 分,但问题是关于反序列化,但这是一个序列化程序。
【解决方案3】:

我们在 GSON 中使用数组而不是列表,并且不存在这样的问题:查看http://app.ecwid.com/api/v1/1003/product?id=4064“类别”属性实际上是一个只有一个元素的 Javascript 数组。它是这样声明的:

Category[] 类别;

更新:使用 TypeToken 和自定义序列化可能会有所帮助,请参阅此文档:https://sites.google.com/site/gson/gson-user-guide

【讨论】:

  • 请注意“[”,它将它声明为一个数组。现在请注意,在我的示例中,只有一个种子,没有“[”。
  • 我的意思是用 Seed[] 种子替换 List 种子应该会有所帮助
  • 试过了。给我这个异常“com.google.gson.JsonObject 不能转换为 com.google.gson.JsonArray”
【解决方案4】:

如果您无法更改 JSON(从其他人那里获取),那么最简单的解决方案是更改 Java 类中的 Apple 和 Seed 类变量名称,使其与解析的 JSON 匹配。

改成:

Apple Class
-----------
String apple_name; // The apples name
String apple_brand; // The apples brand
List<Seed> seeds; // A list of seeds the apple has
And the seed object looks as follows.

Seed Class
-----------
String seed_name; // The seeds name
long seed_size; // The size of the seed

【讨论】:

  • 仔细看JSON,第一种情况下它只是Object,但是它是Array。所以这并不能解决问题。您必须按照接受的答案注册您的typeAdapter
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多