How to parse Json array of object nodes into different dto objects

Acek :

I got following Json response from weather api:

{   "data": [
    {
      "moonrise_ts": 1572876192,
      "wind_cdir": "SE",
      "rh": 84,
      "pres": 982.153,
      "high_temp": 9.3,
      "sunset_ts": 1572884637,
      "ozone": 322.467,
      "moon_phase": 0.552016,
      "wind_gust_spd": 6.28386,
      "snow_depth": 0,
      "clouds": 77,
      "ts": 1572825660,
      "sunrise_ts": 1572850839,
      "app_min_temp": 8.1,
      "wind_spd": 1.39257,
      "pop": 40,
      "wind_cdir_full": "southeast",
      "slp": 985.03,
      "valid_date": "2019-11-04",
      "app_max_temp": 12.5,
      "vis": 0,
      "dewpt": 7.7,
      "snow": 0,
      "uv": 0.697746,
      "weather": {
        "icon": "c04d",
        "code": 804,
        "description": "Overcast clouds"
      },
      "wind_dir": 134,
      "max_dhi": null,
      "clouds_hi": 0,
      "precip": 0.705078,
      "low_temp": 8.1,
      "max_temp": 12.5,
      "moonset_ts": 1572907595,
      "datetime": "2019-11-04",
      "temp": 10.3,
      "min_temp": 8.1,
      "clouds_mid": 45,
      "clouds_low": 54
    },
    {
      "moonrise_ts": 1572964153,
      "wind_cdir": "SW",
      "rh": 86,
      "pres": 993.705,
      "high_temp": 12.4,
      "sunset_ts": 1572970931,
      "ozone": 323.897,
      "moon_phase": 0.648931,
      "wind_gust_spd": 10.783,
      "snow_depth": 0,
      "clouds": 91,
      "ts": 1572912060,
      "sunrise_ts": 1572937349,
      "app_min_temp": 8,
      "wind_spd": 2.9909,
      "pop": 30,
      "wind_cdir_full": "southwest",
      "slp": 996.693,
      "valid_date": "2019-11-05",
      "app_max_temp": 12.4,
      "vis": 0,
      "dewpt": 7.5,
      "snow": 0,
      "uv": 1.5811,
      "weather": {
        "icon": "c04d",
        "code": 804,
        "description": "Overcast clouds"
      },
      "wind_dir": 226,
      "max_dhi": null,
      "clouds_hi": 4,
      "precip": 0.427734,
      "low_temp": 6,
      "max_temp": 12.4,
      "moonset_ts": 1572998028,
      "datetime": "2019-11-05",
      "temp": 9.6,
      "min_temp": 8,
      "clouds_mid": 41,
      "clouds_low": 85
    }   ],   "city_name": "London",   "lon": "-0.09184",   "timezone": "Europe/London",   "lat": "51.51279",   "country_code": "GB",   "state_code": "ENG" }

This is forecast for 2 days. I'm going to use a 16 days one so it will be much longer. However I want to split it so each days is a separete object just with the fields "city_name", "valid_date", "temp", "clouds" and "pop". How can do that, especially when the array is nested and "city_name" is outside of it. I have following deserialize class, which obviously does not work:

public class WeatherDtoDeserializer extends StdDeserializer<WeatherDto> {

    public WeatherDtoDeserializer() {
        this(null);
    }

    public WeatherDtoDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public WeatherDto deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {

        JsonNode weatherNode = jp.getCodec().readTree(jp);
        WeatherDto weatherDto = new WeatherDto();
        weatherDto.setCity(weatherNode.get("city_Name").textValue());
        weatherDto.setDate(LocalDate.parse(weatherNode.get("data").get("valid_date").textValue()));
        weatherDto.setTemperature(weatherNode.get("data").get("temp").intValue());
        weatherDto.setCloudiness(weatherNode.get("data").get("clouds").intValue());
        weatherDto.setRainfall(weatherNode.get("data").get("pop").intValue());
        return weatherDto;
    }
}

Also this is my method in WeatherApiClient to get forecast:

 public List<WeatherDto> getForecast(Airport airport) {
        URI url = UriComponentsBuilder.fromHttpUrl(getBaseUrl() +
                "city=" + airport.getCity() +
                "&country=" + airport.getCountryCode() +
                "&key=" + KEY)
                .build()
                .encode()
                .toUri();
        return Optional.ofNullable(restTemplate.getForObject(url, WeatherDto[].class))
                .map(Arrays::asList)
                .orElse(new ArrayList<>());
    }

And error I'm getting while trying to get forecast and print it out: Error

Thank you in advance.

Deadpool :

The best way i would say is first get the city_Name from JSON

String city = weatherNode.get("city_Name").textValue();

And then get the data as JSON Array of Object nodes and convert them into WeatherDto by iterating each Object node

List<WeatherDto> dtos = new ArrayList<>();
Iterator<JsonNode> itr = weatherNode.get("data").elements();

 while(itr.hasNext()) {

    JsonNode node = its.next();
    WeatherDto weatherDto = new WeatherDto();

       // set all values to weatherDto
    weatherDto.setCity(city);
    weatherDto.setDate(LocalDate.parse(node.get("valid_date").textValue()));
    weatherDto.setTemperature(node.get("temp").intValue());
    weatherDto.setCloudiness(node.get("clouds").intValue());
    weatherDto.setRainfall(node.get("pop").intValue());

    // finally add that dto to List
    dtos.add(weatherDto);

   }

 return dtos;

In order to return List<WeatherDto> you have to tweak the extends StdDeserializer<WeatherDto> to extends StdDeserializer<List<WeatherDto>>

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=323000&siteId=1