web-dev-qa-db-ja.com

オブジェクトの1つの変数のGsonカスタムデセラライザー

私の問題の例:

オブジェクトタイプはAppleです。 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

Appleオブジェクトを取得すると、Appleに複数のシードが含まれるか、1つのシードが含まれるか、またはシードがない可能性があります。

例JSON Apple 1つのシード:

{
"Apple" : {
   "Apple_name" : "Jimmy", 
   "Apple_brand" : "Awesome Brand" , 
   "seeds" : {"seed_name":"Loopy" , "seed_size":"14" }
  }
}

JSON Appleと2つのシードの例:

{
"Apple" : {
   "Apple_name" : "Jimmy" , 
   "Apple_brand" : "Awesome Brand" , 
   "seeds" : [ 
      { 
         "seed_name" : "Loopy",
         "seed_size" : "14"
      },
      {
         "seed_name" : "Quake",
         "seed_size" : "26"
      } 
  ]}
}

ここでの問題は、最初の例がシードのJSONObjectであり、2番目の例がシードのJSONArrayです。 JSONの一貫性がなく、修正する最も簡単な方法はJSON自体を修正することですが、残念ながら他の誰かからJSONを取得しているため、修正できません。この問題を解決する最も簡単な方法は何ですか?

29
Jacob Nelson

Appleタイプのカスタムタイプアダプターを登録する必要があります。タイプアダプターでは、配列または単一のオブジェクトが与えられたかどうかを判断するロジックを追加します。その情報を使用して、Appleオブジェクトを作成できます。

以下のコードに加えて、seedsフィールドが自動的に解析されないようにAppleモデルオブジェクトを変更します。変数宣言を次のように変更します。

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ガイド を参照してください。

39
jjnguy

私も同じ問題に直面しました。私の解決策は少しシンプルで一般的だと思います:

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
matt burns

GSONでリストの代わりに配列を使用しており、そのような問題はありません: http://app.ecwid.com/api/v1/1003/product?id=4064 「カテゴリ"プロパティは実際には1つの要素を持つJavaScript配列です。次のように宣言されました:

カテゴリ[]カテゴリ;

更新:TypeTokenとカスタムシリアル化を使用すると役立つ場合があります。このドキュメントを参照してください: https://sites.google.com/site/gson/gson-user-guide

1
Dmitry Negoda

JSONを変更できない場合(他の人から取得する場合)、最も簡単な解決策は、Apple and Seedクラス変数名をJava Classなので、解析された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
0
yogendra saxena