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 ?
You can use a combination of readTree()
and 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. JsonNode
has the necessary methods:
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
. 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. 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.
The easiest solution I can think of is to use the @JsonCreator
annotation on your NearbyPlace
class' constructor:
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
.
Please refer to Jackson annotations documentation for further details.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.