Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
408 views
in Technique[技术] by (71.8m points)

java - GSON: JSON deserialization to variable type (List/String)

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?

For some reason we have generatable Jsons of 2 types:

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

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.

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

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

Gson builder in BaseApi class just in case:

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

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

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

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.

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

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

if there is always one object, just add

json.getAsJsonArray().get(0);

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().get(0);
      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;
  }

}

if there are more objects, change field data to the list

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();
      List<Data> data = new ArrayList<Data>();
      data.add(context.deserialize(jsonElement, Data.class)) ;
      user.data = data ;
//            user.setData(new Gson().fromJson(jsonElement, new TypeToken<Data>() {}.getType()));
    }
    return user;
  }

}

and change User.class field data to List

public List<Data> data;

this is a similar topic in kotlin language link


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...