web-dev-qa-db-ja.com

Gsonを使用して未知のフィールドでJSONをデコードする方法は?

私はこれに似たJSONを持っています:

{
  "unknown_field": {
    "field1": "str",
    "field2": "str",
    "field3": "str",
    "field4": "str",
    "field5": "str"
  }, ......
}

このJSONをマップするクラスを作成しました

public class MyModel implements Serializable {
  private int id;
  private HashMap<String, Model1> models;

  // getters and setter for id and models here
}

model 1クラスは、文字列フィールドのみを持つ単純なクラスです。

しかし、それは機能しません。

EditJSON形式 は次のようになります:

{
    "1145": {
        "cities_id": "1145",
        "city": "Nawanshahr",
        "city_path": "nawanshahr",
        "region_id": "53",
        "region_district_id": "381",
        "country_id": "0",
        "million": "0",
        "population": null,
        "region_name": "Punjab"
    },
    "1148": {
        "cities_id": "1148",
        "city": "Nimbahera",
        "city_path": "nimbahera",
        "region_id": "54",
        "region_district_id": "528",
        "country_id": "0",
        "million": "0",
        "population": null,
        "region_name": "Rajasthan"
    }, 
    ...
}
28
NazarK

(実際に JSONは次のようになります とOPがコメントした後、答えを完全に更新しました。)

Gson 2.0+のソリューション

I 学習したばかり 新しいGsonバージョンでは、これは非常に簡単です。

_GsonBuilder builder = new GsonBuilder();
Object o = builder.create().fromJson(json, Object.class);
_

作成されたオブジェクトはマップ(com.google.gson.internal.LinkedTreeMap)であり、印刷すると、次のようになります。

_{1145={cities_id=1145, city=Nawanshahr, city_path=nawanshahr, region_id=53, region_district_id=381, country_id=0, million=0, population=null, region_name=Punjab}, 
 1148={cities_id=1148, city=Nimbahera, city_path=nimbahera, region_id=54, region_district_id=528, country_id=0, million=0, population=null, region_name=Rajasthan}
...
_

カスタムデシリアライザーを使用したソリューション

[〜#〜] nb [〜#〜]:2.0より前に固執しない限り、実際にはカスタムデシリアライザーではないことがわかります。しかし、それでも Gsonでのカスタムデシリアライゼーション(およびシリアライゼーション) の方法を知っていると便利です。また、解析されたデータの使用方法によっては、最良のアプローチになることがよくあります。 )

そのため、実際にはランダム/さまざまなフィールド名を扱っています。 (もちろん、このJSON形式はあまり良くありません。この種のデータはJSON配列の中にあるべきです。その場合、リストに非常に簡単に読み込むことができます。 、まだこれを解析できます。)

まず、これはJavaオブジェクトでJSONデータをモデル化する方法です:

_// info for individual city
public class City    {
    String citiesId;
    String city;
    String regionName;
    // and so on
}

// top-level object, containing info for lots of cities
public class CityList  {
    List<City> cities;

    public CityList(List<City> cities) {
        this.cities = cities;
    }
}
_

次に、解析。この種のJSONを処理する1つの方法は、最上位オブジェクト(CityList)のカスタムデシリアライザーを作成することです。

このようなもの:

_public class CityListDeserializer implements JsonDeserializer<CityList> {

    @Override
    public CityList deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject = element.getAsJsonObject();
        List<City> cities = new ArrayList<City>();
        for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
            // For individual City objects, we can use default deserialisation:
            City city = context.deserialize(entry.getValue(), City.class); 
            cities.add(city);
        }
        return new CityList(cities);
    }

}
_

注目すべき重要な点は、jsonObject.entrySet()への呼び出しです。これは、すべてのトップレベルフィールド(「1145」などの名前を持つ) 「1148」など)。 このスタックオーバーフローの答え これを解決するのに役立ちました。

以下の解析コードを完了してください。カスタムシリアライザーを登録するには、registerTypeAdapter()を使用する必要があることに注意してください。

_GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(CityList.class, new CityListDeserializer());
Gson gson = builder.setFieldNamingPolicy(LOWER_CASE_WITH_UNDERSCORES).create();
CityList list = gson.fromJson(json, CityList.class);
_

(これは、テストに使用した完全な 実行可能例 です。Gsonの他に、Guavaライブラリを使用しています。)

68
Jonik