GSON:JSON反序列化为变量类型(列表/字符串) [英] GSON: JSON deserialization to variable type (List/String)

查看:92
本文介绍了GSON:JSON反序列化为变量类型(列表/字符串)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这一点上,这已经是一个老问题了,我可能已经阅读了SO上的每个相关主题.

At this point it's already an old question and I've probably read every related topic on SO.

但是要点.我需要一些建议或更正吗?

But to the point. I need some advice or correction maybe?

由于某些原因,我们产生了两种类型的可生成Json:

For some reason we have generatable Jsons of 2 types:

{"data": {"id": "value"}}{"data":[{"id": "value"}]}

对象和数组.还有其他参数,但在这里无关紧要.每个请求的"id"都不同.有时是userId,PortfolioId等.因此我得到"id"并将其传递给相关的var.

Object and Array. There are also other params but they doesn't matter here. "id" is differ for every request. Sometimes it's userId, portfolioId etc. So I get "id" and pass it to related var.

很长一段时间我一直在处理第一种情况.并像这样创建POJO:

For a long time I was working with the first case. And created POJO like this:

Data.class

public class Data {

@SerializedName("id")
@Expose
private String id;

public Data() {
}

public Data(String id) {
    super();
    this.id = id;
}

protected String getId() {
    return id;
}

然后我通过 User.class 处理数据"参数.

And I adress "data" paramets via User.class.

@JsonAdapter(UserDeserializer.class)
public Data data;


public Data getData() {
    return data;
}

public void setData(Data data) {
    this.data = data;
}


public User() {
}

public User(Data data) {
    super();
    this.data = data;
}

Gson gson = new Gson();

public String getPortfolioList(String tokenId, String userId) {
    Call<User> call = apiRequest.getPortfolioList(userId, tokenId);

    try {
        User newResult = gson.fromJson(String.valueOf(call.execute().body()), User.class);
        System.out.println(newResult.getData().getId());
    } catch (IOException e) {
        e.printStackTrace();
    }
    return getPortfolioId();
}

Deserializer.class

 public class UserDeserializer implements JsonDeserializer<User> {

    private Type listType = new TypeToken<List<Data>>(){}.getType();

    @Override
    public User deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {

        User user = new User();
        JsonElement jsonElement;
        if (json.isJsonArray()) {
            jsonElement = json.getAsJsonArray();
            user.data = context.deserialize(jsonElement,listType);
//            user.data = new Gson().fromJson(jsonElement, new TypeToken<List<Data>>() {}.getType());
        } else {
            jsonElement = json.getAsJsonObject();
            user.data = context.deserialize(jsonElement, Data.class);
//            user.setData(new Gson().fromJson(jsonElement, new TypeToken<Data>() {}.getType()));
        }
        return user;
    }
}

Baseppi类中的

Gson生成器,以防万一:

Gson builder in BaseApi class just in case:

Gson gson = new GsonBuilder().registerTypeAdapter(UserDeserializer.class, new UserDeserializer()).setLenient().create();

没有自定义反序列化和Array JSON问题,它将可以完美地工作.但是现在我必须确定我得到的数据"的确切类型.

Without custom deserialization and Array JSON issue this would work perfectly. But now I have to determine "data" 's exact type I get.

在上述情况下,我得到java.lang.ClassCastException: java.util.ArrayList cannot be cast to auto.Rest.Data

In above case I get java.lang.ClassCastException: java.util.ArrayList cannot be cast to auto.Rest.Data

我假设我必须创建另一个 Data 类(例如,将有 DataObject & DataArray ),并将每个参数描述为I以前在 Data.class 中完成了这项工作吗?我想反序列化期间做错了什么,但是我不确定tbh在哪里.

I assume I have to create another Data class (for example there will be DataObject & DataArray) and describe every parameter as I did before in Data.class to get this work? I think I do something wrong during deserialization but I'm not sure where tbh.

还是我错了,可以将 Data 用作 List ,将 Data 用作 Object 同一班?

Or am I wrong and it is possible to invoke Data as List and Data as an Object of the same class?

我已经为此工作了好几天(?),并且正在考虑使用泛型而不是Gson帮助,是的,我很绝望.因此,任何帮助表示赞赏.

I'm working on this for several days already(?) and was thinking about use generics instead of Gson help, yeah, I'm desperate. So any help appreciated.

推荐答案

如果始终使用objectone-element array,则可以编写自定义解串器,如下所示:

If you always have object or one-element array you can write custom deserialiser as below:

class OneOrElementJsonDeserializer<T> implements JsonDeserializer<T> {

    @Override
    public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json instanceof JsonArray) {
            final JsonArray array = (JsonArray) json;
            final int size = array.size();
            if (size == 0) {
                return null;
            }

            return context.deserialize(array.get(0), typeOfT);
        }

        return context.deserialize(json, typeOfT);
    }
}

简化后的示例模型如下:

Your example model after simplification looks like below:

class User {

    @JsonAdapter(OneOrElementJsonDeserializer.class)
    private Data data;

    public User() {
    }

    public User(Data data) {
        super();
        this.data = data;
    }

    public Data getData() {
        return data;
    }

    public void setData(Data data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "User{" +
                "data=" + data +
                '}';
    }
}

class Data {

    private String id;

    protected String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Data{" +
                "id='" + id + '\'' +
                '}';
    }
}

示例用法:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.JsonAdapter;

import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;

public class GsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        Gson gson = new GsonBuilder()
                .setPrettyPrinting()
                .create();

        User root = gson.fromJson(new FileReader(jsonFile), User.class);
        System.out.println(root);
    }
}

JSON有效负载以下的代码上方:

Above code for below JSON payload:

{
  "data": [
    {
      "id": "c87ca3fe85781007869b83f"
    }
  ]
}

打印:

User{data=Data{id='c87ca3fe85781007869b83f'}}

对于object情况JSON有效载荷:

{
  "data": {
    "id": "c87ca3fe85781007869b83f"
  }
}

打印:

User{data=Data{id='c87ca3fe85781007869b83f'}}

如果您的媒体资源可能包含JSON objectmulti-element array,请参阅我对这个问题的回答

In case your property could contain JSON object or multi-element array see my answer to this question Mapping Json Array to Java Models. There is implemented deserialiser which handle cases like this.

这篇关于GSON:JSON反序列化为变量类型(列表/字符串)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆