Search code examples
javaspringhibernatejacksondto

Handle 2 conversions with one DTO object


This is my first spring project. I am trying to get weather from API (openweathermap), map it to dto and only if dto is unique insert to database.

At first idea was to use two dto classes. One for API response, another for database entity (with fewer fields). It worked pretty well, but I've heard about JSON annotations like @JsonIgnoreProperties(ignoreUnknown = true) and @JsonProperty("name").

After some modifications to weatherSampleDto it worked for API request, but not for entity ↔ dto mapping anymore.

Weather API response:

{
  "coord": {
    "lon": 25.61,
    "lat": 49.56
  },
  "weather": [
    {
      "id": 804,
      "main": "Clouds",
      "description": "хмарно",
      "icon": "04n"
      …
    }
  ],
  "base": "model",
  "main": {
    "temp": 1.06,                   <-------------- temperature
    "feels_like": -2.27,            <-------------- feelsLike
    "temp_min": 1.06,
    "temp_max": 1.06,
    "pressure": 1016,               <-------------- pressure
    "humidity": 84,                 <-------------- humidity
    "sea_level": 1016,
    "grnd_level": 974
  },
  "wind": {
    "speed": 1.65,
    "deg": 281
  },
  "clouds": {
    "all": 100                      <-------------- clouds
  },
  "dt": 1580144397,                 <-------------- time
  "sys": {
    "country": "UA",
    "sunrise": 1580104637,
    "sunset": 1580137367
  },
  "timezone": 7200,
  "id": 691650,                     <-------------- cityId
  "name": "Ternopil",               <-------------- cityName
  "cod": 200
}

Here is WeatherSampleDto after modification:


@JsonIgnoreProperties(ignoreUnknown = true)
public class WeatherSampleDto implements Serializable {
    @JsonIgnore
    private Long id;
    @JsonProperty("name")
    private String cityName;
    private float temperature;
    private float feelsLike;
    private int pressure;
    private int humidity;
    private int clouds;
    private int cityId;
    @JsonProperty("dt")
    private int time;

    @JsonProperty("main")
    private void unpackMain(Map<String, String> main) {
        temperature = Float.parseFloat(main.get("temp"));
        feelsLike = Float.parseFloat(main.get("feels_like"));
        pressure = Integer.parseInt(main.get("pressure"));
        humidity = Integer.parseInt(main.get("humidity"));

    }
    @JsonProperty("clouds")
    private void unpackClouds(Map<String, Integer> cloudsObj) {
        clouds = cloudsObj.get("all");
    }
    @JsonProperty("id")
    private void unpackId(Integer idObj){
        cityId = idObj;
    }
...

And WeatherSample entity:

@Entity
public class WeatherSample {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String cityName;
    private float temperature;
    private float feelsLike;
    private int pressure;
    private int humidity;
    private int clouds;
    private int cityId;
    private int time;
...

It fails on each annotated field. Such as com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.LinkedHashMap<java.lang.Object,java.lang.Object>`out of VALUE_NUMBER_INT token at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: weather.dto.WeatherSampleDto["clouds"])

Is it possible to solve with one dto class? If so how?


Solution

  • Common implementation would be creating @Service class that gets the weather data from the API and the response model would be its own separate class then you take whatever data you need and fill the @Entity class with it then store it.