json 字符串中一个 value 多种类型的反序列化
1. json 格式
{
"ct":{
"id":121605,
"type":"type_str",
"sample_data":["2119"]
}
}
或者
{
"data":{
"ct":{
"id":121605,
"type":"type_factory",
"sample_data":[
{
"factory":"beijing"
},{
"factory":"shanghai"
}
]
}
}
即 sample_data 的 value 可能是 List
类型的,也可能是 List
类型的,ct 的 value 对象对应的 javaBean 为 CtBean
,为了保证 sample_data 既能兼容 String
又能兼容 FactoryDataBean
,所以要添加泛型类型 CTGL_TYPE
class CtBean {
var id = 0
var sample_data : List? = null
class FactoryDataBean {
var factory : String? = null
}
}
2. 自定义 JsonSerializer
自定义 JsonSerializer 来告诉 Gson 如何将指定的 json 字符串 反序列化为指定的类型/序列化为 Json 字符串。
方式一
直接反序列化为一种类型,如果类型转换失败则再转换为另一种类型,适用于没有 type 的情况,如果多次转换会消耗性能。
class CtSerializer : JsonSerializer>, JsonDeserializer> {
override fun serialize(src: CtBean?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
return Gson().toJsonTree(src)
}
override fun deserialize(json: JsonElement, typeOfT: Type?, context: JsonDeserializationContext?): CtBean? {
kotlin.runCatching {
return Gson().fromJson(json, object : TypeToken>() {}.type)
}.onFailure {
return Gson().fromJson(json, object : TypeToken>(){}.type)
}
return Gson().fromJson(json, object : TypeToken>() {}.type)
}
}
方式二
通过 type 来判断究竟反序列化为哪种类型
class CtSerializer : JsonSerializer>, JsonDeserializer> {
override fun serialize(src: CtBean?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
return Gson().toJsonTree(src)
}
override fun deserialize(json: JsonElement, typeOfT: Type?, context: JsonDeserializationContext?): CtBean {
var type = json.asJsonObject.getAsJsonPrimitive("type")?.asString
if ("type_str".equals(type)) {
return Gson().fromJson(json, object : TypeToken>(){}.type)
} else if ("type_factory".equals(type)) {
return Gson().fromJson(json, object : TypeToken>(){}.type)
}
return Gson().fromJson(json, object : TypeToken>() {
}.type)
}
}
3. 注册自定义的 JsonSerializer
private static Retrofit getRetrofitInstance() {
Gson gson = new GsonBuilder()
.registerTypeAdapter(CtBean.class, new CtSerializer())
.create();
if (mRetrofit == null) {
synchronized (HTTPCenter.class) {
if (mRetrofit == null) {
mRetrofit = new Retrofit.Builder()
.baseUrl(HTTPService.Companion.getServiceDefault())
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(initOkHttpClient()).build();
}
}
}
return mRetrofit;
}
4. 解决 java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to xxx.bean.AssembleDetailCtBean$LCtglCsgsqyBean
解决方案:先把 linkedTreeMap 对象转成 json 字符串,然后再转成 JavaBean
Gson gson = new Gsonbuilder.enableComplexMapKeySerialization().create();
String jsonString = gson.toJson(linkedTreeMap);
JavaBean bean = gson.fromJson(jsonString,JavaBean.class);
实际应用如下:
private fun transTreeMapToRealObj(model: AssembleDetailEntity?) {
kotlin.runCatching {
GsonBuilder().enableComplexMapKeySerialization().create().let { gson ->
model?.data?.tags?.let {
val tagResultArrayList: ArrayList = ArrayList()
for (ele in it) {
if (ele !is String) {
val tagsResultBean: AssembleDetailDataBean.TagsBean = gson.fromJson(gson.toJson(ele as LinkedTreeMap<*, *>), AssembleDetailDataBean.TagsBean::class.java)
tagResultArrayList.add(tagsResultBean)
}
}
if (tagResultArrayList.isNotEmpty()) {
model.data?.tags = tagResultArrayList
}
}
}
}.onFailure {
TLog.e("TAG","transTreeMapToRealObj failed msg=" + it.message)
}
}