2015-07-09 8 views
5

chcę analizować google pobliżu odpowiedź miejscach, pozycja ma następujący format:Jackson analizowania odpowiedzi drzewo

  "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" 

Ale chcę analizować to przy użyciu tylko jeden obiekt coś takiego:

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

Problem polega na tym, w jaki sposób uzyskać dostęp do "lat" i "lng" w "geometrii" bezpośrednio z klasy NearbyPlace bez tworzenia kolejnych klas dla każdego węzła?

+0

Czy nie powinno być gdzieś kolekcji? Albo zbiór 'NearbyPlace's lub kolekcje' lattittude's i 'longitude's inside' NearbyPlace'? –

+0

Najbliższe miejsce to przedmiot z kolekcji. – GeniDeveloper

Odpowiedz

0

Można użyć kombinacji readTree() i 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); 
} 

Jednak od vicinity trzymane na zewnątrz wewnętrznej geometrii klasy, trzeba jeszcze, aby ręcznie ustawić tę wartość. JsonNode posiada niezbędne metody:

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

Dziękuję za odpowiedź, ale używam jednego ObjectMappera do odwzorowania wszystkich typów klas: result = (T) objectMapper.readValue (resultString, aClass); Muszę więc rozwiązać mój problem wewnątrz samej klasy zmapowanej, w tym przypadku: NearbyPlace – GeniDeveloper

0

Od skończy się z kolekcją NearbyPlace s, może być najlepiej wyłączyć tylko ręcznie przemierzając JsonNode. W przeciwnym razie mówimy o nadpisywaniu deserializacji dla kolekcji lub pisaniu deserializatora, który może stać się nieprzyjemny.

Poniższy przykład jest rekurencyjny. Rekursja w Javie to bad (na razie), ale fajnie jest pisać. W aplikacji produkcyjnej polecam pętlę.

@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(); 
} 

powoduje przywrócenie listę 3 NearbyPlace s.

0

Najprostszym rozwiązaniem mogę myśleć jest użycie @JsonCreator adnotacji na NearbyPlace klasy konstruktora:

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

Możesz też dodać jakieś kontrole przed null w przypadku przychodzących JSON brakuje jakiegoś zagnieżdżonego obiektu, tj. geometry lub location.

Aby uzyskać więcej informacji, patrz: Jackson annotations documentation.

+1

Dziękuję za odpowiedź, wygląda to na przydatne, ale nie mogę tego przetestować dzisiaj. Postaram się przetestować to jutro i wyrazić opinię. – GeniDeveloper

+0

Sprawdziłem i teraz mam szerokość i długość geograficzną mieć wartość, ale wszystkie inne pola, które używa adnotacji są zerowe, masz pomysł? – GeniDeveloper

+0

Dobrze. .. havent testowane. Być może musisz wyodrębnić je z mapy delegatów w konstruktorze i przypisać każdą wartość do odpowiedniego atrybutu. –