Gson - 在将 JSON 解析为对象时忽略 json 字段

Gson - ignore json fields when parsing JSON to Object

有一个问题 here 与我的问题相似,但不完全是我要找的问题。

我有一个来自网络服务的 JSON 响应,比方说 this JSON response

{
   "routes" : [
      {
         "bounds" : {
            "northeast" : {
               "lat" : 45.5017123,
               "lng" : -73.5672184
            },
            "southwest" : {
               "lat" : 43.6533103,
               "lng" : -79.3827675
            }
         },
         "copyrights" : "Dados do mapa ©2015 Google",
         "legs" : [
            {
               "distance" : {
                  "text" : "541 km",
                  "value" : 540536
               },
               "duration" : {
                  "text" : "5 horas 18 min.",
                  "value" : 19058
               },
               "end_address" : "Montreal, QC, Canada",
               "end_location" : {
                  "lat" : 45.5017123,
                  "lng" : -73.5672184
               },
               "start_address" : "Toronto, ON, Canada",
               "start_location" : {
                  "lat" : 43.6533103,
                  "lng" : -79.3827675
               }, 
               (...)

在这个 JSON 中,我只对 distance 对象感兴趣。我的问题是,如何忽略所有其他字段?

我尝试从 legs 开始构建我的对象,因为它是从 distance 到根的第一个非重复对象名称。

这是我的对象:

public class MyObject {

    public ArrayList<Distance> legs;

    public static class Distance {
        public String text;
        public String value;
    }
}

ArrayList legs 始终是 null

我怎样才能做到这一点?忽略假 json 字段左侧的字段。

我认为 Gson 的理念是将 Json 结构映射到对象图。所以在你的情况下,我可能会创建所有需要的 java 对象来正确映射 json 结构。除此之外,也许有一天你会需要一些其他的响应信息,这样演化就会更容易。类似的东西(我认为正确的方式):

class RouteResponse {
    private List<Route> routes;
}
class Route {
    private List<Bound> bounds;
    private String copyrights;
    private List<Leg> legs;
}
class Leg {
    private Distance distance;
    private Duration duration;
    private String endAddress;
    ...
}
class TextValue {
    private String text;
    private String value;
}
class Distance extends TextValue {
}
// And so on

而且我会使用 ExclusionStrategy 来拥有光对象并且只拥有我感兴趣的字段。在我看来这是正确的方法。

现在,如果您真的只想检索距离列表,我相信您可以使用自定义 TypeAdapter and TypeAdapterFactory

类似的东西(糟糕的方式:-)):

要映射响应的对象:

public class RouteResponse {

    private List<Distance> distances;

   // add getters / setters
}

public class Distance {

    private String text;
    private String value;

   // add getters / setters
}

实例化适配器的工厂(引用 Gson 对象,因此适配器可以检索委托):

public class RouteResponseTypeAdapterFactory implements TypeAdapterFactory {

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        if (type.getRawType() == RouteResponse.class) {
            return (TypeAdapter<T>)new RouteResponseTypeAdapter(gson);
        }
        return null;
    }
}

和类型适配器:此实现首先将 Json 文档解组为 JsonElements 树,然后检索所需的 JsonObjects 以通过委托创建 Distance 对象(抱歉代码不好,写的很快)。

public class RouteResponseTypeAdapter extends TypeAdapter<RouteResponse> {

    private final TypeAdapter<JsonElement> jsonElementTypeAdapter;
    private final TypeAdapter<Distance> distanceTypeAdapter;

    public RouteResponseTypeAdapter(Gson gson) {
        this.jsonElementTypeAdapter = gson.getAdapter(JsonElement.class);
        this.distanceTypeAdapter = gson.getAdapter(Distance.class);
    }

    @Override
    public void write(JsonWriter out, RouteResponse value) throws IOException {
        throw new UnsupportedOperationException("Not implemented");
    }

    @Override
    public RouteResponse read(JsonReader jsonReader) throws IOException {
        RouteResponse result = new RouteResponse();
        List<Distance> distances = new ArrayList<>();
        result.setDistances(distances);
        if (jsonReader.peek() == JsonToken.BEGIN_OBJECT) {
            JsonObject responseObject = (JsonObject) jsonElementTypeAdapter.read(jsonReader);
            JsonArray routes = responseObject.getAsJsonArray("routes");
            if (routes != null) {
                for (JsonElement element:routes) {
                    JsonObject route = element.getAsJsonObject();
                    JsonArray legs = route.getAsJsonArray("legs");
                    if (legs != null) {
                        for (JsonElement legElement:legs) {
                            JsonObject leg = legElement.getAsJsonObject();
                            JsonElement distanceElement = leg.get("distance");
                            if (distanceElement != null) {
                                distances.add(distanceTypeAdapter.fromJsonTree(distanceElement));
                            }
                        }
                    }
                }
            }
        }
        return result;
    }
}

最后,您可以解析您的 json 文档:

    String json = "{ routes: [ ....."; // Json document
    Gson gson = new GsonBuilder().registerTypeAdapterFactory(new RouteResponseTypeAdapterFactory()).create();
    RouteResponse response = gson.fromJson(json, RouteResponse.class);
    //response.getDistances() should contain the distances

希望对您有所帮助。