当前位置: 首页 > 面试题库 >

GSON:JSON反序列化为变量类型(列表/字符串)

宰父宾实
2023-03-14
问题内容

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

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

出于某种原因,我们有两种可生成的Jsons:

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

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

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

数据类

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处理 “数据” 参数

@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();
}

解串器类

 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;
    }
}

__BaseApi类中的 Gson构建器 ,以防万一:

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

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

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

我假设我必须创建另一个 Data 类(例如将有 DataObjectDataArray ),并像以前在 Data.class中
所做的那样描述每个参数,以完成这项工作?我想在反序列化过程中做错了什么,但是我不确定tbh在哪里。

还是我错了,可以将 Data 作为 List 进行调用并将 Data 作为同一类的 Object 进行调用?

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


问题答案:

如果您一直有,object或者one-element array可以编写自定义反序列化器,如下所示:

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);
    }
}

简化后的示例模型如下所示:

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有效负载:

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

印刷品:

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

而对于object案件JSON的有效载荷:

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

印刷品:

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

如果您的媒体资源可以包含JSON objectmulti-elementarray看到我对此问题的回答(将Json数组映射到Java模型)。实现了反序列化程序,可以处理这种情况。



 类似资料:
  • 问题内容: 我有一个具有两列的DataTable。ShipmentDate(DateTime)和Count(Int)。在对字符串反序列化之后,我发现如果第一个itemarray值为null,则ShipmentDate的类型将变为字符串。 检查以下示例。除了第一个数组项,两个json字符串都具有相同的数据。 在我的场景中,第一个项目数组的ShipmentDate可以为null,并且将其转换为字符串类

  • 我有一门课是这样的: 但是当我试图序列化它时,我收到一个错误,上面写着“试图序列化java.lang.class:java.lang.字符串。忘记注册一个类型适配器了吗?”。所以我创建了这个适配器: } 并登记如下: 但我还是犯了同样的错误<我做错了什么 适配器的实现看起来正常吗?

  • 问题内容: 我有一个这样的模型: 例如,我从远程获取以下JSON: 当我反序列化此JSON时,and 变量将获得正确的值。但是我不想解释我变量的内容。相反,我希望它是以下字符串: 之后,我将自己解释。我如何获得的价值? 问题答案: Jackson问题596是为原始问题中描述的所需功能而创建的。如果要实施它,请投票。 当前可用的解决方案是实现自定义反序列化处理。 另外,如何使用Jackson将原始J

  • 我想通过Google Gson传输一个列表对象,但我不知道如何反序列化泛型类型。 我在看了这个之后尝试了什么(Balusc的回答): 编辑: 现在我有 但是,我确实在“FromJson”行得到以下异常: null

  • 我认为最好用一个例子来解释。 我有一个想要反序列化的JSON对象,它包含一个接口类型列表以及列表中的类型,但是我不确定如何让反序列化器确定列表中的具体类型: 要反序列化的类型 界面 儿童 我知道如果类型不是<code>List</code>,我可以将类型与<code>JsonSubTypes</code>一起使用,例如: 如果在父类型内,也是如此。但是当类型在类之外时,是否有一种方法可以帮助反序列

  • 问题内容: 我有这个字符串: 我正在反序列化对象: 该对象看起来像: 并尝试创建字典: 但得到。 可能是什么问题? 问题答案: 请参阅mridula的答案,了解为什么您会得到null。但是,如果您想直接将json字符串转换为字典,则可以尝试以下代码段。