Gson десериализует массив JSON с несколькими типами объектов
У меня есть странный JSON, как:
[
{
"type":"0",
"value":"my string"
},
{
"type":"1",
"value":42
},
{
"type":"2",
"value": {
}
}
]
Основанный на некотором поле, объект в массиве имеет определенный тип. Используя Gson, я подумал о том, чтобы иметь TypeAdapterFactory, который отправляет адаптеры делегатов для этих определенных типов в TypeAdapter, но я зациклен на понимании хорошего способа чтения этого поля типа, чтобы узнать, какой тип создать. В адаптере типов
Object read(JsonReader in) throws IOException {
String type = in.nextString();
switch (type) {
// delegate to creating certain types.
}
}
Предполагается, что поле "тип" идет первым в моем JSON. Есть ли достойный способ снять это предположение?
1 ответ
Вот некоторый код, который я написал для обработки массива элементов NewsFeedArticle и NewsFeedAd в Json. Оба элемента реализуют интерфейс маркера NewsFeedItem, чтобы я мог легко проверить, должен ли TypeAdater использоваться для определенного поля.
public class NewsFeedItemTypeAdapterFactory implements TypeAdapterFactory {
@Override
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (!NewsFeedItem.class.isAssignableFrom(type.getRawType())) {
return null;
}
TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class);
TypeAdapter<NewsFeedArticle> newsFeedArticleAdapter = gson.getDelegateAdapter(this, TypeToken.get(NewsFeedArticle.class));
TypeAdapter<NewsFeedAd> newsFeedAdAdapter = gson.getDelegateAdapter(this, TypeToken.get(NewsFeedAd.class));
return (TypeAdapter<T>) new NewsFeedItemTypeAdapter(jsonElementAdapter, newsFeedArticleAdapter, newsFeedAdAdapter).nullSafe();
}
private static class NewsFeedItemTypeAdapter extends TypeAdapter<NewsFeedItem> {
private final TypeAdapter<JsonElement> jsonElementAdapter;
private final TypeAdapter<NewsFeedArticle> newsFeedArticleAdapter;
private final TypeAdapter<NewsFeedAd> newsFeedAdAdapter;
NewsFeedItemTypeAdapter(TypeAdapter<JsonElement> jsonElementAdapter,
TypeAdapter<NewsFeedArticle> newsFeedArticleAdapter,
TypeAdapter<NewsFeedAd> newsFeedAdAdapter) {
this.jsonElementAdapter = jsonElementAdapter;
this.newsFeedArticleAdapter = newsFeedArticleAdapter;
this.newsFeedAdAdapter = newsFeedAdAdapter;
}
@Override
public void write(JsonWriter out, NewsFeedItem value) throws IOException {
if (value.getClass().isAssignableFrom(NewsFeedArticle.class)) {
newsFeedArticleAdapter.write(out, (NewsFeedArticle) value);
} else if (value.getClass().isAssignableFrom(NewsFeedAd.class)) {
newsFeedAdAdapter.write(out, (NewsFeedAd) value);
}
}
@Override
public NewsFeedItem read(JsonReader in) throws IOException {
JsonObject objectJson = jsonElementAdapter.read(in).getAsJsonObject();
if (objectJson.has("Title")) {
return newsFeedArticleAdapter.fromJsonTree(objectJson);
} else if (objectJson.has("CampaignName")) {
return newsFeedAdAdapter.fromJsonTree(objectJson);
}
return null;
}
}
}
Затем вы можете зарегистрировать это в Gson, используя следующий код.
return new GsonBuilder()
.registerTypeAdapterFactory(new NewsFeedItemTypeAdapterFactory())
.create();