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