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

Пользовательский десализатор 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, у яблока может быть более одного семени, или у него может быть одно семя или, может быть, нет семян!

Пример JSON apple с одним семенем:

{
"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 от кого-то другого, поэтому я не могу его исправить. Каким будет самый простой способ исправить эту проблему?

4b9b3361

Ответ 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 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.

Ответ 2

Мы используем массивы вместо списков с помощью GSON, и нет такой проблемы: посмотрите http://app.ecwid.com/api/v1/1003/product?id=4064 свойство "categories" фактически массив Javascript с одним элементом. Это было объявлено следующим образом:

Категория [] категорий;

Обновление: использование TypeToken и Custom Serialization может помочь, см. этот документ: https://sites.google.com/site/gson/gson-user-guide

Ответ 3

Если вы не можете изменить JSON (как вы его получите от кого-то другого), тогда самое простое решение - изменить имя переменной класса Apple и 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

Ответ 4

Я столкнулся с той же проблемой. Я думаю, что мое решение немного проще и более общее:

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 нет ничего плохого, и он будет значительно упрощать сериализацию и де-сериализацию! К сожалению, иногда эти изменения выходят из-под вашего контроля.