有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Gson句柄对象或数组

我有以下课程

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做到这一点


共 (4) 个答案

  1. # 1 楼答案

    我想出了一个答案

    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

  2. # 2 楼答案

    要共享代码并仅将反序列化逻辑应用于特定字段,请执行以下操作:

    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())
    }
    
  3. # 3 楼答案

    感谢您三杯的解决方案

    泛型类型也是如此,以防多个类型需要它:

    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();
    
  4. # 4 楼答案

    在三个cups的基础上,我有以下内容,可以将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);