问题描述
我正在从我们的后端团队提供的API中获取数据.键data
之一有时包含JSONObject
,有时它包含JSONArray
.我正在使用GSON
来解析响应,因此它引发了异常.
I am fetching data from API provided by our Backend team. One of the keys data
sometimes contains JSONObject
and sometimes it contains JSONArray
. I am using GSON
to parse the response and it is throwing an exception because of this.
我尝试了此线程中给出的解决方案,但在我的情况下不起作用.如何动态处理json响应数组/使用Gson的对象
I tried the solution given in this thread but it's not working in my case.How to dynamically handle json response array/object using Gson
POJO(EntityDetailResponseV2):
package com.tf.eros.faythTv.objects.entityDetail;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import com.tf.eros.faythTv.objects.entityFeatured.EntityFeaturedResponse;
import com.tf.eros.faythTv.utils.ArrayAdapterFactory;
import java.util.List;
public class EntityDetailResponseV2 {
@SerializedName("results")
private Results results;
@SerializedName("success")
private boolean success;
public static EntityDetailResponseV2 getObject(String res) {
try {
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ArrayAdapterFactory()).create();
return gson.fromJson(res, EntityDetailResponseV2.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Results getResults() {
return results;
}
public boolean isSuccess() {
return success;
}
public static class Results {
@SerializedName("id")
Integer entityID;
@SerializedName("name")
String entityName;
@SerializedName("description")
String entityDescription;
@SerializedName("image_url")
String entityImageURL;
@SerializedName("square_entity_url")
String entitySquareURL;
@SerializedName("slug")
String entitySlug;
@SerializedName("live")
boolean isEntityLive;
@SerializedName("twitter_username")
String twitterUserName;
@SerializedName("fb_username")
String fbUserName;
@SerializedName("featured")
private List<EntityFeaturedResponse> featured;
@SerializedName("collections")
List<Collections> collectionsList;
public Integer getEntityID() {
return entityID;
}
public String getEntityName() {
return entityName;
}
public String getEntityDescription() {
return entityDescription;
}
public String getEntityImageURL() {
return entityImageURL;
}
public String getEntitySquareURL() {
return entitySquareURL;
}
public String getEntitySlug() {
return entitySlug;
}
public boolean isEntityLive() {
return isEntityLive;
}
public String getTwitterUserName() {
return twitterUserName;
}
public String getFbUserName() {
return fbUserName;
}
public List<EntityFeaturedResponse> getFeatured() {
return featured;
}
public List<Collections> getCollectionsList() {
return collectionsList;
}
public static class Collections {
@SerializedName("type")
String type;
@SerializedName("type_id")
Integer typeID;
//Data sometimes contains JSON object and sometimes it contains JSON Array
@SerializedName("data")
List<Data> data;
public String getType() {
return type;
}
public Integer getTypeID() {
return typeID;
}
public List<Data> getData() {
return data;
}
public static class Data {
@SerializedName("view_all")
boolean viewAll;
@SerializedName("title")
String title;
public boolean isViewAll() {
return viewAll;
}
public String getTitle() {
return title;
}
}
}
}
}
ArrayAdapterFactory.java
public class ArrayAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings({"unchecked"})
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
ArrayAdapter typeAdapter = null;
try {
if (type.getRawType() == List.class) {
typeAdapter = new ArrayAdapter(
(Class) ((ParameterizedType) type.getType())
.getActualTypeArguments()[0]);
}
} catch (Exception e) {
e.printStackTrace();
}
return typeAdapter;
}
public class ArrayAdapter<T> extends TypeAdapter<List<T>> {
private Class<T> adapterClass;
public ArrayAdapter(Class<T> adapterClass) {
this.adapterClass = adapterClass;
}
public List<T> read(JsonReader reader) throws IOException {
List<T> list = new ArrayList<T>();
Gson gson = new Gson();
if (reader.peek() == JsonToken.BEGIN_OBJECT) {
T inning = (T) gson.fromJson(reader, adapterClass);
list.add(inning);
} else if (reader.peek() == JsonToken.BEGIN_ARRAY) {
reader.beginArray();
while (reader.hasNext()) {
//read(reader);
T inning = (T) gson.fromJson(reader, adapterClass);
list.add(inning);
}
reader.endArray();
} else {
reader.skipValue();
}
return list;
}
public void write(JsonWriter writer, List<T> value) throws IOException {
}
}
}
由于完整的API响应非常大,因此我提供了指向.json文件的链接. https://drive.google.com/open?id=1RMOiM7UjOwR-5b0Ik7ymy65ZOhc8I8hY
As complete API response is very large, I am providing a link to .json file. https://drive.google.com/open?id=1RMOiM7UjOwR-5b0Ik7ymy65ZOhc8I8hY
更新:我尝试了下面提到的解决方案,但DataType1和DataType2都为空.尽管我不再遇到GSON
例外.
UPDATE:I tried the solution which is mentioned below but still, DataType1 and DataType2 both are coming nulls. Although I am no longer getting the GSON
exception.
public class EntityDetailResponseV2 {
@SerializedName("results")
private Results results;
@SerializedName("success")
private boolean success;
public static EntityDetailResponseV2 getObject(String res) {
try {
Gson gson = new GsonBuilder().registerTypeAdapter(Collections.class, new Results.Collections.CollectionItemDeserializer()).create();
return gson.fromJson(res, EntityDetailResponseV2.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Results getResults() {
return results;
}
public boolean isSuccess() {
return success;
}
public static class Results {
@SerializedName("id")
Integer entityID;
@SerializedName("name")
String entityName;
@SerializedName("description")
String entityDescription;
@SerializedName("image_url")
String entityImageURL;
@SerializedName("square_entity_url")
String entitySquareURL;
@SerializedName("slug")
String entitySlug;
@SerializedName("live")
boolean isEntityLive;
@SerializedName("twitter_username")
String twitterUserName;
@SerializedName("fb_username")
String fbUserName;
@SerializedName("featured")
private List<EntityFeaturedResponse> featured;
@SerializedName("collections")
List<Collections> collectionsList;
public Integer getEntityID() {
return entityID;
}
public String getEntityName() {
return entityName;
}
public String getEntityDescription() {
return entityDescription;
}
public String getEntityImageURL() {
return entityImageURL;
}
public String getEntitySquareURL() {
return entitySquareURL;
}
public String getEntitySlug() {
return entitySlug;
}
public boolean isEntityLive() {
return isEntityLive;
}
public String getTwitterUserName() {
return twitterUserName;
}
public String getFbUserName() {
return fbUserName;
}
public List<EntityFeaturedResponse> getFeatured() {
return featured;
}
public List<Collections> getCollectionsList() {
return collectionsList;
}
public static class Collections {
@SerializedName("type")
String type;
@SerializedName("order")
Integer order;
@SerializedName("type_id")
Integer typeId;
DataType1 dataType1;
List<DataType2> dataType2;
public String getType() {
return type;
}
public Integer getOrder() {
return order;
}
public Integer getTypeId() {
return typeId;
}
public DataType1 getDataType1() {
return dataType1;
}
public List<DataType2> getDataType2() {
return dataType2;
}
public static class CollectionItemDeserializer implements JsonDeserializer<Collections> {
@Override
public Collections deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Collections collectionItem = new Gson().fromJson(json, Collections.class);
JsonObject jsonObject = json.getAsJsonObject();
if (collectionItem.getType() != null) {
JsonElement element = jsonObject.get("data");
switch (collectionItem.getTypeId()) {
case AppConstants.ENTITY_SHOP:
case AppConstants.ENTITY_MEDIA_COLLECTION:
case AppConstants.ENTITY_ECOM_COLLECTION:
case AppConstants.ENTITY_BANNER:
collectionItem.dataType1 = new Gson().fromJson(element, DataType1.class);
break;
case AppConstants.ENTITY_TOP_AUDIOS:
case AppConstants.ENTITY_TOP_VIDEOS:
case AppConstants.ENTITY_LATEST_VIDEOS:
case AppConstants.ENTITY_TOP_PLAYLISTS:
case AppConstants.ENTITY_WALLPAPERS:
case AppConstants.ENTITY_QUOTATIONS:
List<DataType2> values = new Gson().fromJson(element, new TypeToken<ArrayList<DataType2>>() {}.getType());
collectionItem.dataType2 = values;
break;
}
}
return collectionItem;
}
}
public static class DataType1 {
@SerializedName("view_all")
boolean viewAll;
public boolean isViewAll() {
return viewAll;
}
}
public static class DataType2 {
@SerializedName("view_all")
boolean viewAll;
public boolean isViewAll() {
return viewAll;
}
}
}
}
}
推荐答案
您需要使用自定义JsonDeserializer.解决方法如下:
You need to use a custom JsonDeserializer. Here's the solution :
public class CollectionListItem {
@SerializedName ("type")
String type;
@SerializedName ("order")
Integer order;
@SerializedName ("id")
Integer id;
@SerializedName ("type_id")
Integer typeId;
DataType1 dataType1;
List<DataType2> dataType2;
List<DataType3> dataType3;
final static String DATA_TYPE_1 = "SHOP";
final static String DATA_TYPE_2 = "TOP_AUDIOS";
final static String DATA_TYPE_3 = "MEDIA_COLLECTION";
//Public getters and setters
public static class CollectionItemDeserializer implements JsonDeserializer<CollectionListItem> {
@Override
public CollectionListItem deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
CollectionListItem collectionItem = new Gson().fromJson(json, CollectionListItem.class);
JsonObject jsonObject = json.getAsJsonObject();
if (collectionItem.getType() != null) {
JsonElement element = jsonObject.get("data");
switch(collectionItem.getType()){
case CollectionListItem.DATA_TYPE_1 :
collectionItem.dataType1 = new Gson().fromJson(element, DataType1.class);
break;
case CollectionListItem.DATA_TYPE_2:
List<DataType2> values = new Gson().fromJson(element, new TypeToken<ArrayList<DataType2>>() {}.getType());
collectionItem.dataType2 = values;
break;
case CollectionListItem.DATA_TYPE_3:
List<DataType3> values_ = new Gson().fromJson(element, new TypeToken<ArrayList<DataType3>>() {}.getType());
collectionItem.dataType3 = values_;
break;
}
}
return collectionItem;
}
}
}
DataType1,DataType2等是用于不同响应的各个类.
DataType1, DataType2, etc are the individual classes for different responses.
此外,添加此行以向gson注册您的自定义解串器
Also, add this line to register your custom deserializer with gson
Gson gson = new GsonBuilder()
.registerTypeAdapter(CollectionListItem.class,
new CollectionListItem.CollectionItemDeserializer())
.create();
这篇关于Android:当键可以是JSON对象或JSON数组时,解析JSON响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!