Lista obiektów z Json.

0

Witam. Dopiero się uczę i mam problem z przerobieniem Json na liste obiektów. Piszę appkę gdzie otrzymuje od API z prognozą pogody następujący Json:

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

Jest to prognoza na dwa dni, gdzie każdy dzień jest jest elementem w tablicy "data" jednak tablica ta jest zagnieżdżona (Json nie zaczyna sie od [ ). Chciałbym aby każdy dzień był u mnie osobnym obiektem. Próbowałem różnych metod i bibliotek, ale najsensownieszy wydaje mi się własny deserializer. Mój wygląda tak:

public class WeatherDtoDeserializer extends JsonDeserializer<List<WeatherDto>> {

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

        JsonNode weatherNode = jp.getCodec().readTree(jp);

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

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

        while (itr.hasNext()) {
            JsonNode node = itr.next();
            WeatherDto weatherDto = new 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());

            dtos.add(weatherDto);
        }

        return dtos;
    }
}

Niestety kiedy próbuję do zrobić dostaję następujący błąd:
https://pastebin.com/bHs37XAP

Nie wiem co mam z tym zrobić. Prosiłbym o pomoc.

Jeszcze dodam klasą na którą chce przerobić json:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@JsonDeserialize(using = WeatherDtoDeserializer.class)
public class WeatherDto {

    private Long id;
    private String city;
    private LocalDate date;
    private int temperature;
    private int cloudiness;
    private int rainfall;

    public WeatherDto(String city, LocalDate date, int temperature, int cloudiness, int rainfall) {
        this.city = city;
        this.date = date;
        this.temperature = temperature;
        this.cloudiness = cloudiness;
        this.rainfall = rainfall;
    }
}

Oraz klient API pogody:

public List<WeatherDto> getForecast(Airport airport) {
        URI url = UriComponentsBuilder.fromHttpUrl(getBaseUrl() +
                "city=" + airport.getCity() +
                "&country=" + airport.getCountryCode() +
                "&key=" + KEY)
                .build()
                .encode()
                .toUri();
        String response = restTemplate.getForObject(url, String.class);

        return Optional.ofNullable(restTemplate.getForObject(url, WeatherDto[].class))
                .map(Arrays::asList)
                .orElse(new ArrayList<>());
    }
1

próbujesz deserializować List<WeatherDto> gdzie na początku masz obiekt, który nie jest listą :) To miałoby sens, gdybyś od razu dostawał obiekt, który byłby nazwany data, i miał wpakowany w siebie obiekt List<WeatherDto>

0
IRusio napisał(a):

próbujesz deserializować List<WeatherDto> gdzie na początku masz obiekt, który nie jest listą :) To miałoby sens, gdybyś od razu dostawał obiekt, który byłby nazwany data, i miał wpakowany w siebie obiekt List<WeatherDto>

A czy możliwe w ogóle jest aby z obiektu który otrzymuję zrobić od razu liste WeatherDto czy może zrobić jeszcze dodatkową klasę która będzie w sobie przetrzymywała taką liste i wtedy zdeserializować Json na obiekt takiej klasy i później z niej wyciągać WeatherDto?

1

ogólnie spójrz sobie na https://www.jsonschema.net/, i zobacz jak wygląda schema tego obiektu, i zobacz do czego ty próbujesz parsować :)

0

Do tego, co polecił @IRusio, można jeszcze dodać plugin mavena jsonschema2pojo, który na podstawie Json Schema wygeneruje Ci gotowe POJO.

Przykładowa konfiguracja:

<plugin>
  <groupId>org.jsonschema2pojo</groupId>
  <artifactId>jsonschema2pojo-maven-plugin</artifactId>
  <version>${jsonschema2pojo.version}</version>
  <configuration>
    <useBigDecimals>true</useBigDecimals> <!-- Use BigDecimal instead of float -->
    <generateBuilders>true</generateBuilders> <!-- Generate builder methods starting, which look like "withFoo(Foo foo)", "withBar(Bar bar)" -->
  </configuration>
  <executions>
    <execution> <!-- Single execution definition with it's configuration -->
      <id>generate-json-pojos</id> <!-- id of this execution, can be named however you want  -->
      <goals>
        <goal>generate</goal> <!-- Plugin's goal which is generate, to generate sources, bound to generate-sources maven phase by default -->
      </goals>
      <configuration> <!-- execution configuration -->
        <sourceDirectory>${baseDir/src/main/resources/schema<sourceDirectory> <!-- Directory with json-schema files -->
        <outputDirectory>${project.build.directory}/generated-sources/jsonschema2pojo</outputDirectory> <!-- this is default path, so can be ommited -->
        <targetPackage>com.example.json.schema</targetPackage> <!-- Generated POJOs package -->
      </configuration>
    </execution>
  </executions>
</plugin>

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.