简体   繁体   English

使用Gson优雅地处理嵌套的json对象?

[英]Using Gson to elegantly handle nested json objects?

I'm using Gson to parse responses from a server on Android. 我正在使用Gson解析Android上服务器的响应。 Each response has some useless (to me) data on it that complicates my Gson models. 每个响应都有一些无用的(对我而言)数据,这使我的Gson模型变得复杂。 Here is the general hierarchy of json returned: 这是json返回的一般层次结构:

response: {
  date: 1406253006807,
  otherUselessData1: "This is some useless data",
  otherUselessData2: "This is some useless data",

  usefulJsonObject: {   <---- This is really the object that I care about
  }

}

Everything above or at the same level as usefulJsonObject I could really do without. 高于或等于usefulJsonObject所有东西,我真的可以没有。 The useless data is returned for every request, and the actual response is embedded beneath as the usefulJsonObject . 为每个请求返回无用的数据,实际的响应作为usefulJsonObject嵌入到下面。 This wouldn't be a big problem but it's really cluttering up my gson model objects. 这不是一个大问题,但它真的让我的gson模型对象变得混乱。

For example: Let's say I have 3 requests I can make: A, B, and C . 例如:假设我有3个请求: A,B和C. For each response it seems I need to make a minimum of 3 custom classes. 对于每个响应,我似乎需要至少制作3个自定义类。

public class ResponseA {

  @SerializedName("response") ResponseObjectA responseObject;

  public static class ResponseObjectA {
    @SerializedName("usefulJsonObject") UsefulObjectA usefulObject; 
  }

  public static class UsefulObjectA {
  }

}

I've tried a few solutions, but I haven't found anything elegant that wouldn't add an extra step to my process. 我已经尝试了一些解决方案,但我没有找到任何优雅的东西,不会给我的过程增加额外的一步。 I'm using retrofit to do my http requests and it's really nice that it just returns the fully parsed gson object to me. 我正在使用改造来做我的http请求,它真的很好,它只是将完全解析的gson对象返回给我。 I've thought of other solutions like having the useful object just be a JsonElement and then doing a 2nd gson call after the first comes back. 我想到了其他解决方案,比如让有用的对象只是一个JsonElement,然后在第一次回来之后进行第二次gson调用。 Again, not ideal. 再次,不理想。

I just wanted to know if I was missing something. 我只是想知道我是否遗漏了什么。 Surely I'm not the only one who's encountered something like this, and so I thought I'd ask how other people would handle something like this. 当然,我不是唯一一个遇到类似事情的人,所以我想我会问其他人如何处理这样的事情。

It is initialization Instance value, not NULL value. 它是初始化Instance值,而不是NULL值。 Check my example. 检查我的例子。

Address.java Address.java

public class Address {
    public Address(){
    }
}

Person.java Person.java

public class Person {
    private String name;
    private String nrc;
    private Address address;

    public Person(String name, String nrc, Address address) {
        this.name = name;
        this.nrc = nrc;
        this.address = address;
    }
}

The following Json string is equalvent to 以下Json字符串等于

Person person = new Person("Zaw Than Oo", "11111", null);

{
  "name": "Zaw Than Oo",
  "nrc": "11111"
}

The following Json string is equalvent to 以下Json字符串等于

Person person = new Person("Zaw Than Oo", "11111", new Address());

{
  "name": "Zaw Than Oo",
  "nrc": "11111",
  "address": {} <-- here use less object for you. 
}

Even if you don't create new Instance , Other lib/api (you used) may be create that instance by Reflection . 即使您没有创建新Instance ,其他lib/api (您使用过的)也可能通过Reflection创建该实例。

Short to the Point 点到点

{
    ...
    "xxx": {} --> new instance without data/value
    ...
}
{
    ...
              --> null value
    ...
}

I never found an elegant way dealing with just Gson. 我从来没有找到一个优雅的方式处理只是Gson。 I tried several options with Generics, all of which didn't work or left something to be desired. 我尝试了Generics的几个选项,所有这些选项都不起作用或留下了一些不足之处。

Since I'm using Retrofit, I decided to override the GsonConverter, and just filter out the unnecessary information from all my requests. 由于我正在使用Retrofit,我决定覆盖GsonConverter,只是从我的所有请求中过滤掉不必要的信息。 It ends up not being as flexible, as in I can't use the same Retrofit network interface for calls to other servers, but I'm not really doing that, and it also has the down side of having 2 rounds of json parsing calls (meh). 它最终没有那么灵活,因为我无法使用相同的Retrofit网络接口来调用其他服务器,但我并没有真正这样做,而且它还有两轮json解析调用的缺点(MEH)。 You could probably do this more efficiently, but this is working for me for now. 你可以更有效地做到这一点,但现在这对我有用。

public class CustomGsonConverter extends GsonConverter {

  private Gson mGson;

  public CustomGsonConverter(Gson gson) {
    super(gson);
    this.mGson = gson;
  }

  public CustomGsonConverter(Gson gson, String encoding) {
    super(gson, encoding);
    this.mGson = gson;
  }

  @Override public Object fromBody(TypedInput body, Type type) throws ConversionException {
    try {
      CustomResponse customResponse = mGson.fromJson(new InputStreamReader(body.in()), CustomResponse.class);
      return mGson.fromJson(customResponse.responseObject.data, type);
    } catch (IOException e) {
      throw new ConversionException(e);
    }
  }

  public static class CustomResponse {

    @SerializedName("rsp") ResponseObject responseObject;

    public static class ResponseObject {

//    @SerializedName("date") long date;

      @SerializedName("data") JsonElement data;

    }

  }

}

Maybe there is a better way that I'm just not realizing. 也许有一种更好的方式,我只是没有意识到。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM