Подтвердить что ты не робот

Как декодировать JSON с неизвестным полем с помощью Gson?

У меня 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
}

и класс Model1 - это простой класс только со строковыми полями.

Но это не сработает.

Изменить: Формат JSON выглядит следующим образом:

{
    "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"
    }, 
    ...
}
4b9b3361

Ответ 1

(После того, как OP прокомментировал, что на самом деле JSON выглядит так, я полностью обновил ответ.)

Решение для Gson 2.0 +

I только что узнал, что с более новыми версиями Gson это очень просто:

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

Созданный объект - это Map (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). Оказывается, вы не являетесь обычным десериализатором, если вы не застряли в версиях GSS до 2.0. Но все же полезно знать, как это сделать настраиваемая десериализация (и сериализация) в Gson, и это может часто быть лучшим подходом в зависимости от того, как вы хотите использовать проанализированные данные.)

Итак, мы действительно имеем дело со случайными/переменными именами полей. (Конечно, этот формат JSON не очень хорош, такие данные должны быть внутри массива JSON, и в этом случае его можно было бы легко прочитать в списке. Ну, мы все еще можем разобрать это.)

Во-первых, именно так я буду моделировать данные JSON в объектах Java:

// 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 - создать настраиваемый десериализатор для объекта верхнего уровня (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.)