diff --git a/pom.xml b/pom.xml
index 579637e..88e5314 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.github.prominence
openweathermap-api
- 2.3.0
+ 2.4.0
jar
Java OpenWeatherMap API
@@ -80,7 +80,7 @@
org.sonatype.plugins
nexus-staging-maven-plugin
- 1.6.9
+ 1.6.13
true
ossrh
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 c29d1eb..a450b7d 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java
@@ -31,6 +31,7 @@ import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherRe
import com.github.prominence.openweathermap.api.request.weather.CurrentWeatherRequester;
import static com.github.prominence.openweathermap.api.enums.SubscriptionPlan.ALL;
+import static com.github.prominence.openweathermap.api.enums.SubscriptionPlan.SPECIAL;
/**
* The main public API client to communicate with OpenWeatherMap services.
@@ -80,10 +81,29 @@ public class OpenWeatherMapClient {
* @return requester for retrieving one call weather information.
*/
@SubscriptionAvailability(plans = ALL)
+ @Deprecated
public OneCallWeatherRequester oneCall() {
return new OneCallWeatherRequester(new RequestSettings(apiKey, timeoutSettings));
}
+ /**
+ * One Call 3 API API.
+ * Includes a weather summary statement in addition to the information provided by {@link #oneCall()}
+ *
+ * Please note, that One Call API 3.0 is included in the "One Call by Call" subscription only.
+ * This separate subscription includes 1,000 calls/day for free and allows you to pay only for the number of API calls made to this product.
+ * Please note, that you do not need to subscribe to any other OpenWeather subscription plans to get access to the One Call API 3.0.
+ * Please find more details on the pricing page and FAQ or ask Ulla, OpenWeather AI assistant.
+ *
+ * @return requester for retrieving one call weather information for the OneCall 3 API.
+ */
+ @SubscriptionAvailability(plans = SPECIAL)
+ public OneCallWeatherRequester oneCall3() {
+ RequestSettings requestSettings = new RequestSettings(apiKey, timeoutSettings);
+ requestSettings.setUseApi3();
+ return new OneCallWeatherRequester(requestSettings);
+ }
+
/**
* Air Pollution API.
* Air Pollution API provides current, forecast and historical air pollution data for any coordinates on the globe.
diff --git a/src/main/java/com/github/prominence/openweathermap/api/enums/SubscriptionPlan.java b/src/main/java/com/github/prominence/openweathermap/api/enums/SubscriptionPlan.java
index b2419c7..d4ffbde 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/enums/SubscriptionPlan.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/enums/SubscriptionPlan.java
@@ -56,4 +56,9 @@ public enum SubscriptionPlan {
* All existing subscription plans.
*/
ALL,
+
+ /**
+ * Special subscription cases.
+ */
+ SPECIAL,
}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/mapper/OneCallWeatherResponseMapper.java b/src/main/java/com/github/prominence/openweathermap/api/mapper/OneCallWeatherResponseMapper.java
index d3477b4..e3ad567 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/mapper/OneCallWeatherResponseMapper.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/mapper/OneCallWeatherResponseMapper.java
@@ -213,6 +213,7 @@ public class OneCallWeatherResponseMapper {
daily.setMoonPhase(new MoonPhase(moonPhaseNode.asDouble()));
}
+ daily.setSummary(parseSummary(dailyNode));
daily.setWeatherState(parseWeatherState(dailyNode.get("weather").get(0)));
daily.setTemperature(parseDailyTemperature(dailyNode));
daily.setAtmosphericPressure(parsePressure(dailyNode));
@@ -439,4 +440,12 @@ public class OneCallWeatherResponseMapper {
return null;
}
+
+ private String parseSummary(JsonNode dailyNode) {
+ final JsonNode summaryNode = dailyNode.get("summary");
+ if(summaryNode != null) {
+ return summaryNode.asText();
+ }
+ return null;
+ }
}
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 e2f8b45..baeb87d 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
@@ -43,6 +43,7 @@ public class Daily {
private LocalDateTime moonsetTime;
private MoonPhase moonPhase;
+ private String summary;
private WeatherState weatherState;
private DailyTemperature temperature;
private AtmosphericPressure atmosphericPressure;
@@ -162,6 +163,24 @@ public class Daily {
this.moonPhase = moonPhase;
}
+ /**
+ * Gets summary.
+ *
+ * @return the summary
+ */
+ public String getSummary() {
+ return summary;
+ }
+
+ /**
+ * Sets summary.
+ *
+ * @param summary the summary
+ */
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+
/**
* Gets weather state.
*
@@ -435,4 +454,5 @@ public class Daily {
}
return stringBuilder.toString();
}
+
}
diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/RequestSettings.java b/src/main/java/com/github/prominence/openweathermap/api/request/RequestSettings.java
index db0b103..5e3a0a7 100644
--- a/src/main/java/com/github/prominence/openweathermap/api/request/RequestSettings.java
+++ b/src/main/java/com/github/prominence/openweathermap/api/request/RequestSettings.java
@@ -45,6 +45,7 @@ public class RequestSettings {
private Language language = Language.ENGLISH;
private UnitSystem unitSystem = UnitSystem.STANDARD;
+ private boolean useApi3 = false;
public RequestSettings(String apiKey, TimeoutSettings timeoutSettings) {
this.putRequestParameter(API_KEY_PARAM_NAME, apiKey);
@@ -94,6 +95,14 @@ public class RequestSettings {
urlAppenderBuilder.append(appendix);
}
+ public void setUseApi3() {
+ this.useApi3 = true;
+ }
+
+ public boolean getUseApi3() {
+ return this.useApi3;
+ }
+
public StringBuilder getUrlAppender() {
return urlAppenderBuilder;
}
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 c20ec6d..3d410f8 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
@@ -29,13 +29,11 @@ import com.github.prominence.openweathermap.api.request.RequestSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
+import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
@@ -44,7 +42,8 @@ import java.util.stream.Collectors;
*/
public final class RequestUtils {
- private static final String OWM_URL_BASE = "http://api.openweathermap.org/data/2.5/";
+ private static final String OWM_URL_BASE = "https://api.openweathermap.org/data/2.5/";
+ private static final String OWM_URL_BASE_3_0 = "https://api.openweathermap.org/data/3.0/";
private static final Logger logger = LoggerFactory.getLogger(RequestUtils.class);
@@ -53,10 +52,19 @@ public final class RequestUtils {
public static String getResponse(RequestSettings requestSettings) {
StringBuilder requestUrlBuilder = new StringBuilder(OWM_URL_BASE);
+ if(requestSettings.getUseApi3()) {
+ requestUrlBuilder = new StringBuilder(OWM_URL_BASE_3_0);
+ }
requestUrlBuilder.append(requestSettings.getUrlAppender());
requestUrlBuilder.append('?');
String parameters = requestSettings.getRequestParameters().entrySet().stream()
- .map(entry -> entry.getKey() + "=" + entry.getValue())
+ .map(entry -> {
+ try {
+ return entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ })
.collect(Collectors.joining("&"));
requestUrlBuilder.append(parameters);
diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/onecall/current/CurrentWeatherOneCallApi3IntegrationTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/onecall/current/CurrentWeatherOneCallApi3IntegrationTest.java
new file mode 100644
index 0000000..bc4ff50
--- /dev/null
+++ b/src/test/java/com/github/prominence/openweathermap/api/request/onecall/current/CurrentWeatherOneCallApi3IntegrationTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.onecall.current;
+
+import com.github.prominence.openweathermap.api.ApiTest;
+import com.github.prominence.openweathermap.api.OpenWeatherMapClient;
+import com.github.prominence.openweathermap.api.enums.Language;
+import com.github.prominence.openweathermap.api.enums.OneCallResultOptions;
+import com.github.prominence.openweathermap.api.enums.UnitSystem;
+import com.github.prominence.openweathermap.api.exception.InvalidAuthTokenException;
+import com.github.prominence.openweathermap.api.exception.NoDataFoundException;
+import com.github.prominence.openweathermap.api.model.Coordinate;
+import com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class CurrentWeatherOneCallApi3IntegrationTest extends ApiTest {
+ @Test
+ public void whenRetrieveCurrentOneCallResponseAsJava_thenOk() {
+ final CurrentWeatherData currentWeatherData = getClient()
+ .oneCall3()
+ .current()
+ .byCoordinate(Coordinate.of(53.54, 27.34))
+ .language(Language.ENGLISH)
+ .unitSystem(UnitSystem.METRIC)
+ .retrieve()
+ .asJava();
+
+ assertNotNull(currentWeatherData);
+ assertNotNull(currentWeatherData.getDailyList().get(0).getSummary());
+ }
+
+ @Test
+ public void whenRetrieveCurrentOneCallResponseAsJSON_thenOk() {
+ final String responseJson = getClient()
+ .oneCall3()
+ .current()
+ .byCoordinate(Coordinate.of(53.54, 27.34))
+ .language(Language.ENGLISH)
+ .unitSystem(UnitSystem.METRIC)
+ .retrieve()
+ .asJSON();
+
+ assertNotNull(responseJson);
+ assertNotEquals("", responseJson);
+ }
+
+ @Test
+ public void whenRetrieveCurrentOneCallResponseWithExclusionAsJava_thenOk() {
+ final CurrentWeatherData currentWeatherData = getClient()
+ .oneCall3()
+ .current()
+ .byCoordinate(Coordinate.of(53.54, 27.34))
+ .language(Language.ENGLISH)
+ .unitSystem(UnitSystem.METRIC)
+ .exclude(OneCallResultOptions.CURRENT, OneCallResultOptions.MINUTELY)
+ .retrieve()
+ .asJava();
+
+ assertNotNull(currentWeatherData);
+ assertNull(currentWeatherData.getCurrent());
+ assertNull(currentWeatherData.getMinutelyList());
+ assertNotNull(currentWeatherData.getDailyList().get(0).getSummary());
+ }
+
+ @Test
+ public void whenRetrieveCurrentOneCallAsyncResponseAsJava_thenOk() throws ExecutionException, InterruptedException {
+ final CompletableFuture currentWeatherDataFuture = getClient()
+ .oneCall3()
+ .current()
+ .byCoordinate(Coordinate.of(53.54, 27.34))
+ .language(Language.ENGLISH)
+ .unitSystem(UnitSystem.METRIC)
+ .retrieveAsync()
+ .asJava();
+
+ assertNotNull(currentWeatherDataFuture);
+ assertNotNull(currentWeatherDataFuture.get());
+ assertNotNull(currentWeatherDataFuture.get().getDailyList().get(0).getSummary());
+ }
+
+ @Test
+ public void whenRetrieveCurrentOneCallAsyncResponseAsJSON_thenOk() throws ExecutionException, InterruptedException {
+ final CompletableFuture responseJsonFuture = getClient()
+ .oneCall3()
+ .current()
+ .byCoordinate(Coordinate.of(53.54, 27.34))
+ .language(Language.ENGLISH)
+ .unitSystem(UnitSystem.METRIC)
+ .retrieveAsync()
+ .asJSON();
+
+ assertNotNull(responseJsonFuture);
+ final String responseJson = responseJsonFuture.get();
+ assertNotNull(responseJson);
+ }
+
+ @Test
+ public void whenRequestOnecallWithInvalidApiKey_thenThrowAnException() {
+ OpenWeatherMapClient client = new OpenWeatherMapClient("invalidKey");
+ assertThrows(InvalidAuthTokenException.class, () ->
+ client
+ .oneCall3()
+ .current()
+ .byCoordinate(Coordinate.of(53.54, 27.34))
+ .language(Language.ENGLISH)
+ .unitSystem(UnitSystem.METRIC)
+ .retrieve()
+ .asJSON()
+ );
+ }
+}