diff --git a/README.md b/README.md
index 1004e28..47b6ca4 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,12 @@ Free:
* 5 day / 3-hour forecast
* One Call API
* Air pollution
+* Geocoding API
+
+Paid:
+* Hourly Forecast 4 days
+* Daily Forecast 16 days
+* Climatic 30 days
Other:
* Request timeout settings
@@ -14,14 +20,15 @@ Other:
### Will be implemented later:
Free:
-* Geocoding API
* Weather Stations
* Weather Triggers
Paid:
-* Daily Forecast 16 days
-* Hourly Forecast 4 days
-* probably others...
+* Climatic Forecast 30 days
+* Bulk Downloading
+* Solar Radiation API
+* Global Weather Alerts / Push notifications
+* Road Risk API
### Maven coordinates:
diff --git a/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java b/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java
index ec052c2..3981fd6 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java
@@ -26,6 +26,7 @@ import com.github.prominence.openweathermap.api.annotation.SubscriptionAvailabil
import com.github.prominence.openweathermap.api.conf.TimeoutSettings;
import com.github.prominence.openweathermap.api.request.RequestSettings;
import com.github.prominence.openweathermap.api.request.air.pollution.AirPollutionRequester;
+import com.github.prominence.openweathermap.api.request.forecast.climatic.ClimaticForecastRequester;
import com.github.prominence.openweathermap.api.request.forecast.daily.DailyForecastRequester;
import com.github.prominence.openweathermap.api.request.forecast.free.FiveDayThreeHourStepForecastRequester;
import com.github.prominence.openweathermap.api.request.forecast.hourly.FourDaysHourlyForecastRequester;
@@ -68,15 +69,6 @@ public class OpenWeatherMapClient {
return new CurrentWeatherRequester(new RequestSettings(apiKey, timeoutSettings));
}
- /**
- * 5 Day / 3 Hour Forecast API.
- * @return requester for retrieving 5 day/3-hour weather forecast information.
- */
- @SubscriptionAvailability(plans = ALL)
- public FiveDayThreeHourStepForecastRequester forecast5Day3HourStep() {
- return new FiveDayThreeHourStepForecastRequester(new RequestSettings(apiKey, timeoutSettings));
- }
-
/**
* Hourly forecast API.
* @return requester for retrieving hourly weather forecast information for 4 days.
@@ -86,6 +78,16 @@ public class OpenWeatherMapClient {
return new FourDaysHourlyForecastRequester(new RequestSettings(apiKey, timeoutSettings));
}
+ /**
+ * One Call API.
+ * To get information about current weather, minute forecast for 1 hour, hourly forecast for 48 hours, daily forecast for 7 days and government weather alerts.
+ * @return requester for retrieving one call weather information.
+ */
+ @SubscriptionAvailability(plans = ALL)
+ public OneCallWeatherRequester oneCall() {
+ return new OneCallWeatherRequester(new RequestSettings(apiKey, timeoutSettings));
+ }
+
/**
* Daily forecast API.
* @return requester for retrieving daily weather forecast information for 16 days.
@@ -96,13 +98,21 @@ public class OpenWeatherMapClient {
}
/**
- * One Call API.
- * To get information about current weather, minute forecast for 1 hour, hourly forecast for 48 hours, daily forecast for 7 days and government weather alerts.
- * @return requester for retrieving one call weather information.
+ * Climatic forecast API.
+ * @return requester for retrieving climatic weather forecast information for 30 days.
+ */
+ @SubscriptionAvailability(plans = { DEVELOPER, PROFESSIONAL, ENTERPRISE })
+ public ClimaticForecastRequester climaticForecast30Days() {
+ return new ClimaticForecastRequester(new RequestSettings(apiKey, timeoutSettings));
+ }
+
+ /**
+ * 5 Day / 3 Hour Forecast API.
+ * @return requester for retrieving 5 day/3-hour weather forecast information.
*/
@SubscriptionAvailability(plans = ALL)
- public OneCallWeatherRequester oneCall() {
- return new OneCallWeatherRequester(new RequestSettings(apiKey, timeoutSettings));
+ public FiveDayThreeHourStepForecastRequester forecast5Day3HourStep() {
+ return new FiveDayThreeHourStepForecastRequester(new RequestSettings(apiKey, timeoutSettings));
}
/**
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastAtmosphericPressureDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastAtmosphericPressureDeserializer.java
new file mode 100644
index 0000000..187c805
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastAtmosphericPressureDeserializer.java
@@ -0,0 +1,18 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.climatic;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.AtmosphericPressure;
+
+import java.io.IOException;
+
+public class ClimaticForecastAtmosphericPressureDeserializer extends JsonDeserializer {
+ @Override
+ public AtmosphericPressure deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode jsonNode = jsonParser.getCodec().readTree(jsonParser);
+ return (AtmosphericPressure) AtmosphericPressure.withValue(jsonNode.get("pressure").asDouble());
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastCloudsDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastCloudsDeserializer.java
new file mode 100644
index 0000000..95bf04c
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastCloudsDeserializer.java
@@ -0,0 +1,23 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.climatic;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.Clouds;
+
+import java.io.IOException;
+
+public class ClimaticForecastCloudsDeserializer extends JsonDeserializer {
+ @Override
+ public Clouds deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+ final JsonNode cloudsNode = rootNode.get("clouds");
+ if (cloudsNode != null) {
+ return Clouds.withValue((byte) cloudsNode.asInt());
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastLocationDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastLocationDeserializer.java
new file mode 100644
index 0000000..97fe05d
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastLocationDeserializer.java
@@ -0,0 +1,54 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.climatic;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.github.prominence.openweathermap.api.deserializer.CoordinatesDeserializer;
+import com.github.prominence.openweathermap.api.model.Coordinates;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.Location;
+
+import java.io.IOException;
+
+import static com.github.prominence.openweathermap.api.utils.JsonDeserializationUtils.parseZoneOffset;
+
+public class ClimaticForecastLocationDeserializer extends JsonDeserializer {
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ public ClimaticForecastLocationDeserializer() {
+ final SimpleModule module = new SimpleModule();
+ module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
+ objectMapper.registerModule(module);
+ }
+
+ @Override
+ public Location deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+ final Location location = (Location) Location.withValues(rootNode.get("id").asInt(), rootNode.get("name").asText());
+
+ final JsonNode timezoneNode = rootNode.get("timezone");
+ if (timezoneNode != null) {
+ location.setZoneOffset(parseZoneOffset(timezoneNode));
+ }
+
+ final JsonNode countryNode = rootNode.get("country");
+ if (countryNode != null) {
+ location.setCountryCode(countryNode.asText());
+ }
+
+ final JsonNode coordNode = rootNode.get("coord");
+ if (coordNode != null) {
+ location.setCoordinate(objectMapper.readValue(objectMapper.treeAsTokens(coordNode), Coordinates.class));
+ }
+
+ final JsonNode populationNode = rootNode.get("population");
+ if (populationNode != null) {
+ location.setPopulation(populationNode.asLong());
+ }
+
+ return location;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastRainDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastRainDeserializer.java
new file mode 100644
index 0000000..4af8413
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastRainDeserializer.java
@@ -0,0 +1,22 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.climatic;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.Rain;
+
+import java.io.IOException;
+
+public class ClimaticForecastRainDeserializer extends JsonDeserializer {
+ @Override
+ public Rain deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+ final JsonNode rainNode = rootNode.get("rain");
+ if (rainNode != null) {
+ return (Rain) Rain.withValue(rainNode.asDouble());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastSnowDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastSnowDeserializer.java
new file mode 100644
index 0000000..b7ca77a
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastSnowDeserializer.java
@@ -0,0 +1,22 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.climatic;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.Snow;
+
+import java.io.IOException;
+
+public class ClimaticForecastSnowDeserializer extends JsonDeserializer {
+ @Override
+ public Snow deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+ final JsonNode snowNode = rootNode.get("snow");
+ if (snowNode != null) {
+ return (Snow) Snow.withValue(snowNode.asDouble());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastTemperatureDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastTemperatureDeserializer.java
new file mode 100644
index 0000000..10d27f9
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastTemperatureDeserializer.java
@@ -0,0 +1,34 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.climatic;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.Temperature;
+
+import java.io.IOException;
+
+public class ClimaticForecastTemperatureDeserializer extends JsonDeserializer {
+ @Override
+ public Temperature deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+
+ final Temperature temperature = new Temperature();
+ final JsonNode tempNode = rootNode.get("temp");
+ temperature.setMorning(tempNode.get("morn").asDouble());
+ temperature.setDay(tempNode.get("day").asDouble());
+ temperature.setEve(tempNode.get("eve").asDouble());
+ temperature.setNight(tempNode.get("night").asDouble());
+ temperature.setMin(tempNode.get("min").asDouble());
+ temperature.setMax(tempNode.get("max").asDouble());
+
+ final JsonNode feelsLikeNode = rootNode.get("feels_like");
+ temperature.setMorningFeelsLike(feelsLikeNode.get("morn").asDouble());
+ temperature.setDayFeelsLike(feelsLikeNode.get("day").asDouble());
+ temperature.setEveFeelsLike(feelsLikeNode.get("eve").asDouble());
+ temperature.setNightFeelsLike(feelsLikeNode.get("night").asDouble());
+
+ return temperature;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastWindDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastWindDeserializer.java
new file mode 100644
index 0000000..3f4fc96
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/climatic/ClimaticForecastWindDeserializer.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.deserializer.forecast.climatic;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.enums.UnitSystem;
+import com.github.prominence.openweathermap.api.model.Wind;
+
+import java.io.IOException;
+
+public class ClimaticForecastWindDeserializer extends JsonDeserializer {
+ @Override
+ public Wind deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
+ final JsonNode windNode = p.getCodec().readTree(p);
+ final UnitSystem unitSystem = (UnitSystem) ctxt.findInjectableValue("unitSystem", null, null);
+
+ JsonNode speedNode = windNode.get("speed");
+ if (speedNode == null) {
+ speedNode = windNode.get("wind_speed");
+ }
+ double speed = speedNode.asDouble();
+
+ final Wind wind = Wind.withValue(speed, unitSystem.getWindUnit());
+ JsonNode degNode = windNode.get("deg");
+ if (degNode == null) {
+ degNode = windNode.get("wind_deg");
+ }
+ if (degNode != null) {
+ wind.setDegrees(degNode.asDouble());
+ }
+
+ return wind;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastAtmosphericPressureDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastAtmosphericPressureDeserializer.java
new file mode 100644
index 0000000..42a5a84
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastAtmosphericPressureDeserializer.java
@@ -0,0 +1,18 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.daily;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.forecast.daily.AtmosphericPressure;
+
+import java.io.IOException;
+
+public class DailyForecastAtmosphericPressureDeserializer extends JsonDeserializer {
+ @Override
+ public AtmosphericPressure deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode jsonNode = jsonParser.getCodec().readTree(jsonParser);
+ return (AtmosphericPressure) AtmosphericPressure.withValue(jsonNode.get("pressure").asDouble());
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastCloudsDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastCloudsDeserializer.java
new file mode 100644
index 0000000..8b23c9f
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastCloudsDeserializer.java
@@ -0,0 +1,23 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.daily;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.Clouds;
+
+import java.io.IOException;
+
+public class DailyForecastCloudsDeserializer extends JsonDeserializer {
+ @Override
+ public Clouds deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+ final JsonNode cloudsNode = rootNode.get("clouds");
+ if (cloudsNode != null) {
+ return Clouds.withValue((byte) cloudsNode.asInt());
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastLocationDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastLocationDeserializer.java
new file mode 100644
index 0000000..0297c2a
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastLocationDeserializer.java
@@ -0,0 +1,54 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.daily;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.github.prominence.openweathermap.api.deserializer.CoordinatesDeserializer;
+import com.github.prominence.openweathermap.api.model.Coordinates;
+import com.github.prominence.openweathermap.api.model.forecast.daily.Location;
+
+import java.io.IOException;
+
+import static com.github.prominence.openweathermap.api.utils.JsonDeserializationUtils.parseZoneOffset;
+
+public class DailyForecastLocationDeserializer extends JsonDeserializer {
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ public DailyForecastLocationDeserializer() {
+ final SimpleModule module = new SimpleModule();
+ module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
+ objectMapper.registerModule(module);
+ }
+
+ @Override
+ public Location deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+ final Location location = (Location) Location.withValues(rootNode.get("id").asInt(), rootNode.get("name").asText());
+
+ final JsonNode timezoneNode = rootNode.get("timezone");
+ if (timezoneNode != null) {
+ location.setZoneOffset(parseZoneOffset(timezoneNode));
+ }
+
+ final JsonNode countryNode = rootNode.get("country");
+ if (countryNode != null) {
+ location.setCountryCode(countryNode.asText());
+ }
+
+ final JsonNode coordNode = rootNode.get("coord");
+ if (coordNode != null) {
+ location.setCoordinate(objectMapper.readValue(objectMapper.treeAsTokens(coordNode), Coordinates.class));
+ }
+
+ final JsonNode populationNode = rootNode.get("population");
+ if (populationNode != null) {
+ location.setPopulation(populationNode.asLong());
+ }
+
+ return location;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastRainDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastRainDeserializer.java
new file mode 100644
index 0000000..9e2d604
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastRainDeserializer.java
@@ -0,0 +1,22 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.daily;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.forecast.daily.Rain;
+
+import java.io.IOException;
+
+public class DailyForecastRainDeserializer extends JsonDeserializer {
+ @Override
+ public Rain deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+ final JsonNode rainNode = rootNode.get("rain");
+ if (rainNode != null) {
+ return (Rain) Rain.withValue(rainNode.asDouble());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastSnowDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastSnowDeserializer.java
new file mode 100644
index 0000000..3f8a46b
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastSnowDeserializer.java
@@ -0,0 +1,22 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.daily;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.forecast.daily.Snow;
+
+import java.io.IOException;
+
+public class DailyForecastSnowDeserializer extends JsonDeserializer {
+ @Override
+ public Snow deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+ final JsonNode snowNode = rootNode.get("snow");
+ if (snowNode != null) {
+ return (Snow) Snow.withValue(snowNode.asDouble());
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastTemperatureDeserializer.java b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastTemperatureDeserializer.java
new file mode 100644
index 0000000..3384664
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/deserializer/forecast/daily/DailyForecastTemperatureDeserializer.java
@@ -0,0 +1,34 @@
+package com.github.prominence.openweathermap.api.deserializer.forecast.daily;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.prominence.openweathermap.api.model.forecast.daily.Temperature;
+
+import java.io.IOException;
+
+public class DailyForecastTemperatureDeserializer extends JsonDeserializer {
+ @Override
+ public Temperature deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
+ final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
+
+ final Temperature temperature = new Temperature();
+ final JsonNode tempNode = rootNode.get("temp");
+ temperature.setMorning(tempNode.get("morn").asDouble());
+ temperature.setDay(tempNode.get("day").asDouble());
+ temperature.setEve(tempNode.get("eve").asDouble());
+ temperature.setNight(tempNode.get("night").asDouble());
+ temperature.setMin(tempNode.get("min").asDouble());
+ temperature.setMax(tempNode.get("max").asDouble());
+
+ final JsonNode feelsLikeNode = rootNode.get("feels_like");
+ temperature.setMorningFeelsLike(feelsLikeNode.get("morn").asDouble());
+ temperature.setDayFeelsLike(feelsLikeNode.get("day").asDouble());
+ temperature.setEveFeelsLike(feelsLikeNode.get("eve").asDouble());
+ temperature.setNightFeelsLike(feelsLikeNode.get("night").asDouble());
+
+ return temperature;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/mapper/ClimaticForecastResponseMapper.java b/src/main/java/com/github/prominence/openweathermap/api/mapper/ClimaticForecastResponseMapper.java
new file mode 100644
index 0000000..4dcc37e
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/mapper/ClimaticForecastResponseMapper.java
@@ -0,0 +1,84 @@
+package com.github.prominence.openweathermap.api.mapper;
+
+import com.fasterxml.jackson.databind.InjectableValues;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.github.prominence.openweathermap.api.deserializer.HumidityDeserializer;
+import com.github.prominence.openweathermap.api.deserializer.WeatherStateDeserializer;
+import com.github.prominence.openweathermap.api.deserializer.forecast.climatic.*;
+import com.github.prominence.openweathermap.api.enums.UnitSystem;
+import com.github.prominence.openweathermap.api.model.Clouds;
+import com.github.prominence.openweathermap.api.model.Humidity;
+import com.github.prominence.openweathermap.api.model.WeatherState;
+import com.github.prominence.openweathermap.api.model.Wind;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClimaticForecastResponseMapper extends AbstractMapper {
+
+ public ClimaticForecastResponseMapper(UnitSystem unitSystem) {
+ objectMapper.setInjectableValues(new InjectableValues.Std().addValue("unitSystem", unitSystem != null ? unitSystem : UnitSystem.STANDARD));
+ final SimpleModule module = new SimpleModule();
+ module.addDeserializer(WeatherState.class, new WeatherStateDeserializer());
+ module.addDeserializer(Temperature.class, new ClimaticForecastTemperatureDeserializer());
+ module.addDeserializer(AtmosphericPressure.class, new ClimaticForecastAtmosphericPressureDeserializer());
+ module.addDeserializer(Humidity.class, new HumidityDeserializer());
+ module.addDeserializer(Clouds.class, new ClimaticForecastCloudsDeserializer());
+ module.addDeserializer(Rain.class, new ClimaticForecastRainDeserializer());
+ module.addDeserializer(Snow.class, new ClimaticForecastSnowDeserializer());
+ module.addDeserializer(Wind.class, new ClimaticForecastWindDeserializer());
+ module.addDeserializer(Location.class, new ClimaticForecastLocationDeserializer());
+ objectMapper.registerModule(module);
+ }
+
+ public Forecast mapToForecast(String json) {
+ Forecast forecast;
+ try {
+ final JsonNode root = objectMapper.readTree(json);
+ forecast = mapToForecast(root);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot parse Forecast response", e);
+ }
+
+ return forecast;
+ }
+
+ private Forecast mapToForecast(JsonNode root) throws IOException {
+ final Forecast forecast = new Forecast();
+ forecast.setLocation(objectMapper.readValue(objectMapper.treeAsTokens(root.get("city")), Location.class));
+
+ final List forecasts = new ArrayList<>();
+
+ final JsonNode forecastListNode = root.get("list");
+ for (JsonNode forecastNode : forecastListNode) {
+ forecasts.add(parseWeatherForecast(forecastNode));
+ }
+
+ forecast.setWeatherForecasts(forecasts);
+
+ return forecast;
+ }
+
+ private WeatherForecast parseWeatherForecast(JsonNode rootNode) throws IOException {
+ final WeatherForecast weatherForecast = new WeatherForecast();
+
+ weatherForecast.setForecastTime(parseDateTime(rootNode.get("dt")));
+ weatherForecast.setSunriseTime(parseDateTime(rootNode.get("sunrise")));
+ weatherForecast.setSunsetTime(parseDateTime(rootNode.get("sunset")));
+
+ weatherForecast.setWeatherStates(parseWeatherStates(rootNode.get("weather")));
+
+ weatherForecast.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Temperature.class));
+ weatherForecast.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), AtmosphericPressure.class));
+ weatherForecast.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Humidity.class));
+ weatherForecast.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Clouds.class));
+ weatherForecast.setWind(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Wind.class));
+ weatherForecast.setRain(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Rain.class));
+ weatherForecast.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Snow.class));
+
+ return weatherForecast;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/mapper/CurrentWeatherResponseMapper.java b/src/main/java/com/github/prominence/openweathermap/api/mapper/CurrentWeatherResponseMapper.java
index bbbc1b7..08a7968 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/mapper/CurrentWeatherResponseMapper.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/mapper/CurrentWeatherResponseMapper.java
@@ -22,22 +22,21 @@
package com.github.prominence.openweathermap.api.mapper;
-import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.InjectableValues;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.github.prominence.openweathermap.api.deserializer.*;
import com.github.prominence.openweathermap.api.deserializer.weather.WeatherLocationDeserializer;
import com.github.prominence.openweathermap.api.deserializer.weather.WeatherRainDeserializer;
import com.github.prominence.openweathermap.api.deserializer.weather.WeatherSnowDeserializer;
-import com.github.prominence.openweathermap.api.model.weather.*;
import com.github.prominence.openweathermap.api.enums.UnitSystem;
import com.github.prominence.openweathermap.api.model.*;
+import com.github.prominence.openweathermap.api.model.weather.Location;
+import com.github.prominence.openweathermap.api.model.weather.Rain;
+import com.github.prominence.openweathermap.api.model.weather.Snow;
+import com.github.prominence.openweathermap.api.model.weather.Weather;
import java.io.IOException;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.TimeZone;
/**
* Official API response documentation: https://openweathermap.org/current#current_JSON.
@@ -86,13 +85,7 @@ public class CurrentWeatherResponseMapper extends AbstractMapper {
final JsonNode weatherArrayNode = rootNode.get("weather");
final Weather weather = new Weather();
- final List weatherStateList = new ArrayList<>();
- if (weatherArrayNode != null && weatherArrayNode.isArray()) {
- for (JsonNode weatherNode : weatherArrayNode) {
- weatherStateList.add(objectMapper.readValue(objectMapper.treeAsTokens(weatherNode), WeatherState.class));
- }
- weather.setWeatherStates(weatherStateList);
- }
+ weather.setWeatherStates(parseWeatherStates(weatherArrayNode));
weather.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("main")), Temperature.class));
weather.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("main")), AtmosphericPressure.class));
diff --git a/src/main/java/com/github/prominence/openweathermap/api/mapper/DailyForecastResponseMapper.java b/src/main/java/com/github/prominence/openweathermap/api/mapper/DailyForecastResponseMapper.java
index 99bb0e9..4af016b 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/mapper/DailyForecastResponseMapper.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/mapper/DailyForecastResponseMapper.java
@@ -22,33 +22,41 @@
package com.github.prominence.openweathermap.api.mapper;
+import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.github.prominence.openweathermap.api.deserializer.HumidityDeserializer;
+import com.github.prominence.openweathermap.api.deserializer.WeatherStateDeserializer;
+import com.github.prominence.openweathermap.api.deserializer.WindDeserializer;
+import com.github.prominence.openweathermap.api.deserializer.forecast.daily.*;
import com.github.prominence.openweathermap.api.enums.UnitSystem;
import com.github.prominence.openweathermap.api.model.Clouds;
-import com.github.prominence.openweathermap.api.model.Coordinates;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.Wind;
import com.github.prominence.openweathermap.api.model.forecast.daily.*;
import java.io.IOException;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
-import java.util.TimeZone;
/**
* Official API response documentation: https://openweathermap.org/forecast16#JSON.
*/
-public class DailyForecastResponseMapper {
- private final ObjectMapper objectMapper = new ObjectMapper();
- private final UnitSystem unitSystem;
-
+public class DailyForecastResponseMapper extends AbstractMapper {
public DailyForecastResponseMapper(UnitSystem unitSystem) {
- this.unitSystem = unitSystem;
+ objectMapper.setInjectableValues(new InjectableValues.Std().addValue("unitSystem", unitSystem != null ? unitSystem : UnitSystem.STANDARD));
+ final SimpleModule module = new SimpleModule();
+ module.addDeserializer(WeatherState.class, new WeatherStateDeserializer());
+ module.addDeserializer(Temperature.class, new DailyForecastTemperatureDeserializer());
+ module.addDeserializer(AtmosphericPressure.class, new DailyForecastAtmosphericPressureDeserializer());
+ module.addDeserializer(Humidity.class, new HumidityDeserializer());
+ module.addDeserializer(Clouds.class, new DailyForecastCloudsDeserializer());
+ module.addDeserializer(Rain.class, new DailyForecastRainDeserializer());
+ module.addDeserializer(Snow.class, new DailyForecastSnowDeserializer());
+ module.addDeserializer(Wind.class, new WindDeserializer());
+ module.addDeserializer(Location.class, new DailyForecastLocationDeserializer());
+ objectMapper.registerModule(module);
}
/**
@@ -63,7 +71,7 @@ public class DailyForecastResponseMapper {
final JsonNode root = objectMapper.readTree(json);
forecast = mapToForecast(root);
} catch (IOException e) {
- throw new RuntimeException("Cannot parse Forecast response");
+ throw new RuntimeException("Cannot parse Forecast response", e);
}
return forecast;
@@ -71,7 +79,7 @@ public class DailyForecastResponseMapper {
private Forecast mapToForecast(JsonNode root) throws IOException {
final Forecast forecast = new Forecast();
- forecast.setLocation(parseLocation(root.get("city")));
+ forecast.setLocation(objectMapper.readValue(objectMapper.treeAsTokens(root.get("city")), Location.class));
final List forecasts = new ArrayList<>(root.get("cnt").asInt());
@@ -87,124 +95,25 @@ public class DailyForecastResponseMapper {
private WeatherForecast parseWeatherForecast(JsonNode rootNode) throws IOException {
final WeatherForecast weatherForecast = new WeatherForecast();
- final JsonNode weatherArrayNode = rootNode.get("weather");
- if (weatherArrayNode != null) {
- final JsonNode weatherNode = weatherArrayNode.get(0);
- weatherForecast.setWeatherState(parseWeatherState(weatherNode));
+
+ weatherForecast.setForecastTime(parseDateTime(rootNode.get("dt")));
+ weatherForecast.setSunriseTime(parseDateTime(rootNode.get("sunrise")));
+ weatherForecast.setSunsetTime(parseDateTime(rootNode.get("sunset")));
+
+ weatherForecast.setWeatherStates(parseWeatherStates(rootNode.get("weather")));
+
+ weatherForecast.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Temperature.class));
+ weatherForecast.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), AtmosphericPressure.class));
+ weatherForecast.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Humidity.class));
+ weatherForecast.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Clouds.class));
+ weatherForecast.setWind(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Wind.class));
+ weatherForecast.setRain(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Rain.class));
+ weatherForecast.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Snow.class));
+
+ if (rootNode.has("pop")) {
+ weatherForecast.setProbabilityOfPrecipitation(rootNode.get("pop").asDouble());
}
- final JsonNode mainNode = rootNode.get("main");
- weatherForecast.setTemperature(parseTemperature(mainNode));
- weatherForecast.setAtmosphericPressure(parsePressure(mainNode));
- weatherForecast.setHumidity(parseHumidity(mainNode));
- weatherForecast.setClouds(parseClouds(rootNode));
- weatherForecast.setWind(parseWind(rootNode));
- weatherForecast.setRain(parseRain(rootNode));
- weatherForecast.setSnow(parseSnow(rootNode));
-
- weatherForecast.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(rootNode.get("dt").asLong()), TimeZone.getDefault().toZoneId()));
-
return weatherForecast;
}
-
- private WeatherState parseWeatherState(JsonNode weatherNode) throws IOException {
- if (weatherNode == null) {
- return null;
- }
- return objectMapper.readValue(objectMapper.treeAsTokens(weatherNode), WeatherState.class);
- }
-
- private Temperature parseTemperature(JsonNode rootNode) {
- final Temperature temperature = new Temperature();
- final JsonNode tempNode = rootNode.get("temp");
- temperature.setMorning(tempNode.get("morn").asDouble());
- temperature.setDay(tempNode.get("day").asDouble());
- temperature.setEve(tempNode.get("eve").asDouble());
- temperature.setNight(tempNode.get("night").asDouble());
- temperature.setMin(tempNode.get("min").asDouble());
- temperature.setMax(tempNode.get("max").asDouble());
-
- final JsonNode feelsLikeNode = rootNode.get("feels_like");
- temperature.setMorningFeelsLike(feelsLikeNode.get("morn").asDouble());
- temperature.setDayFeelsLike(feelsLikeNode.get("day").asDouble());
- temperature.setEveFeelsLike(feelsLikeNode.get("eve").asDouble());
- temperature.setNightFeelsLike(feelsLikeNode.get("night").asDouble());
-
- return temperature;
- }
-
- private AtmosphericPressure parsePressure(JsonNode rootNode) {
- return AtmosphericPressure.withValue(rootNode.get("pressure").asDouble());
- }
-
- private Humidity parseHumidity(JsonNode rootNode) {
- return Humidity.withValue((byte) (rootNode.get("humidity").asInt()));
- }
-
- private Wind parseWind(JsonNode root) throws IOException {
- final JsonNode windNode = root.get("wind");
- return objectMapper.readValue(objectMapper.treeAsTokens(windNode), Wind.class);
- }
-
- private Rain parseRain(JsonNode root) {
- final JsonNode rainNode = root.get("rain");
- if (rainNode != null) {
- final JsonNode threeHourNode = rainNode.get("3h");
- if (threeHourNode != null) {
- return Rain.withThreeHourLevelValue(threeHourNode.asDouble());
- }
- }
- return null;
- }
-
- private Snow parseSnow(JsonNode root) {
- final JsonNode snowNode = root.get("snow");
- if (snowNode != null) {
- final JsonNode threeHourNode = snowNode.get("3h");
- if (threeHourNode != null) {
- return Snow.withThreeHourLevelValue(threeHourNode.asDouble());
- }
- }
- return null;
- }
-
- private Clouds parseClouds(JsonNode rootNode) {
- final JsonNode cloudsNode = rootNode.get("clouds");
- final JsonNode allValueNode = cloudsNode.get("all");
- if (allValueNode != null) {
- return Clouds.withValue((byte) allValueNode.asInt());
- }
-
- return null;
- }
-
- private Location parseLocation(JsonNode rootNode) {
- final Location location = Location.withValues(rootNode.get("id").asInt(), rootNode.get("name").asText());
-
- final JsonNode timezoneNode = rootNode.get("timezone");
- if (timezoneNode != null) {
- location.setZoneOffset(ZoneOffset.ofTotalSeconds(timezoneNode.asInt()));
- }
-
- final JsonNode countryNode = rootNode.get("country");
- if (countryNode != null) {
- location.setCountryCode(countryNode.asText());
- }
-
- final JsonNode coordNode = rootNode.get("coord");
- if (coordNode != null) {
- location.setCoordinate(parseCoordinate(coordNode));
- }
-
- return location;
- }
-
- private Coordinates parseCoordinate(JsonNode rootNode) {
- final JsonNode latitudeNode = rootNode.get("lat");
- final JsonNode longitudeNode = rootNode.get("lon");
- if (latitudeNode != null && longitudeNode != null) {
- return Coordinates.of(latitudeNode.asDouble(), longitudeNode.asDouble());
- }
- return null;
- }
}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/mapper/GeocodingResponseMapper.java b/src/main/java/com/github/prominence/openweathermap/api/mapper/GeocodingResponseMapper.java
index 6f76190..135c772 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/mapper/GeocodingResponseMapper.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/mapper/GeocodingResponseMapper.java
@@ -28,8 +28,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.github.prominence.openweathermap.api.deserializer.GeocodingRecordDeserializer;
import com.github.prominence.openweathermap.api.deserializer.ZipCodeGeocodingDeserializer;
-import com.github.prominence.openweathermap.api.model.geocoding.ZipCodeGeocodingRecord;
import com.github.prominence.openweathermap.api.model.geocoding.GeocodingRecord;
+import com.github.prominence.openweathermap.api.model.geocoding.ZipCodeGeocodingRecord;
import java.util.List;
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/AtmosphericPressure.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/AtmosphericPressure.java
new file mode 100644
index 0000000..164a524
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/AtmosphericPressure.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2021 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.model.forecast.climatic;
+
+import java.util.Objects;
+
+/**
+ * The AtmosphericPressure type represents atmospheric pressure value.
+ * Its value can only be a double in [0, +∞) range.
+ */
+public class AtmosphericPressure {
+ private static final String DEFAULT_UNIT = "hPa";
+
+ private double seaLevelValue;
+
+ protected AtmosphericPressure() {
+ }
+
+ /**
+ * Static method for {@link AtmosphericPressure} creation with value checking.
+ * @param seaLevelValue atmospheric pressure value.
+ * @return instantiated {@link AtmosphericPressure} object.
+ */
+ public static AtmosphericPressure withValue(double seaLevelValue) {
+ final AtmosphericPressure atmosphericPressure = new AtmosphericPressure();
+ atmosphericPressure.setSeaLevelValue(seaLevelValue);
+ return atmosphericPressure;
+ }
+
+ /**
+ * Gets sea level value.
+ *
+ * @return the sea level value.
+ */
+ public Double getSeaLevelValue() {
+ return seaLevelValue;
+ }
+
+ /**
+ * Sets sea level value.
+ *
+ * @param seaLevelValue the sea level value.
+ * @throws IllegalArgumentException in case if provided value isn't in allowed range.
+ */
+ public void setSeaLevelValue(double seaLevelValue) {
+ if (seaLevelValue < 0) {
+ throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range.");
+ }
+ this.seaLevelValue = seaLevelValue;
+ }
+
+ /**
+ * Returns pressure unitSystem. Constantly equals to 'hPa'.
+ *
+ * @return the pressure unitSystem.
+ */
+ public String getUnit() {
+ return DEFAULT_UNIT;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AtmosphericPressure that = (AtmosphericPressure) o;
+ return Double.compare(that.seaLevelValue, seaLevelValue) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(seaLevelValue);
+ }
+
+ @Override
+ public String toString() {
+ return "Pressure: " + seaLevelValue + ' ' + getUnit();
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Forecast.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Forecast.java
new file mode 100644
index 0000000..e36295a
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Forecast.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2022 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.model.forecast.climatic;
+
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents information about forecast for different timestamps.
+ */
+public class Forecast {
+ private Location location;
+ private List extends WeatherForecast> weatherForecasts;
+
+ /**
+ * Returns location information.
+ * @return location
+ */
+ public Location getLocation() {
+ return location;
+ }
+
+ /**
+ * Sets forecast location.
+ * @param location forecast location
+ */
+ public void setLocation(Location location) {
+ this.location = location;
+ }
+
+ /**
+ * Returns list of weather forecasts for different timestamps.
+ * @return list of forecast-per-timestamp information.
+ */
+ public List extends WeatherForecast> getWeatherForecasts() {
+ return weatherForecasts;
+ }
+
+ /**
+ * Sets list of weather forecasts for different timestamps.
+ * @param weatherForecasts list of forecast information
+ */
+ public void setWeatherForecasts(List extends WeatherForecast> weatherForecasts) {
+ this.weatherForecasts = weatherForecasts;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Forecast forecast = (Forecast) o;
+ return Objects.equals(location, forecast.location) && Objects.equals(weatherForecasts, forecast.weatherForecasts);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(location, weatherForecasts);
+ }
+
+ @Override
+ public String toString() {
+ return "A forecast for " + location.getName() + " with " + weatherForecasts.size() + " timestamps.";
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Location.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Location.java
new file mode 100644
index 0000000..f541191
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Location.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2022 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.model.forecast.climatic;
+
+import com.github.prominence.openweathermap.api.model.Coordinates;
+
+import java.time.ZoneOffset;
+import java.util.Objects;
+
+/**
+ * Represents location information.
+ */
+public class Location {
+ private int id;
+ private String name;
+ private String countryCode;
+
+ private ZoneOffset zoneOffset;
+
+ private Coordinates coordinates;
+
+ private Long population;
+
+ protected Location(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ /**
+ * Creates {@link Location} object with correctness check.
+ * @param id location id
+ * @param name location name
+ * @return location object
+ */
+ public static Location withValues(int id, String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("Name must be set.");
+ }
+ return new Location(id, name);
+ }
+
+ /**
+ * Returns ID.
+ * @return location ID
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Sets location ID.
+ * @param id location id
+ */
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns location name.
+ * @return location name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets location name.
+ * @param name location name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns country code.
+ * @return location country code
+ */
+ public String getCountryCode() {
+ return countryCode;
+ }
+
+ /**
+ * Sets location country code.
+ * @param countryCode location country code
+ */
+ public void setCountryCode(String countryCode) {
+ this.countryCode = countryCode;
+ }
+
+ /**
+ * Returns location timezone offset.
+ * @return timezone offset
+ */
+ public ZoneOffset getZoneOffset() {
+ return zoneOffset;
+ }
+
+ /**
+ * Sets location timezone offset.
+ * @param zoneOffset timezone offset
+ */
+ public void setZoneOffset(ZoneOffset zoneOffset) {
+ this.zoneOffset = zoneOffset;
+ }
+
+ /**
+ * Returns location coordinates.
+ * @return location coordinates.
+ */
+ public Coordinates getCoordinate() {
+ return coordinates;
+ }
+
+ /**
+ * Sets location coordinates.
+ * @param coordinates location coordinates
+ */
+ public void setCoordinate(Coordinates coordinates) {
+ this.coordinates = coordinates;
+ }
+
+ /**
+ * Sets location population.
+ * @return location population
+ */
+ public Long getPopulation() {
+ return population;
+ }
+
+ /**
+ * Sets location population.
+ * @param population location population
+ */
+ public void setPopulation(Long population) {
+ this.population = population;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Location)) return false;
+ Location location = (Location) o;
+ return id == location.id &&
+ Objects.equals(name, location.name) &&
+ Objects.equals(countryCode, location.countryCode) &&
+ Objects.equals(zoneOffset, location.zoneOffset) &&
+ Objects.equals(coordinates, location.coordinates) &&
+ Objects.equals(population, location.population);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name, countryCode, zoneOffset, coordinates, population);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder stringBuilder = new StringBuilder();
+ if (coordinates != null) {
+ stringBuilder.append(coordinates);
+ stringBuilder.append(". ");
+ }
+ stringBuilder.append("ID: ");
+ stringBuilder.append(id);
+ stringBuilder.append(", Name: ");
+ stringBuilder.append(name);
+ if (countryCode != null) {
+ stringBuilder.append('(');
+ stringBuilder.append(countryCode);
+ stringBuilder.append(')');
+ }
+ if (population != null) {
+ stringBuilder.append(", Population: ");
+ stringBuilder.append(population);
+ }
+ return stringBuilder.toString();
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Rain.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Rain.java
new file mode 100644
index 0000000..055c6a4
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Rain.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2022 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.model.forecast.climatic;
+
+import java.util.Objects;
+
+/**
+ * Represents rain information.
+ */
+public class Rain {
+ private static final String DEFAULT_UNIT = "mm";
+
+ private double level;
+
+ protected Rain(double level) {
+ this.level = level;
+ }
+
+ /**
+ * Creates {@link Rain} object with correctness check.
+ * @param level rain level value
+ * @return rain object.
+ */
+ public static Rain withValue(double level) {
+ if (level < 0) {
+ throw new IllegalArgumentException("Rain level value cannot be negative.");
+ }
+ return new Rain(level);
+ }
+
+ /**
+ * Returns rain level value.
+ * @return rain level value
+ */
+ public double getLevel() {
+ return level;
+ }
+
+ /**
+ * Sets rain level value with correctness check.
+ * @param level rain level value
+ */
+ public void setLevel(double level) {
+ if (level < 0) {
+ throw new IllegalArgumentException("Rain level value cannot be negative.");
+ }
+ this.level = level;
+ }
+
+ /**
+ * Returns rain level unit of measure. Currently, is constant.
+ * @return rain level unit of measure
+ */
+ public String getUnit() {
+ return DEFAULT_UNIT;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Rain rain = (Rain) o;
+ return Double.compare(rain.level, level) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(level);
+ }
+
+ @Override
+ public String toString() {
+ return "Rain precipitation volume, mm: " +
+ level + ' ' +
+ getUnit();
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Snow.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Snow.java
new file mode 100644
index 0000000..1e8e01d
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Snow.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2022 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.model.forecast.climatic;
+
+import java.util.Objects;
+
+/**
+ * Represents snow information.
+ */
+public class Snow {
+ private static final String DEFAULT_UNIT = "mm";
+
+ private double level;
+
+ protected Snow(double level) {
+ this.level = level;
+ }
+
+ /**
+ * Creates {@link Snow} object with correctness check.
+ * @param threeHourLevel snow level value
+ * @return snow object.
+ */
+ public static Snow withValue(double threeHourLevel) {
+ if (threeHourLevel < 0) {
+ throw new IllegalArgumentException("Snow level value cannot be negative.");
+ }
+ return new Snow(threeHourLevel);
+ }
+
+ /**
+ * Returns snow level value.
+ * @return snow level value
+ */
+ public double getLevel() {
+ return level;
+ }
+
+ /**
+ * Sets snow level value with correctness check.
+ * @param level snow level value
+ */
+ public void setLevel(double level) {
+ if (level < 0) {
+ throw new IllegalArgumentException("Snow level value cannot be negative.");
+ }
+ this.level = level;
+ }
+
+ /**
+ * Returns snow level unit of measure. Currently, is constant.
+ * @return snow level unit of measure
+ */
+ public String getUnit() {
+ return DEFAULT_UNIT;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Snow snow = (Snow) o;
+ return Double.compare(snow.level, level) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(level);
+ }
+
+ @Override
+ public String toString() {
+ return "Snow volume, mm: " +
+ level + ' ' +
+ getUnit();
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Temperature.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Temperature.java
new file mode 100644
index 0000000..18e003d
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Temperature.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2021 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.model.forecast.climatic;
+
+import java.util.Objects;
+
+/**
+ * The type Daily temperature.
+ */
+public class Temperature {
+ private Double morning;
+ private Double morningFeelsLike;
+ private Double day;
+ private Double dayFeelsLike;
+ private Double eve;
+ private Double eveFeelsLike;
+ private Double night;
+ private Double nightFeelsLike;
+ private Double min;
+ private Double max;
+ private String unit;
+
+ /**
+ * Gets morning temperature.
+ *
+ * @return the morning
+ */
+ public Double getMorning() {
+ return morning;
+ }
+
+ /**
+ * Sets morning temperature.
+ *
+ * @param morning the morning
+ */
+ public void setMorning(Double morning) {
+ this.morning = morning;
+ }
+
+ /**
+ * Gets morning feels like temperature.
+ *
+ * @return the morning feels like temperature
+ */
+ public Double getMorningFeelsLike() {
+ return morningFeelsLike;
+ }
+
+ /**
+ * Sets morning feels like temperature.
+ *
+ * @param morningFeelsLike the morning feels like temperature
+ */
+ public void setMorningFeelsLike(Double morningFeelsLike) {
+ this.morningFeelsLike = morningFeelsLike;
+ }
+
+ /**
+ * Gets day temperature.
+ *
+ * @return the day temperature
+ */
+ public Double getDay() {
+ return day;
+ }
+
+ /**
+ * Sets day temperature.
+ *
+ * @param day the day temperature
+ */
+ public void setDay(Double day) {
+ this.day = day;
+ }
+
+ /**
+ * Gets day feels like temperature.
+ *
+ * @return the day feels like temperature
+ */
+ public Double getDayFeelsLike() {
+ return dayFeelsLike;
+ }
+
+ /**
+ * Sets day feels like temperature.
+ *
+ * @param dayFeelsLike the day feels like temperature
+ */
+ public void setDayFeelsLike(Double dayFeelsLike) {
+ this.dayFeelsLike = dayFeelsLike;
+ }
+
+ /**
+ * Gets eve temperature.
+ *
+ * @return the eve temperature
+ */
+ public Double getEve() {
+ return eve;
+ }
+
+ /**
+ * Sets eve temperature.
+ *
+ * @param eve the eve temperature
+ */
+ public void setEve(Double eve) {
+ this.eve = eve;
+ }
+
+ /**
+ * Gets eve feels like temperature.
+ *
+ * @return the eve feels like temperature
+ */
+ public Double getEveFeelsLike() {
+ return eveFeelsLike;
+ }
+
+ /**
+ * Sets eve feels like temperature.
+ *
+ * @param eveFeelsLike the eve feels like temperature
+ */
+ public void setEveFeelsLike(Double eveFeelsLike) {
+ this.eveFeelsLike = eveFeelsLike;
+ }
+
+ /**
+ * Gets night temperature.
+ *
+ * @return the night temperature
+ */
+ public Double getNight() {
+ return night;
+ }
+
+ /**
+ * Sets night temperature.
+ *
+ * @param night the night temperature
+ */
+ public void setNight(Double night) {
+ this.night = night;
+ }
+
+ /**
+ * Gets night feels like temperature.
+ *
+ * @return the night feels like temperature
+ */
+ public Double getNightFeelsLike() {
+ return nightFeelsLike;
+ }
+
+ /**
+ * Sets night feels like temperature.
+ *
+ * @param nightFeelsLike the night feels like temperature
+ */
+ public void setNightFeelsLike(Double nightFeelsLike) {
+ this.nightFeelsLike = nightFeelsLike;
+ }
+
+ /**
+ * Gets min temperature.
+ *
+ * @return the min temperature
+ */
+ public Double getMin() {
+ return min;
+ }
+
+ /**
+ * Sets min temperature.
+ *
+ * @param min the min temperature
+ */
+ public void setMin(Double min) {
+ this.min = min;
+ }
+
+ /**
+ * Gets max temperature.
+ *
+ * @return the max temperature
+ */
+ public Double getMax() {
+ return max;
+ }
+
+ /**
+ * Sets max temperature.
+ *
+ * @param max the max temperature
+ */
+ public void setMax(Double max) {
+ this.max = max;
+ }
+
+ /**
+ * Gets unit temperature.
+ *
+ * @return the unit temperature
+ */
+ public String getUnit() {
+ return unit;
+ }
+
+ /**
+ * Sets unit temperature.
+ *
+ * @param unit the unit temperature
+ */
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Temperature that = (Temperature) o;
+ return Objects.equals(morning, that.morning) &&
+ Objects.equals(morningFeelsLike, that.morningFeelsLike) &&
+ Objects.equals(day, that.day) &&
+ Objects.equals(dayFeelsLike, that.dayFeelsLike) &&
+ Objects.equals(eve, that.eve) &&
+ Objects.equals(eveFeelsLike, that.eveFeelsLike) &&
+ Objects.equals(night, that.night) &&
+ Objects.equals(nightFeelsLike, that.nightFeelsLike) &&
+ Objects.equals(min, that.min) &&
+ Objects.equals(max, that.max) &&
+ Objects.equals(unit, that.unit);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(morning, morningFeelsLike, day, dayFeelsLike, eve, eveFeelsLike, night, nightFeelsLike, min, max, unit);
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/WeatherForecast.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/WeatherForecast.java
new file mode 100644
index 0000000..6427b21
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/WeatherForecast.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2022 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.model.forecast.climatic;
+
+
+import com.github.prominence.openweathermap.api.model.Clouds;
+import com.github.prominence.openweathermap.api.model.Humidity;
+import com.github.prominence.openweathermap.api.model.WeatherState;
+import com.github.prominence.openweathermap.api.model.Wind;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents weather forecast information for a particular timestamp.
+ */
+public class WeatherForecast {
+ private LocalDateTime forecastTime;
+ private LocalDateTime sunriseTime;
+ private LocalDateTime sunsetTime;
+
+ private List weatherStates;
+ private Temperature temperature;
+ private AtmosphericPressure atmosphericPressure;
+ private Humidity humidity;
+
+ private Wind wind;
+ private Rain rain;
+ private Snow snow;
+ private Clouds clouds;
+
+ /**
+ * Gets forecast time.
+ *
+ * @return the forecast time
+ */
+ public LocalDateTime getForecastTime() {
+ return forecastTime;
+ }
+
+ /**
+ * Sets forecast time.
+ *
+ * @param forecastTime the forecast time
+ */
+ public void setForecastTime(LocalDateTime forecastTime) {
+ this.forecastTime = forecastTime;
+ }
+
+ public LocalDateTime getSunriseTime() {
+ return sunriseTime;
+ }
+
+ public void setSunriseTime(LocalDateTime sunriseTime) {
+ this.sunriseTime = sunriseTime;
+ }
+
+ public LocalDateTime getSunsetTime() {
+ return sunsetTime;
+ }
+
+ public void setSunsetTime(LocalDateTime sunsetTime) {
+ this.sunsetTime = sunsetTime;
+ }
+
+ /**
+ * Gets weather state.
+ *
+ * @return the weather state
+ */
+ public List getWeatherStates() {
+ return weatherStates;
+ }
+
+ /**
+ * Sets weather state.
+ *
+ * @param weatherStates the weather state
+ */
+ public void setWeatherStates(List weatherStates) {
+ this.weatherStates = weatherStates;
+ }
+
+ /**
+ * Gets temperature.
+ *
+ * @return the temperature
+ */
+ public Temperature getTemperature() {
+ return temperature;
+ }
+
+ /**
+ * Sets temperature.
+ *
+ * @param temperature the temperature
+ */
+ public void setTemperature(Temperature temperature) {
+ this.temperature = temperature;
+ }
+
+ /**
+ * Gets atmospheric pressure.
+ *
+ * @return the atmospheric pressure
+ */
+ public AtmosphericPressure getAtmosphericPressure() {
+ return atmosphericPressure;
+ }
+
+ /**
+ * Sets atmospheric pressure.
+ *
+ * @param atmosphericPressure the atmospheric pressure
+ */
+ public void setAtmosphericPressure(AtmosphericPressure atmosphericPressure) {
+ this.atmosphericPressure = atmosphericPressure;
+ }
+
+ /**
+ * Gets humidity.
+ *
+ * @return the humidity
+ */
+ public Humidity getHumidity() {
+ return humidity;
+ }
+
+ /**
+ * Sets humidity.
+ *
+ * @param humidity the humidity
+ */
+ public void setHumidity(Humidity humidity) {
+ this.humidity = humidity;
+ }
+
+ /**
+ * Gets wind.
+ *
+ * @return the wind
+ */
+ public Wind getWind() {
+ return wind;
+ }
+
+ /**
+ * Sets wind.
+ *
+ * @param wind the wind
+ */
+ public void setWind(Wind wind) {
+ this.wind = wind;
+ }
+
+ /**
+ * Gets rain.
+ *
+ * @return the rain
+ */
+ public Rain getRain() {
+ return rain;
+ }
+
+ /**
+ * Sets rain.
+ *
+ * @param rain the rain
+ */
+ public void setRain(Rain rain) {
+ this.rain = rain;
+ }
+
+ /**
+ * Gets snow.
+ *
+ * @return the snow
+ */
+ public Snow getSnow() {
+ return snow;
+ }
+
+ /**
+ * Sets snow.
+ *
+ * @param snow the snow
+ */
+ public void setSnow(Snow snow) {
+ this.snow = snow;
+ }
+
+ /**
+ * Gets clouds.
+ *
+ * @return the clouds
+ */
+ public Clouds getClouds() {
+ return clouds;
+ }
+
+ /**
+ * Sets clouds.
+ *
+ * @param clouds the clouds
+ */
+ public void setClouds(Clouds clouds) {
+ this.clouds = clouds;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ WeatherForecast that = (WeatherForecast) o;
+ return Objects.equals(forecastTime, that.forecastTime) &&
+ Objects.equals(sunriseTime, that.sunriseTime) &&
+ Objects.equals(sunsetTime, that.sunsetTime) &&
+ Objects.equals(weatherStates, that.weatherStates) &&
+ Objects.equals(temperature, that.temperature) &&
+ Objects.equals(atmosphericPressure, that.atmosphericPressure) &&
+ Objects.equals(humidity, that.humidity) &&
+ Objects.equals(wind, that.wind) &&
+ Objects.equals(rain, that.rain) &&
+ Objects.equals(snow, that.snow) &&
+ Objects.equals(clouds, that.clouds);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(forecastTime, sunriseTime, sunsetTime, weatherStates, temperature, atmosphericPressure, humidity, wind, rain, snow, clouds);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Timestamp: ");
+ stringBuilder.append(forecastTime);
+ if (weatherStates != null && weatherStates.size() > 0) {
+ stringBuilder.append(", Weather: ");
+ stringBuilder.append(weatherStates.get(0).getDescription());
+ }
+ if (temperature != null) {
+ stringBuilder.append(", Min temperature: ");
+ stringBuilder.append(temperature.getMin());
+ stringBuilder.append(temperature.getUnit());
+ stringBuilder.append(", Max temperature: ");
+ stringBuilder.append(temperature.getMax());
+ stringBuilder.append(temperature.getUnit());
+ }
+ if (atmosphericPressure != null) {
+ stringBuilder.append(", ");
+ stringBuilder.append(atmosphericPressure.getSeaLevelValue());
+ stringBuilder.append(' ');
+ stringBuilder.append(atmosphericPressure.getUnit());
+ }
+ if (clouds != null) {
+ stringBuilder.append(", ");
+ stringBuilder.append(clouds);
+ }
+ if (rain != null) {
+ stringBuilder.append(", Rain: ");
+ stringBuilder.append(rain.getLevel());
+ stringBuilder.append(' ');
+ stringBuilder.append(rain.getUnit());
+ }
+ if (snow != null) {
+ stringBuilder.append(", Snow: ");
+ stringBuilder.append(snow.getLevel());
+ stringBuilder.append(' ');
+ stringBuilder.append(snow.getUnit());
+ }
+ return stringBuilder.toString();
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Wind.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Wind.java
new file mode 100644
index 0000000..4140c7f
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/climatic/Wind.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2022 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.model.forecast.climatic;
+
+import java.util.Objects;
+
+/**
+ * The type Wind.
+ */
+public class Wind {
+ private double speed;
+ private Double degrees;
+ private String unit;
+
+ /**
+ * Instantiates a new Wind.
+ *
+ * @param speed the speed
+ * @param unit the unitSystem
+ */
+ private Wind(double speed, String unit) {
+ this.speed = speed;
+ this.unit = unit;
+ }
+
+ /**
+ * Creates {@link Wind} object with correctness check.
+ *
+ * @param speed the speed
+ * @param unit the unitSystem
+ * @return wind object
+ */
+ public static Wind withValue(double speed, String unit) {
+ if (speed < 0) {
+ throw new IllegalArgumentException("Wind speed value must be in positive or zero.");
+ }
+ if (unit == null) {
+ throw new IllegalArgumentException("Unit must be set.");
+ }
+ return new Wind(speed, unit);
+ }
+
+ /**
+ * Gets speed.
+ *
+ * @return the speed
+ */
+ public double getSpeed() {
+ return speed;
+ }
+
+ /**
+ * Sets speed.
+ *
+ * @param speed the speed
+ */
+ public void setSpeed(double speed) {
+ if (speed < 0) {
+ throw new IllegalArgumentException("Wind speed value must be in positive or zero.");
+ }
+ this.speed = speed;
+ }
+
+ /**
+ * Gets degrees.
+ *
+ * @return the degrees
+ */
+ public Double getDegrees() {
+ return degrees;
+ }
+
+ /**
+ * Sets degrees.
+ *
+ * @param degrees the degrees
+ */
+ public void setDegrees(double degrees) {
+ if (degrees < 0 || degrees > 360) {
+ throw new IllegalArgumentException("Wind direction value must be in [0, 360] range.");
+ }
+ this.degrees = degrees;
+ }
+
+ /**
+ * Gets unitSystem.
+ *
+ * @return the unitSystem
+ */
+ public String getUnit() {
+ return unit;
+ }
+
+ /**
+ * Sets unitSystem.
+ *
+ * @param unit the unitSystem
+ */
+ public void setUnit(String unit) {
+ if (unit == null) {
+ throw new IllegalArgumentException("Unit must be set.");
+ }
+ this.unit = unit;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Wind)) return false;
+ Wind wind = (Wind) o;
+ return Double.compare(wind.speed, speed) == 0 &&
+ Objects.equals(degrees, wind.degrees) &&
+ Objects.equals(unit, wind.unit);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(speed, degrees, unit);
+ }
+
+ @Override
+ public String toString() {
+ return "Wind speed: " + speed + " " + unit +
+ ", degrees: " + degrees;
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/AtmosphericPressure.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/AtmosphericPressure.java
index 7404966..f4e8b4d 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/AtmosphericPressure.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/AtmosphericPressure.java
@@ -33,7 +33,7 @@ public class AtmosphericPressure {
private double seaLevelValue;
- private AtmosphericPressure() {
+ protected AtmosphericPressure() {
}
/**
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Forecast.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Forecast.java
index 6f2bbff..9841732 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Forecast.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Forecast.java
@@ -31,7 +31,7 @@ import java.util.Objects;
*/
public class Forecast {
private Location location;
- private List weatherForecasts;
+ private List extends WeatherForecast> weatherForecasts;
/**
* Returns location information.
@@ -53,7 +53,7 @@ public class Forecast {
* Returns list of weather forecasts for different timestamps.
* @return list of forecast-per-timestamp information.
*/
- public List getWeatherForecasts() {
+ public List extends WeatherForecast> getWeatherForecasts() {
return weatherForecasts;
}
@@ -61,7 +61,7 @@ public class Forecast {
* Sets list of weather forecasts for different timestamps.
* @param weatherForecasts list of forecast information
*/
- public void setWeatherForecasts(List weatherForecasts) {
+ public void setWeatherForecasts(List extends WeatherForecast> weatherForecasts) {
this.weatherForecasts = weatherForecasts;
}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Location.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Location.java
index d876f45..4cb0beb 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Location.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Location.java
@@ -41,7 +41,7 @@ public class Location {
private Long population;
- private Location(int id, String name) {
+ protected Location(int id, String name) {
this.id = id;
this.name = name;
}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Rain.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Rain.java
index 10806fd..3358630 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Rain.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Rain.java
@@ -32,33 +32,33 @@ public class Rain {
private double level;
- private Rain(double level) {
+ protected Rain(double level) {
this.level = level;
}
/**
* Creates {@link Rain} object with correctness check.
- * @param threeHourLevel 3-hour rain level value
+ * @param level rain level value
* @return rain object.
*/
- public static Rain withThreeHourLevelValue(double threeHourLevel) {
- if (threeHourLevel < 0) {
+ public static Rain withValue(double level) {
+ if (level < 0) {
throw new IllegalArgumentException("Rain level value cannot be negative.");
}
- return new Rain(threeHourLevel);
+ return new Rain(level);
}
/**
- * Returns 3-hour rain level value.
- * @return 3-hour rain level value
+ * Returns rain level value.
+ * @return rain level value
*/
public double getLevel() {
return level;
}
/**
- * Sets 3-hour rain level value with correctness check.
- * @param level 3-hour rain level value
+ * Sets rain level value with correctness check.
+ * @param level rain level value
*/
public void setLevel(double level) {
if (level < 0) {
@@ -68,7 +68,7 @@ public class Rain {
}
/**
- * Returns rain level unit of measure. Currently is constant.
+ * Returns rain level unit of measure. Currently, is constant.
* @return rain level unit of measure
*/
public String getUnit() {
@@ -90,7 +90,7 @@ public class Rain {
@Override
public String toString() {
- return "3-hour rain level: " +
+ return "Rain precipitation volume, mm: " +
level + ' ' +
getUnit();
}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Snow.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Snow.java
index 258163f..bfa6a37 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Snow.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/Snow.java
@@ -32,16 +32,16 @@ public class Snow {
private double level;
- private Snow(double level) {
+ protected Snow(double level) {
this.level = level;
}
/**
* Creates {@link Snow} object with correctness check.
- * @param threeHourLevel 3-hour snow level value
+ * @param threeHourLevel snow level value
* @return snow object.
*/
- public static Snow withThreeHourLevelValue(double threeHourLevel) {
+ public static Snow withValue(double threeHourLevel) {
if (threeHourLevel < 0) {
throw new IllegalArgumentException("Snow level value cannot be negative.");
}
@@ -49,16 +49,16 @@ public class Snow {
}
/**
- * Returns 3-hour snow level value.
- * @return 3-hour snow level value
+ * Returns snow level value.
+ * @return snow level value
*/
public double getLevel() {
return level;
}
/**
- * Sets 3-hour snow level value with correctness check.
- * @param level 3-hour snow level value
+ * Sets snow level value with correctness check.
+ * @param level snow level value
*/
public void setLevel(double level) {
if (level < 0) {
@@ -68,7 +68,7 @@ public class Snow {
}
/**
- * Returns snow level unit of measure. Currently is constant.
+ * Returns snow level unit of measure. Currently, is constant.
* @return snow level unit of measure
*/
public String getUnit() {
@@ -90,7 +90,7 @@ public class Snow {
@Override
public String toString() {
- return "3-hour snow level: " +
+ return "Snow volume, mm: " +
level + ' ' +
getUnit();
}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/WeatherForecast.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/WeatherForecast.java
index 6d9d3b9..a1e0648 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/WeatherForecast.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/daily/WeatherForecast.java
@@ -29,6 +29,7 @@ import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.Wind;
import java.time.LocalDateTime;
+import java.util.List;
import java.util.Objects;
/**
@@ -36,12 +37,10 @@ import java.util.Objects;
*/
public class WeatherForecast {
private LocalDateTime forecastTime;
-
private LocalDateTime sunriseTime;
-
private LocalDateTime sunsetTime;
- private WeatherState weatherState;
+ private List weatherStates;
private Temperature temperature;
private AtmosphericPressure atmosphericPressure;
private Humidity humidity;
@@ -51,6 +50,8 @@ public class WeatherForecast {
private Snow snow;
private Clouds clouds;
+ private Double probabilityOfPrecipitation;
+
/**
* Gets forecast time.
*
@@ -69,22 +70,38 @@ public class WeatherForecast {
this.forecastTime = forecastTime;
}
+ public LocalDateTime getSunriseTime() {
+ return sunriseTime;
+ }
+
+ public void setSunriseTime(LocalDateTime sunriseTime) {
+ this.sunriseTime = sunriseTime;
+ }
+
+ public LocalDateTime getSunsetTime() {
+ return sunsetTime;
+ }
+
+ public void setSunsetTime(LocalDateTime sunsetTime) {
+ this.sunsetTime = sunsetTime;
+ }
+
/**
* Gets weather state.
*
* @return the weather state
*/
- public WeatherState getWeatherState() {
- return weatherState;
+ public List getWeatherStates() {
+ return weatherStates;
}
/**
* Sets weather state.
*
- * @param weatherState the weather state
+ * @param weatherStates the weather state
*/
- public void setWeatherState(WeatherState weatherState) {
- this.weatherState = weatherState;
+ public void setWeatherStates(List weatherStates) {
+ this.weatherStates = weatherStates;
}
/**
@@ -213,25 +230,36 @@ public class WeatherForecast {
this.clouds = clouds;
}
+ public Double getProbabilityOfPrecipitation() {
+ return probabilityOfPrecipitation;
+ }
+
+ public void setProbabilityOfPrecipitation(Double probabilityOfPrecipitation) {
+ this.probabilityOfPrecipitation = probabilityOfPrecipitation;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WeatherForecast that = (WeatherForecast) o;
return Objects.equals(forecastTime, that.forecastTime) &&
- Objects.equals(weatherState, that.weatherState) &&
+ Objects.equals(sunriseTime, that.sunriseTime) &&
+ Objects.equals(sunsetTime, that.sunsetTime) &&
+ Objects.equals(weatherStates, that.weatherStates) &&
Objects.equals(temperature, that.temperature) &&
Objects.equals(atmosphericPressure, that.atmosphericPressure) &&
Objects.equals(humidity, that.humidity) &&
Objects.equals(wind, that.wind) &&
Objects.equals(rain, that.rain) &&
Objects.equals(snow, that.snow) &&
- Objects.equals(clouds, that.clouds);
+ Objects.equals(clouds, that.clouds) &&
+ Objects.equals(probabilityOfPrecipitation, that.probabilityOfPrecipitation);
}
@Override
public int hashCode() {
- return Objects.hash(forecastTime, weatherState, temperature, atmosphericPressure, humidity, wind, rain, snow, clouds);
+ return Objects.hash(forecastTime, sunriseTime, sunsetTime, weatherStates, temperature, atmosphericPressure, humidity, wind, rain, snow, clouds, probabilityOfPrecipitation);
}
@Override
@@ -239,9 +267,9 @@ public class WeatherForecast {
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Timestamp: ");
stringBuilder.append(forecastTime);
- if (weatherState != null) {
+ if (weatherStates != null && weatherStates.size() > 0) {
stringBuilder.append(", Weather: ");
- stringBuilder.append(weatherState.getDescription());
+ stringBuilder.append(weatherStates.get(0).getDescription());
}
if (temperature != null) {
stringBuilder.append(", Min temperature: ");
@@ -259,7 +287,7 @@ public class WeatherForecast {
}
if (clouds != null) {
stringBuilder.append(", ");
- stringBuilder.append(clouds.toString());
+ stringBuilder.append(clouds);
}
if (rain != null) {
stringBuilder.append(", Rain: ");
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/free/WeatherForecast.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/free/WeatherForecast.java
index 0b682bf..0b64cde 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/free/WeatherForecast.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/free/WeatherForecast.java
@@ -23,7 +23,6 @@
package com.github.prominence.openweathermap.api.model.forecast.free;
import com.github.prominence.openweathermap.api.model.*;
-import com.github.prominence.openweathermap.api.model.Wind;
import java.time.LocalDateTime;
import java.util.Objects;
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/hourly/WeatherForecast.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/hourly/WeatherForecast.java
index eaa1d63..95d2ea6 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/hourly/WeatherForecast.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/hourly/WeatherForecast.java
@@ -23,7 +23,6 @@
package com.github.prominence.openweathermap.api.model.forecast.hourly;
import com.github.prominence.openweathermap.api.model.*;
-import com.github.prominence.openweathermap.api.model.Wind;
import java.time.LocalDateTime;
import java.util.List;
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Daily.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Daily.java
index b3232bc..e0de6fc 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Daily.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Daily.java
@@ -25,8 +25,8 @@ package com.github.prominence.openweathermap.api.model.onecall.current;
import com.github.prominence.openweathermap.api.model.Clouds;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
-import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
import com.github.prominence.openweathermap.api.model.Wind;
+import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
import java.time.LocalDateTime;
import java.util.List;
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Hourly.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Hourly.java
index a587071..e9d617b 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Hourly.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Hourly.java
@@ -26,7 +26,10 @@ import com.github.prominence.openweathermap.api.model.Clouds;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.Wind;
-import com.github.prominence.openweathermap.api.model.onecall.*;
+import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
+import com.github.prominence.openweathermap.api.model.onecall.Rain;
+import com.github.prominence.openweathermap.api.model.onecall.Snow;
+import com.github.prominence.openweathermap.api.model.onecall.Temperature;
import java.time.LocalDateTime;
import java.util.List;
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeather.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeather.java
index 69e64a5..caab8a4 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeather.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeather.java
@@ -22,7 +22,7 @@
package com.github.prominence.openweathermap.api.model.onecall.historical;
-import com.github.prominence.openweathermap.api.model.onecall.*;
+import com.github.prominence.openweathermap.api.model.onecall.Current;
/**
* The type Historical weather.
diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistorical.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistorical.java
index e59e8d1..d62c7f8 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistorical.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistorical.java
@@ -26,7 +26,10 @@ import com.github.prominence.openweathermap.api.model.Clouds;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.Wind;
-import com.github.prominence.openweathermap.api.model.onecall.*;
+import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
+import com.github.prominence.openweathermap.api.model.onecall.Rain;
+import com.github.prominence.openweathermap.api.model.onecall.Snow;
+import com.github.prominence.openweathermap.api.model.onecall.Temperature;
import java.time.LocalDateTime;
import java.util.List;
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastAsyncRequestTerminator.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastAsyncRequestTerminator.java
new file mode 100644
index 0000000..12f4f2c
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastAsyncRequestTerminator.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.request.forecast.climatic;
+
+import com.github.prominence.openweathermap.api.enums.ResponseType;
+import com.github.prominence.openweathermap.api.mapper.ClimaticForecastResponseMapper;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.Forecast;
+import com.github.prominence.openweathermap.api.request.RequestSettings;
+import com.github.prominence.openweathermap.api.utils.RequestUtils;
+
+import java.util.concurrent.CompletableFuture;
+
+class ClimaticForecastAsyncRequestTerminator {
+ private final RequestSettings requestSettings;
+
+ ClimaticForecastAsyncRequestTerminator(RequestSettings requestSettings) {
+ this.requestSettings = requestSettings;
+ }
+
+ public CompletableFuture asJava() {
+ return CompletableFuture.supplyAsync(() -> new ClimaticForecastResponseMapper(requestSettings.getUnitSystem()).mapToForecast(getRawResponse()));
+ }
+
+ public CompletableFuture asJSON() {
+ return CompletableFuture.supplyAsync(this::getRawResponse);
+ }
+
+ public CompletableFuture asXML() {
+ requestSettings.setResponseType(ResponseType.XML);
+ return CompletableFuture.supplyAsync(this::getRawResponse);
+ }
+
+ private String getRawResponse() {
+ return RequestUtils.getResponse(requestSettings);
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequestCustomizer.java
new file mode 100644
index 0000000..34e16ac
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequestCustomizer.java
@@ -0,0 +1,45 @@
+package com.github.prominence.openweathermap.api.request.forecast.climatic;
+
+import com.github.prominence.openweathermap.api.enums.Language;
+import com.github.prominence.openweathermap.api.enums.UnitSystem;
+import com.github.prominence.openweathermap.api.request.RequestSettings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClimaticForecastRequestCustomizer {
+ private static final Logger logger = LoggerFactory.getLogger(ClimaticForecastRequestCustomizer.class);
+
+ private final RequestSettings requestSettings;
+
+ public ClimaticForecastRequestCustomizer(RequestSettings requestSettings) {
+ this.requestSettings = requestSettings;
+ }
+
+ public ClimaticForecastRequestCustomizer language(Language language) {
+ requestSettings.setLanguage(language);
+ return this;
+ }
+
+ public ClimaticForecastRequestCustomizer unitSystem(UnitSystem unitSystem) {
+ requestSettings.setUnitSystem(unitSystem);
+ return this;
+ }
+
+ public ClimaticForecastRequestCustomizer numberOfDays(int numberOfDays) {
+ int days = numberOfDays;
+ if (days > 30) {
+ logger.warn("Cannot use more than 30 days for this API request. Please, specify 30 or less days. !!! Requesting information for 30 days...");
+ days = 30;
+ }
+ requestSettings.putRequestParameter("cnt", Integer.toString(days));
+ return this;
+ }
+
+ public ClimaticForecastRequestTerminator retrieve() {
+ return new ClimaticForecastRequestTerminator(requestSettings);
+ }
+
+ public ClimaticForecastAsyncRequestTerminator retrieveAsync() {
+ return new ClimaticForecastAsyncRequestTerminator(requestSettings);
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequestTerminator.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequestTerminator.java
new file mode 100644
index 0000000..bfd8197
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequestTerminator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021 Alexey Zinchenko
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.prominence.openweathermap.api.request.forecast.climatic;
+
+import com.github.prominence.openweathermap.api.enums.ResponseType;
+import com.github.prominence.openweathermap.api.mapper.ClimaticForecastResponseMapper;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.Forecast;
+import com.github.prominence.openweathermap.api.request.RequestSettings;
+import com.github.prominence.openweathermap.api.utils.RequestUtils;
+
+class ClimaticForecastRequestTerminator {
+ private final RequestSettings requestSettings;
+
+ ClimaticForecastRequestTerminator(RequestSettings requestSettings) {
+ this.requestSettings = requestSettings;
+ }
+
+ public Forecast asJava() {
+ return new ClimaticForecastResponseMapper(requestSettings.getUnitSystem()).mapToForecast(getRawResponse());
+ }
+
+ public String asJSON() {
+ return getRawResponse();
+ }
+
+ public String asXML() {
+ requestSettings.setResponseType(ResponseType.XML);
+ return getRawResponse();
+ }
+
+ private String getRawResponse() {
+ return RequestUtils.getResponse(requestSettings);
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequester.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequester.java
new file mode 100644
index 0000000..a937c13
--- /dev/null
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/climatic/ClimaticForecastRequester.java
@@ -0,0 +1,20 @@
+package com.github.prominence.openweathermap.api.request.forecast.climatic;
+
+import com.github.prominence.openweathermap.api.model.Coordinates;
+import com.github.prominence.openweathermap.api.request.RequestSettings;
+
+public class ClimaticForecastRequester {
+ private final RequestSettings requestSettings;
+
+ public ClimaticForecastRequester(RequestSettings requestSettings) {
+ this.requestSettings = requestSettings;
+ this.requestSettings.setSubdomain("pro");
+ this.requestSettings.appendToURL("data/2.5/forecast/climate");
+ }
+
+ public ClimaticForecastRequestCustomizer byCoordinates(Coordinates coordinates) {
+ requestSettings.putRequestParameter("lat", String.valueOf(coordinates.getLatitude()));
+ requestSettings.putRequestParameter("lon", String.valueOf(coordinates.getLongitude()));
+ return new ClimaticForecastRequestCustomizer(requestSettings);
+ }
+}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/daily/DailyForecastRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/daily/DailyForecastRequestCustomizer.java
index 03b7e0a..03b307d 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/daily/DailyForecastRequestCustomizer.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/daily/DailyForecastRequestCustomizer.java
@@ -50,7 +50,7 @@ class DailyForecastRequestCustomizer {
public DailyForecastRequestCustomizer numberOfDays(int numberOfDays) {
int days = numberOfDays;
if (days > 16) {
- logger.warn("Cannot use more than 16 days for this api request. Please, specify 16 or less days. !!! Requesting information for 16 days...");
+ logger.warn("Cannot use more than 16 days for this API request. Please, specify 16 or less days. !!! Requesting information for 16 days...");
days = 16;
}
requestSettings.putRequestParameter("cnt", Integer.toString(days));
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/daily/DailyForecastRequester.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/daily/DailyForecastRequester.java
index 0c6fbba..fe9ab50 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/daily/DailyForecastRequester.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/daily/DailyForecastRequester.java
@@ -30,7 +30,7 @@ public class DailyForecastRequester {
public DailyForecastRequester(RequestSettings requestSettings) {
this.requestSettings = requestSettings;
- this.requestSettings.appendToURL("data/2.5/forecast/hourly");
+ this.requestSettings.appendToURL("data/2.5/forecast/daily");
}
public DailyForecastRequestCustomizer byCoordinates(Coordinates coordinates) {
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/geocoding/direct/DirectGeocodingRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/geocoding/direct/DirectGeocodingRequestCustomizer.java
index 3e44225..5ddb9c6 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/request/geocoding/direct/DirectGeocodingRequestCustomizer.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/geocoding/direct/DirectGeocodingRequestCustomizer.java
@@ -23,8 +23,6 @@
package com.github.prominence.openweathermap.api.request.geocoding.direct;
import com.github.prominence.openweathermap.api.request.RequestSettings;
-import com.github.prominence.openweathermap.api.request.geocoding.reverse.ReverseGeocodingRequestAsyncTerminator;
-import com.github.prominence.openweathermap.api.request.geocoding.reverse.ReverseGeocodingRequestTerminator;
import java.util.function.Function;
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherAsyncRequestTerminator.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherAsyncRequestTerminator.java
index a0f1b77..2c3bfef 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherAsyncRequestTerminator.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherAsyncRequestTerminator.java
@@ -23,9 +23,9 @@
package com.github.prominence.openweathermap.api.request.weather;
import com.github.prominence.openweathermap.api.enums.ResponseType;
-import com.github.prominence.openweathermap.api.request.RequestSettings;
import com.github.prominence.openweathermap.api.mapper.CurrentWeatherResponseMapper;
import com.github.prominence.openweathermap.api.model.weather.Weather;
+import com.github.prominence.openweathermap.api.request.RequestSettings;
import com.github.prominence.openweathermap.api.utils.RequestUtils;
import java.util.concurrent.CompletableFuture;
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherRequestTerminator.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherRequestTerminator.java
index 1601fbc..639779f 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherRequestTerminator.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherRequestTerminator.java
@@ -23,9 +23,9 @@
package com.github.prominence.openweathermap.api.request.weather;
import com.github.prominence.openweathermap.api.enums.ResponseType;
+import com.github.prominence.openweathermap.api.mapper.CurrentWeatherResponseMapper;
import com.github.prominence.openweathermap.api.model.weather.Weather;
import com.github.prominence.openweathermap.api.request.RequestSettings;
-import com.github.prominence.openweathermap.api.mapper.CurrentWeatherResponseMapper;
import com.github.prominence.openweathermap.api.utils.RequestUtils;
/**
diff --git a/src/main/java/com/github/prominence/openweathermap/api/utils/RequestUtils.java b/src/main/java/com/github/prominence/openweathermap/api/utils/RequestUtils.java
index ec7e95d..1ef190d 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/utils/RequestUtils.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/utils/RequestUtils.java
@@ -23,8 +23,8 @@
package com.github.prominence.openweathermap.api.utils;
import com.github.prominence.openweathermap.api.conf.TimeoutSettings;
-import com.github.prominence.openweathermap.api.exception.NoDataFoundException;
import com.github.prominence.openweathermap.api.exception.InvalidAuthTokenException;
+import com.github.prominence.openweathermap.api.exception.NoDataFoundException;
import com.github.prominence.openweathermap.api.request.RequestSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/test/java/com/github/prominence/openweathermap/api/mapper/ClimaticForecastResponseMapperTest.java b/src/test/java/com/github/prominence/openweathermap/api/mapper/ClimaticForecastResponseMapperTest.java
new file mode 100644
index 0000000..3f97f38
--- /dev/null
+++ b/src/test/java/com/github/prominence/openweathermap/api/mapper/ClimaticForecastResponseMapperTest.java
@@ -0,0 +1,126 @@
+package com.github.prominence.openweathermap.api.mapper;
+
+import com.github.prominence.openweathermap.api.enums.UnitSystem;
+import com.github.prominence.openweathermap.api.model.Wind;
+import com.github.prominence.openweathermap.api.model.*;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.AtmosphericPressure;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.Temperature;
+import com.github.prominence.openweathermap.api.model.forecast.climatic.*;
+import com.github.prominence.openweathermap.api.utils.TestMappingUtils;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ClimaticForecastResponseMapperTest {
+
+ @Test
+ public void mapToForecast() {
+ final String jsonResponse = """
+ {
+ "cod": "200",
+ "city": {
+ "id": 2643743,
+ "name": "London",
+ "coord": {
+ "lon": -0.1277,
+ "lat": 51.5073
+ },
+ "country": "GB"
+ },
+ "message": 0.353472054,
+ "list": [
+ {
+ "dt": 1594382400,
+ "sunrise": 1594353335,
+ "sunset": 1594412149,
+ "temp": {
+ "day": 286.98,
+ "min": 285.22,
+ "max": 287.97,
+ "night": 285.22,
+ "eve": 287.97,
+ "morn": 287.29
+ },
+ "feels_like": {
+ "day": 282.61,
+ "night": 283.19,
+ "eve": 284.98,
+ "morn": 282.68
+ },
+ "pressure": 1016,
+ "humidity": 84,
+ "weather": [
+ {
+ "id": 500,
+ "main": "Rain",
+ "description": "light rain",
+ "icon": "10d"
+ }
+ ],
+ "speed": 6.78,
+ "deg": 320,
+ "clouds": 81,
+ "rain": 1.96,
+ "snow": 2.21
+ }
+ ]
+ }
+ """;
+
+ final Forecast forecast = new ClimaticForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonResponse);
+ assertNotNull(forecast);
+
+ final Location location = forecast.getLocation();
+ assertNotNull(location);
+ assertEquals(Coordinates.of(51.5073, -0.1277), location.getCoordinate());
+ assertEquals(2643743, location.getId());
+ assertEquals("London", location.getName());
+ assertEquals("GB", location.getCountryCode());
+ assertNull(location.getPopulation());
+ assertNull(location.getZoneOffset());
+
+ assertEquals(1, forecast.getWeatherForecasts().size());
+ final WeatherForecast weatherForecast = forecast.getWeatherForecasts().get(0);
+ assertEquals(TestMappingUtils.parseDateTime(1594382400), weatherForecast.getForecastTime());
+ assertEquals(TestMappingUtils.parseDateTime(1594353335), weatherForecast.getSunriseTime());
+ assertEquals(TestMappingUtils.parseDateTime(1594412149), weatherForecast.getSunsetTime());
+
+ final Temperature temperature = weatherForecast.getTemperature();
+ assertEquals(286.98, temperature.getDay());
+ assertEquals(285.22, temperature.getMin());
+ assertEquals(287.97, temperature.getMax());
+ assertEquals(285.22, temperature.getNight());
+ assertEquals(287.97, temperature.getEve());
+ assertEquals(287.29, temperature.getMorning());
+ assertEquals(282.61, temperature.getDayFeelsLike());
+ assertEquals(283.19, temperature.getNightFeelsLike());
+ assertEquals(284.98, temperature.getEveFeelsLike());
+ assertEquals(282.68, temperature.getMorningFeelsLike());
+
+ final AtmosphericPressure pressure = weatherForecast.getAtmosphericPressure();
+ assertEquals(1016, pressure.getSeaLevelValue());
+
+ final Humidity humidity = weatherForecast.getHumidity();
+ assertEquals(84, humidity.getValue());
+
+ final Wind wind = weatherForecast.getWind();
+ assertEquals(6.78, wind.getSpeed());
+ assertEquals(320, wind.getDegrees());
+
+ final Clouds clouds = weatherForecast.getClouds();
+ assertEquals(81, clouds.getValue());
+
+ assertEquals(1, weatherForecast.getWeatherStates().size());
+ final WeatherState weatherState = weatherForecast.getWeatherStates().get(0);
+ assertEquals(500, weatherState.getId());
+ assertEquals("Rain", weatherState.getName());
+ assertEquals("light rain", weatherState.getDescription());
+ assertEquals("10d", weatherState.getIconId());
+
+ final Rain rain = weatherForecast.getRain();
+ assertEquals(1.96, rain.getLevel());
+
+ final Snow snow = weatherForecast.getSnow();
+ assertEquals(2.21, snow.getLevel());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/prominence/openweathermap/api/mapper/DailyForecastResponseMapperTest.java b/src/test/java/com/github/prominence/openweathermap/api/mapper/DailyForecastResponseMapperTest.java
new file mode 100644
index 0000000..081ee6d
--- /dev/null
+++ b/src/test/java/com/github/prominence/openweathermap/api/mapper/DailyForecastResponseMapperTest.java
@@ -0,0 +1,137 @@
+package com.github.prominence.openweathermap.api.mapper;
+
+import com.github.prominence.openweathermap.api.enums.UnitSystem;
+import com.github.prominence.openweathermap.api.model.*;
+import com.github.prominence.openweathermap.api.model.forecast.daily.AtmosphericPressure;
+import com.github.prominence.openweathermap.api.model.forecast.daily.Temperature;
+import com.github.prominence.openweathermap.api.model.forecast.daily.*;
+import com.github.prominence.openweathermap.api.utils.TestMappingUtils;
+import org.junit.jupiter.api.Test;
+
+import java.time.ZoneOffset;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class DailyForecastResponseMapperTest {
+
+ @Test
+ public void mapToForecast() {
+ final String jsonResponse = """
+ {
+ "city": {
+ "id": 2643743,
+ "name": "London",
+ "coord": {
+ "lon": -0.1258,
+ "lat": 51.5085
+ },
+ "country": "GB",
+ "population": 0,
+ "timezone": 3600
+ },
+ "cod": "200",
+ "message": 0.7809187,
+ "cnt": 1,
+ "list": [
+ {
+ "dt": 1568977200,
+ "sunrise": 1568958164,
+ "sunset": 1569002733,
+ "temp": {
+ "day": 293.79,
+ "min": 288.85,
+ "max": 294.47,
+ "night": 288.85,
+ "eve": 290.44,
+ "morn": 293.79
+ },
+ "feels_like": {
+ "day": 278.87,
+ "night": 282.73,
+ "eve": 281.92,
+ "morn": 278.87
+ },
+ "pressure": 1025.04,
+ "humidity": 42,
+ "weather": [
+ {
+ "id": 800,
+ "main": "Clear",
+ "description": "sky is clear",
+ "icon": "01d"
+ }
+ ],
+ "speed": 4.66,
+ "deg": 102,
+ "gust": 5.3,
+ "clouds": 0,
+ "pop": 0.24,
+ "rain": 22.2,
+ "snow": 24.2
+ }
+ ]
+ }
+ """;
+
+ final Forecast forecast = new DailyForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonResponse);
+ assertNotNull(forecast);
+
+ final Location location = forecast.getLocation();
+ assertNotNull(location);
+ assertEquals(Coordinates.of(51.5085, -0.1258), location.getCoordinate());
+ assertEquals(2643743, location.getId());
+ assertEquals("London", location.getName());
+ assertEquals("GB", location.getCountryCode());
+ assertEquals(0, location.getPopulation());
+ assertEquals(ZoneOffset.ofTotalSeconds(3600), location.getZoneOffset());
+
+ assertEquals(1, forecast.getWeatherForecasts().size());
+ final WeatherForecast weatherForecast = forecast.getWeatherForecasts().get(0);
+ assertEquals(TestMappingUtils.parseDateTime(1568977200), weatherForecast.getForecastTime());
+ // TODO: Does the API provide the sunrise and sunset info??? It is not officially described in the API but present in the example.
+ assertEquals(TestMappingUtils.parseDateTime(1568958164), weatherForecast.getSunriseTime());
+ assertEquals(TestMappingUtils.parseDateTime(1569002733), weatherForecast.getSunsetTime());
+
+ final Temperature temperature = weatherForecast.getTemperature();
+ assertEquals(293.79, temperature.getDay());
+ assertEquals(288.85, temperature.getMin());
+ assertEquals(294.47, temperature.getMax());
+ assertEquals(288.85, temperature.getNight());
+ assertEquals(290.44, temperature.getEve());
+ assertEquals(293.79, temperature.getMorning());
+ assertEquals(278.87, temperature.getDayFeelsLike());
+ assertEquals(282.73, temperature.getNightFeelsLike());
+ assertEquals(281.92, temperature.getEveFeelsLike());
+ assertEquals(278.87, temperature.getMorningFeelsLike());
+
+ final AtmosphericPressure pressure = weatherForecast.getAtmosphericPressure();
+ assertEquals(1025.04, pressure.getSeaLevelValue());
+
+ final Humidity humidity = weatherForecast.getHumidity();
+ assertEquals(42, humidity.getValue());
+
+ final Wind wind = weatherForecast.getWind();
+ assertEquals(4.66, wind.getSpeed());
+ assertEquals(102, wind.getDegrees());
+ assertEquals(5.3, wind.getGust());
+
+ final Clouds clouds = weatherForecast.getClouds();
+ assertEquals(0, clouds.getValue());
+
+ assertEquals(1, weatherForecast.getWeatherStates().size());
+ final WeatherState weatherState = weatherForecast.getWeatherStates().get(0);
+ assertEquals(800, weatherState.getId());
+ assertEquals("Clear", weatherState.getName());
+ assertEquals("sky is clear", weatherState.getDescription());
+ assertEquals("01d", weatherState.getIconId());
+
+ final Rain rain = weatherForecast.getRain();
+ assertEquals(22.2, rain.getLevel());
+
+ final Snow snow = weatherForecast.getSnow();
+ assertEquals(24.2, snow.getLevel());
+
+ assertEquals(0.24, weatherForecast.getProbabilityOfPrecipitation());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/github/prominence/openweathermap/api/mapper/GeocodingResponseMapperTest.java b/src/test/java/com/github/prominence/openweathermap/api/mapper/GeocodingResponseMapperTest.java
index cf4d1b0..04a82c3 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/mapper/GeocodingResponseMapperTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/mapper/GeocodingResponseMapperTest.java
@@ -29,7 +29,8 @@ import org.junit.jupiter.api.Test;
import java.util.List;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
class GeocodingResponseMapperTest {
diff --git a/src/test/java/com/github/prominence/openweathermap/api/mapper/HourlyForecastResponseMapperTest.java b/src/test/java/com/github/prominence/openweathermap/api/mapper/HourlyForecastResponseMapperTest.java
index 4aeba61..63f34f9 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/mapper/HourlyForecastResponseMapperTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/mapper/HourlyForecastResponseMapperTest.java
@@ -32,7 +32,8 @@ import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.TimeZone;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
class HourlyForecastResponseMapperTest {
diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/air/pollution/AirPollutionDetailsUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/air/pollution/AirPollutionDetailsUnitTest.java
index d6ac6fe..d98661e 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/model/air/pollution/AirPollutionDetailsUnitTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/model/air/pollution/AirPollutionDetailsUnitTest.java
@@ -30,7 +30,8 @@ import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class AirPollutionDetailsUnitTest {
@Test
diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/WindUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/WindUnitTest.java
index d357510..59c9588 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/WindUnitTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/WindUnitTest.java
@@ -22,8 +22,8 @@
package com.github.prominence.openweathermap.api.model.onecall;
-import org.junit.jupiter.api.Test;
import com.github.prominence.openweathermap.api.model.Wind;
+import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperatureUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperatureUnitTest.java
index 93dfb91..f083393 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperatureUnitTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperatureUnitTest.java
@@ -24,7 +24,8 @@ package com.github.prominence.openweathermap.api.model.onecall.current;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class DailyTemperatureUnitTest {
diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyUnitTest.java
index 8a1f676..732f7ec 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyUnitTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyUnitTest.java
@@ -25,8 +25,8 @@ package com.github.prominence.openweathermap.api.model.onecall.current;
import com.github.prominence.openweathermap.api.model.Clouds;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
-import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
import com.github.prominence.openweathermap.api.model.Wind;
+import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/HourlyUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/HourlyUnitTest.java
index 938ef9c..cb8d1cd 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/HourlyUnitTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/HourlyUnitTest.java
@@ -26,7 +26,10 @@ import com.github.prominence.openweathermap.api.model.Clouds;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.Wind;
-import com.github.prominence.openweathermap.api.model.onecall.*;
+import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
+import com.github.prominence.openweathermap.api.model.onecall.Rain;
+import com.github.prominence.openweathermap.api.model.onecall.Snow;
+import com.github.prominence.openweathermap.api.model.onecall.Temperature;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherUnitTest.java
index afbb747..2be1df4 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherUnitTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherUnitTest.java
@@ -26,7 +26,10 @@ import com.github.prominence.openweathermap.api.model.Clouds;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.Wind;
-import com.github.prominence.openweathermap.api.model.onecall.*;
+import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
+import com.github.prominence.openweathermap.api.model.onecall.Rain;
+import com.github.prominence.openweathermap.api.model.onecall.Snow;
+import com.github.prominence.openweathermap.api.model.onecall.Temperature;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistoricalUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistoricalUnitTest.java
index bf8832b..57617fb 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistoricalUnitTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistoricalUnitTest.java
@@ -26,7 +26,10 @@ import com.github.prominence.openweathermap.api.model.Clouds;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.Wind;
-import com.github.prominence.openweathermap.api.model.onecall.*;
+import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
+import com.github.prominence.openweathermap.api.model.onecall.Rain;
+import com.github.prominence.openweathermap.api.model.onecall.Snow;
+import com.github.prominence.openweathermap.api.model.onecall.Temperature;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/weather/WeatherUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/weather/WeatherUnitTest.java
index e2df79f..0c9f9e1 100644
--- a/src/test/java/com/github/prominence/openweathermap/api/model/weather/WeatherUnitTest.java
+++ b/src/test/java/com/github/prominence/openweathermap/api/model/weather/WeatherUnitTest.java
@@ -27,7 +27,6 @@ import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
import java.util.Collections;
-import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
diff --git a/src/test/java/com/github/prominence/openweathermap/api/utils/TestMappingUtils.java b/src/test/java/com/github/prominence/openweathermap/api/utils/TestMappingUtils.java
new file mode 100644
index 0000000..478dbef
--- /dev/null
+++ b/src/test/java/com/github/prominence/openweathermap/api/utils/TestMappingUtils.java
@@ -0,0 +1,12 @@
+package com.github.prominence.openweathermap.api.utils;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.util.TimeZone;
+
+public class TestMappingUtils {
+
+ public static LocalDateTime parseDateTime(int seconds) {
+ return LocalDateTime.ofInstant(Instant.ofEpochSecond(seconds), TimeZone.getDefault().toZoneId());
+ }
+}