原始类型和数组的 GSON 自定义反序列化器
Posted
技术标签:
【中文标题】原始类型和数组的 GSON 自定义反序列化器【英文标题】:GSON Custom Deserializer for a primitive type and an array 【发布时间】:2021-11-01 18:21:49 【问题描述】:我有一个可能具有不同值的 JSON 响应。
"values": [
"type": "AAA",
"value": 3
,
"type": "BBB",
"value": [
"ABC": 8
,
"DEF": 9
,
"GHI": 9
,
"JKL": 8
,
"MNO": 9
,
"PQR": 9
]
]
数据类
data class Values(
@SerializedName("type")
@Expose
val type: String,
@SerializedName("value")
@Expose
val value: Int)
如您所见,value
可以是 Int 或另一个 Json 数组。任何想法如何为此编写反序列化器? android 应用程序当前正在使用 Int 字段(类型 AAA),我正在尝试集成潜在的数组值(类型 BBB)。谢谢。
【问题讨论】:
即使value
是单个 int 值,您能否将其设为 Json 数组?我的意思是只需将该 int 值添加到 json 数组并返回它,因为这将使 json 数组在所有情况下都成为统一类型,并且更容易建模,因此更容易反序列化。如果发生这种情况,我有一个解决方案,即如果您可以控制来自后端的数据
我也在研究一些相关的问题,有些场景只是将其转换为原始类型数组。不幸的是,我无法控制数据的嵌套
如果 json 对象的键和值对您都很重要,并且在输入单个值的情况下,您可以做的一件事是创建一个 List<Pair>
如果你不会使用它。如果您同意在下面的答案部分中继续使用此方法,我也可以在这种情况下为您提供详细的解决方案,但只需先与您确认
就像下面的一些答案建议的那样,我们将进行自定义反序列化,然后将您的模型 value
更改为 List<Pair
而不是 int 我已经在上面描述了如何处理单个值案例
很遗憾,我无法转换为 List,因为该应用有键值对
【参考方案1】:
例如,您可以拥有一个带有两个子类的密封类Value
:
sealed class Value
/* type AAA */
data class IntValue(val value: Int) : Value()
/* type BBB */
data class IntPairValue(val value: List<Pair<String, Int>>) : Value()
并编写自定义反序列化器:
class ValueTypeDeserializer : JsonDeserializer<Value?>
override fun deserialize(
json: JsonElement,
typeOfT: Type,
context: JsonDeserializationContext
): Value?
return when
json.isJsonPrimitive ->
Value.IntValue(json.asJsonPrimitive.asInt)
json.isJsonArray ->
val list = context.deserialize<List<Map<String, Int>>>(json, LIST_OF_MAP_TYPE)
val pairs = list.map e -> e.firstNotNullOf (key, value) -> Pair(key, value)
Value.IntPairValue(pairs)
else -> null
companion object
private val LIST_OF_MAP_TYPE = object : TypeToken<List<Map<String, Int>>>() .type
现在您可以使用 @JsonAdapter
注释将这个反序列化器应用到 "value"
字段,例如:
data class Values(
@SerializedName("type")
@Expose
val type: String,
@SerializedName("value")
@Expose
@JsonAdapter(ValueTypeDeserializer::class)
val value: Value
)
val optIntValue: Int?
get() = (value as? Value.IntValue)?.value
val optIntPairValue: List<Pair<String, Int>>?
get() = (value as? Value.IntPairValue)?.value
使用optIntValue
或optIntPairValue
访问您感兴趣的值。
【讨论】:
【参考方案2】:试试这个代码:
try
JSONObject jsonObject = new JSONObject(); // this is your values object
Object o = jsonObject.get("value");
if (o instanceof JSONArray)
//this is jsonarray
else if (o instanceof JSONObject)
//this is jsonobject
else if (o instanceof Integer)
//this is int
else if (o instanceof String)
//this is String
catch (JSONException e)
e.printStackTrace();
【讨论】:
嗨@Praful Patel,我目前正在使用改造来映射JSON响应,我没有手动映射它们 然后将 value_object 类型设置为“Object”到您的改造模型类中。然后你将我的 if 条件用于你的活动或 getter 方法。 正如我所说,Int 值已经存在使用,我不能只是更改它,因为它会影响很多东西【参考方案3】:首先,在您的情况下使用手动解析而不是自动解析,因为自动解析可能会出现问题并且在这种情况下也有点复杂。现在您需要将请求更改为“JsonObject”。
试试这个代码...
try
JSONObject your_response=new JSONObject();
JSONArray jsonArrayMain=your_response.getJSONArray("values");
for (int i = 0; i < jsonArrayMain.length(); i++)
JSONObject jsonObject=jsonArrayMain.getJSONObject(i);
String type=jsonObject.getString("type");
Object o = jsonObject.get("value");
if (o instanceof JSONArray)
//value is array
JSONArray jsonArrayValue=jsonObject.getJSONArray("value");
for (int j = 0; j <jsonArrayValue.length(); j++)
JSONObject subJsonObject=jsonArrayValue.getJSONObject(j);
Iterator<String> iterator = subJsonObject.keys();
while (iterator.hasNext())
String key = iterator.next();
Log.i("====TAG","key:"+key +"--Value::"+subJsonObject.optString(key);
else if (o instanceof String)
//value is string
String value=jsonObject.getString("value");
catch (Exception e)
e.printStackTrace();
希望,它有效。 :)
【讨论】:
以上是关于原始类型和数组的 GSON 自定义反序列化器的主要内容,如果未能解决你的问题,请参考以下文章
JSON 序列化与反序列化(-)泛型 及 java.lang.reflect.Type
如何通过 gson 将 json 反序列化为嵌套的自定义地图?