简体   繁体   English

杰克逊解析树的反应

[英]Jackson parse tree response

I want to parse google nearby places response, an item have this format : 我想解析谷歌附近的地方响应,一个项目有这种格式:

         "geometry" : {
            "location" : {
               "lat" : 75.22404,
               "lng" : 57.42276
            },
            "viewport" : {
               "northeast" : {
                  "lat" : 95.2353532,
                  "lng" : 75.4427513
               },
               "southwest" : {
                  "lat" : 55.207256,
                  "lng" : 45.4045009
               }
            }
         },
         "vicinity" : "something"

But I want to parse this using only one object something like that : 但是我想用一个像这样的对象来解析它:

public class NearbyPlace extends BaseResponse {

    @JsonProperty("how to access geometry->lat ?")
    private double latitude;

    @JsonProperty("how to access geometry->lng ?")
    private double longitude;

    @JsonProperty("vicinity")
    private String vicinity;
}

The problem is how to access "lat" and "lng" in "geometry" directly from NearbyPlace class without creating another classes for each node ? 问题是如何直接从NearbyPlace类访问“几何”中的“lat”和“lng”而不为每个节点创建另一个类?

You can use a combination of readTree() and treeToValue() : 您可以使用readTree()treeToValue()

final String placesResponse = "...";
final ObjectMapper om;

NearbyPlace place = null;
final JsonNode placesNode = om.readTree(placesResponse);
final JsonNode locationNode = placesNode.findPath("geometry").findPath("location");
if (! locationNode.isMissingNode()) {
     place = om.treeToValue(locationNode, NearbyPlace.class);
}

However, since vicinity kept outside of the inner geometry class, you still need to set that value manually. 但是,由于vicinity保持在内部几何类之外,您仍需要手动设置该值。 JsonNode has the necessary methods: JsonNode有必要的方法:

final JsonNode vicinityNode = placesNode.findPath("vicinity");
if (vicinityNode.isTextual()) {
    place.vicinity = vicinityNode.textValue();
}

Since you will end up with a collection of NearbyPlace s, you may be best off just manually traversing the JsonNode . 由于您最终会得到一个NearbyPlace集合, NearbyPlace您最好只需手动遍历JsonNode Otherwise you're talking about overriding deserialization for collections, or writing a deserializer that is likely to get nasty. 否则你谈论的是对集合的重新反序列化,或者编写一个可能令人讨厌的反序列化器。

The example below is recursive. 下面的示例是递归的。 Recursion in Java is bad (for now), but fun to write. Java中的递归很糟糕 (现在),但编写很有趣。 In a production app I'd recommend a loop. 在生产应用程序中,我建议循环。

@Test
public void testNearbyPlaceDeserialization() throws Exception {
    JsonNode jsonNode = objectMapper.readTree(new File("input.json"));
    // or objectMapper.readValue(resultString, JsonNode.class);
    ImmutableList<NearbyPlace> nearbyPlaces = readLatLng(jsonNode, 
            jsonNode.get("vicinity").asText(null), 
            ImmutableList.builder());
    System.out.println(nearbyPlaces);
}

private static ImmutableList<NearbyPlace> readLatLng(JsonNode jsonNode, 
                                                     String vicinity, 
                                                     ImmutableList.Builder<NearbyPlace> placeBuilder) {
    JsonNode latNode = jsonNode.get("lat");
    JsonNode lngNode = jsonNode.get("lng");
    if (latNode != null && lngNode != null) {
        placeBuilder.add(NearbyPlace.builder()
                .setLatitude(latNode.asDouble())
                .setLongitude(lngNode.asDouble())
                .setVicinity(vicinity)
                .build());
    } else {
        jsonNode.elements().forEachRemaining((element) -> {
            readLatLng(element, vicinity, placeBuilder);
        });
    }
    return placeBuilder.build();
}

This will return a list of 3 NearbyPlace s. 这将返回3个NearbyPlace的列表。

The easiest solution I can think of is to use the @JsonCreator annotation on your NearbyPlace class' constructor: 我能想到的最简单的解决方案是在您的NearbyPlace类的构造函数上使用@JsonCreator注释:

public class NearbyPlace extends BaseResponse {

    private double latitude;

    private double longitude;

    @JsonProperty("vicinity")
    private String vicinity;

    @JsonCreator
    public NearbyPlace(Map<String, Object> delegate) {
        super();
        this.latitude = (Double) delegate.get("geometry").get("location").get("lat");
        this.latitude = (Double) delegate.get("geometry").get("location").get("lng");
    }
}

You might want to add some checks against null in case the incoming JSON lacks some nested object, ie geometry or location . 如果传入的JSON缺少某些嵌套对象(即geometrylocation ,您可能希望对null添加一些检查。

Please refer to Jackson annotations documentation for further details. 有关更多详细信息,请参阅Jackson注释文档

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

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