我有以下课程
public class MyClass {
private List<MyOtherClass> others;
}
public class MyOtherClass {
private String name;
}
我有JSON可能看起来像这样
{
others: {
name: "val"
}
}
或者
{
others: [
{
name: "val"
},
{
name: "val"
}
]
}
我希望能够对这两种JSON格式使用相同的MyClass
。有没有办法用Gson做到这一点?
答案 0 :(得分:74)
我想出了一个答案。
private static class MyOtherClassTypeAdapter implements JsonDeserializer<List<MyOtherClass>> {
public List<MyOtherClass> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) {
List<MyOtherClass> vals = new ArrayList<MyOtherClass>();
if (json.isJsonArray()) {
for (JsonElement e : json.getAsJsonArray()) {
vals.add((MyOtherClass) ctx.deserialize(e, MyOtherClass.class));
}
} else if (json.isJsonObject()) {
vals.add((MyOtherClass) ctx.deserialize(json, MyOtherClass.class));
} else {
throw new RuntimeException("Unexpected JSON type: " + json.getClass());
}
return vals;
}
}
实例化像这样的Gson对象
Type myOtherClassListType = new TypeToken<List<MyOtherClass>>() {}.getType();
Gson gson = new GsonBuilder()
.registerTypeAdapter(myOtherClassListType, new MyOtherClassTypeAdapter())
.create();
TypeToken
是com.google.gson.reflect.TypeToken
。
您可以在此处阅读解决方案:
https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener
答案 1 :(得分:8)
谢谢三杯的解决方案!
如果需要多种类型,则使用泛型类型:
public class SingleElementToListDeserializer<T> implements JsonDeserializer<List<T>> {
private final Class<T> clazz;
public SingleElementToListDeserializer(Class<T> clazz) {
this.clazz = clazz;
}
public List<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<T> resultList = new ArrayList<>();
if (json.isJsonArray()) {
for (JsonElement e : json.getAsJsonArray()) {
resultList.add(context.<T>deserialize(e, clazz));
}
} else if (json.isJsonObject()) {
resultList.add(context.<T>deserialize(json, clazz));
} else {
throw new RuntimeException("Unexpected JSON type: " + json.getClass());
}
return resultList;
}
}
配置Gson:
Type myOtherClassListType = new TypeToken<List<MyOtherClass>>() {}.getType();
SingleElementToListDeserializer<MyOtherClass> adapter = new SingleElementToListDeserializer<>(MyOtherClass.class);
Gson gson = new GsonBuilder()
.registerTypeAdapter(myOtherClassListType, adapter)
.create();
答案 2 :(得分:0)
建立三杯答案,我有以下内容让JsonArray直接反序列化为数组。
static public <T> T[] fromJsonAsArray(Gson gson, JsonElement json, Class<T> tClass, Class<T[]> tArrClass)
throws JsonParseException {
T[] arr;
if(json.isJsonObject()){
//noinspection unchecked
arr = (T[]) Array.newInstance(tClass, 1);
arr[0] = gson.fromJson(json, tClass);
}else if(json.isJsonArray()){
arr = gson.fromJson(json, tArrClass);
}else{
throw new RuntimeException("Unexpected JSON type: " + json.getClass());
}
return arr;
}
用法:
String response = ".......";
JsonParser p = new JsonParser();
JsonElement json = p.parse(response);
Gson gson = new Gson();
MyQuote[] quotes = GsonUtils.fromJsonAsArray(gson, json, MyQuote.class, MyQuote[].class);
答案 3 :(得分:0)
共享代码,并将反序列化逻辑仅应用于特定字段:
JSON模型:
public class AdminLoginResponse implements LoginResponse
{
public Login login;
public Customer customer;
@JsonAdapter(MultiOrganizationArrayOrObject.class) // <-------- look here
public RealmList<MultiOrganization> allAccounts;
}
抽象类:
/**
* parsed field can either be a [JSONArray] of type [Element], or an single [Element] [JSONObject].
*/
abstract class ArrayOrSingleObjectTypeAdapter<TypedList: List<Element>, Element : Any>(
private val elementKClass: KClass<Element>
) : JsonDeserializer<TypedList> {
override fun deserialize(
json: JsonElement, typeOfT: Type?, ctx: JsonDeserializationContext
): TypedList = when {
json.isJsonArray -> json.asJsonArray.map { ctx.deserialize<Element>(it, elementKClass.java) }
json.isJsonObject -> listOf(ctx.deserialize<Element>(json, elementKClass.java))
else -> throw RuntimeException("Unexpected JSON type: " + json.javaClass)
}.toTypedList()
abstract fun List<Element>.toTypedList(): TypedList
}
特定于字段的类:
class MultiOrganizationArrayOrObject
: ArrayOrSingleObjectTypeAdapter<RealmList<MultiOrganization>,MultiOrganization>(kClass()) {
override fun List<MultiOrganization>.toTypedList() = RealmList(*this.toTypedArray())
}