[英]Resolve JSON field types dynamically using Gson
I have the following API response:我有以下 API 响应:
{
"data":{
"categoryFields":[
{
"name":"brand",
"label":"Marca",
"values":[
{
"key":53,
"value":"Alfa Romeo"
},
{
"key":55,
"value":"Audi"
}
]
},
{
"name":"year",
"label":"Año", ,
"dataType":"select",
"values":[
{
"key":2017,
"value":2017
},
{
"key":2016,
"value":2016
}
]
},
]
}
}
Ok, in the first categoryField
the values are:好的,在第一个
categoryField
,值是:
"key":53 INT,
"value":"Alfa Romeo", STRING
In the second categoryField
the values are:在第二个
categoryField
,值是:
"key":2017, INT
"value":2017, INT
Also there's another type:还有另一种类型:
"key":"string", STRING
"value":"String", STRING
I need a class that can handle those types of data.我需要一个可以处理这些类型数据的类。 Something like:
就像是:
public class Value {
@SerializedName("key")
@Expose
private DYNAMIC_TYPE key;
@SerializedName("value")
@Expose
private DYNAMIC_TYPE value;
}
How can I do that?我怎样才能做到这一点? Or there's a Gson function to help me with that?
或者有一个 Gson 函数可以帮助我解决这个问题?
solution解决方案
public class CategoryValueDeserializer implements JsonDeserializer<CategoryValue> {
@Override
public CategoryValue deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final JsonElement jsonKey = jsonObject.get("key");
final String key = jsonKey.getAsString();
final JsonElement jsonValue = jsonObject.get("value");
final String value = jsonValue.getAsString();
CategoryValue categoryValue = new CategoryValue();
categoryValue.setKey(key);
categoryValue.setValue(value);
return categoryValue;
}
}
//retrofit //改造
final Gson gson = new GsonBuilder()
.registerTypeAdapter(Response.class, new CategoryValueDeserializer())
.create();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(END_POINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
Here is a working solution这是一个有效的解决方案
First create a POJO class like below首先创建一个像下面这样的 POJO 类
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class KeyValuePair {
@SerializedName("key")
@Expose
private String key;
@SerializedName("value")
@Expose
private Object value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
Then for Gson to serialize this class properly use this code然后对于 Gson 正确序列化此类使用此代码
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import java.lang.reflect.Type;
public class KeyValuePairDeserializer implements JsonDeserializer<KeyValuePair> {
@Override
public KeyValuePair deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final JsonElement jsonKey = jsonObject.get("key");
final String key = jsonKey.getAsString();
final JsonElement jsonValue = jsonObject.get("value");
Object value = jsonValue.getAsString();
if (jsonValue.isJsonPrimitive()) {
JsonPrimitive jsonPrimitive = jsonValue.getAsJsonPrimitive();
if (jsonPrimitive.isBoolean())
value = jsonValue.getAsBoolean();
else if (jsonPrimitive.isString())
value = jsonValue.getAsString();
else if (jsonPrimitive.isNumber()){
value = jsonValue.getAsNumber();
}
}
KeyValuePair categoryValue = new KeyValuePair();
categoryValue.setKey(key);
categoryValue.setValue(value);
return categoryValue;
}
}
Register the adapter with Gson like this像这样用 Gson 注册适配器
Gson provideGson() {
return new GsonBuilder()
.registerTypeAdapter(KeyValuePair.class, new KeyValuePairDeserializer())
.create();
}
Now you access the values by using getter methods like these现在您可以使用这些 getter 方法访问这些值
public String getString(String key) {
return (String) value;
}
public int getInt(String key) {
return ((Number) value).intValue();
}
public long getLong(String key) {
return ((Number) value).longValue();
}
public float getFloat(String key) {
return ((Number) value).floatValue();
}
public boolean getBoolean(String key) {
return (boolean) value;
}
I always had something like dataType
provided by BE.我总是有类似 BE 提供的
dataType
东西。 Then I could base on its value during deserialization.然后我可以在反序列化过程中基于它的值。 You've got
dataType
too, but only for Int, Int
case.您也有
dataType
,但仅适用于Int, Int
大小写。
Well, I'd do one of two things:好吧,我会做两件事之一:
dataType
for every different case.dataType
类型。 This is good for types with many parameters and only few different dataTypes.JsonDeserializer
to what I need, conditionally - based on dataType
.JsonDeserializer
反序列JsonDeserializer
到我需要的,有条件地 - 基于dataType
。isString
and others, as proposed in different answer.isString
和其他人进行检查,如不同答案中所建议的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.