Jednym z najczęściej wykorzystywanych sposobów by pobierać dane z usługi REST jest wykorzystanie klasy RestTemplate i przemapowanie JSON na POJO (klasy modelu).
W tym artykule pokażę jak w estetyczny sposób można operować na danych nie posiadając klas modelowych.
JsonNode
To klasa, która umożliwia na przechowywanie struktury drzewiastej obiektu JSON. Klasa ta pochodzi z pakietu com.fasterxml.jackson.databind – co oznacza, że znajduje się wewnątrz modułu Spring Web Starter i nie wymaga stosowania dodatkowych importów.
Przykład
Łączymy się z API, które ma następującą strukturę:
{ "consolidated_weather": [ { "id": 4591072749551616, "weather_state_name": "Heavy Cloud", "weather_state_abbr": "hc", "wind_direction_compass": "WNW", "created": "2019-07-25T19:10:58.841574Z", "applicable_date": "2019-07-25", "the_temp": 27.895, }, { "id": 5466136332206080, "weather_state_name": "Light Rain", "weather_state_abbr": "lr", "wind_direction_compass": "NNE", "created": "2019-07-25T19:11:01.833177Z", "applicable_date": "2019-07-26", "the_temp": 24.035, } ], "time": "2019-07-25T23:54:43.732909+02:00", "sun_rise": "2019-07-25T04:45:36.568582+02:00", "sun_set": "2019-07-25T20:38:27.238865+02:00", "timezone_name": "LMT", "parent": { "title": "Poland", "location_type": "Country", "woeid": 23424923, "latt_long": "51.918919,19.134300" }, "sources": [<->], "title": "Warsaw", "location_type": "City", "woeid": 523920, "latt_long": "52.235352,21.009390", "timezone": "Europe/Warsaw" }
Jest ona wielokrotnie zagnieżdżona i w przypadku tworzenia modeli musielibyśmy stworzyć wiele klas modelowych. Natomiast jako alternatywne można wykorzystać JsonNode.
Łączymy się z API wykorzystując klasyczne podejście jakim jest RestTemplate. Jednak w metodzie getForObject podajemy, że typem do którego przekazujemy odpowiedź (Response type) jest JsonNode.class.
public void getData() { String url = "https://www.metaweather.com/api/location/523920/"; RestTemplate restTemplate = new RestTemplate(); JsonNode forObject = restTemplate.getForObject(url, JsonNode.class).get("consolidated_weather"); for (JsonNode jsonNode : forObject) { System.out.println(jsonNode.get("weather_state_name") + " " + jsonNode.get("the_temp") + "°C"); } }
Z wykorzystaniem metody get tej klasy możemy otrzymać interesujący nas element na drzewie. W przypadku, kiedy zwracany element stanowi tablice to możemy się po niej przeliterować tak jak widać to w linii 6.
Możliwości
JsonNode może dać informacje czy element pobierany z wykorzystaniem metody get jest w rezultacie pojedynczym obiektem lub całą tablicą. Służą do tego metody:
- isArray()
- isObject()
Przed dokonaniem rzutowania można też wykorzystać szereg metod sprawdzających czy konwersja jest możliwa:
- isInt()
- isBigDecimal()
- isDouble()
- canConvertToInt()
- canConvertToLong()
Wnioski
JsonNode umożliwia łatwe i przyjemne tworzenie klientów REST. Natomiast czy uciekanie od tworzenia modelu jest dobrą praktyka?
Zazwyczaj, kiedy zależy nam na pojedynczych polach – owszem. Ale kiedy dokonujemy operacji na wielokrotnie zagnieżdżonej strukturze to dobrze dla czytelności i łatwości utrzymania kodu jest wykorzsytać klasy modelowe.