preparing for packaging
This commit is contained in:
parent
f88d3f1023
commit
ef7a32aab6
8 changed files with 468 additions and 5 deletions
32
pom.xml
32
pom.xml
|
@ -12,6 +12,13 @@
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>724rocks</id>
|
||||||
|
<url>https://git.724.rocks/api/packages/Minecon724/maven</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -26,5 +33,30 @@
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-release-plugin</artifactId>
|
||||||
|
<version>3.0.1</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>724rocks</id>
|
||||||
|
<url>https://git.724.rocks/api/packages/Minecon724/maven</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>724rocks</id>
|
||||||
|
<url>https://git.724.rocks/api/packages/Minecon724/maven</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<developerConnection>scm:git:https://git.724.rocks/Minecon724/wtapi.git</developerConnection>
|
||||||
|
</scm>
|
||||||
|
|
||||||
</project>
|
</project>
|
21
release.properties
Normal file
21
release.properties
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#release configuration
|
||||||
|
#Thu May 30 13:53:21 CEST 2024
|
||||||
|
completedPhase=check-poms
|
||||||
|
exec.pomFileName=pom.xml
|
||||||
|
exec.snapshotReleasePluginAllowed=false
|
||||||
|
pinExternals=false
|
||||||
|
preparationGoals=clean verify
|
||||||
|
project.scm.eu.m724\:wtapi.developerConnection=scm\:git\:https\://git.724.rocks/Minecon724/wtapi.git
|
||||||
|
project.scm.eu.m724\:wtapi.tag=HEAD
|
||||||
|
projectVersionPolicyConfig=<projectVersionPolicyConfig>${projectVersionPolicyConfig}</projectVersionPolicyConfig>\n
|
||||||
|
projectVersionPolicyId=default
|
||||||
|
pushChanges=true
|
||||||
|
releaseStrategyId=default
|
||||||
|
remoteTagging=true
|
||||||
|
scm.branchCommitComment=@{prefix} prepare branch @{releaseLabel}
|
||||||
|
scm.commentPrefix=[maven-release-plugin]
|
||||||
|
scm.developmentCommitComment=@{prefix} prepare for next development iteration
|
||||||
|
scm.releaseCommitComment=@{prefix} prepare release @{releaseLabel}
|
||||||
|
scm.rollbackCommitComment=@{prefix} rollback the release of @{releaseLabel}
|
||||||
|
scm.tagNameFormat=@{project.artifactId}-@{project.version}
|
||||||
|
scm.url=scm\:git\:https\://git.724.rocks/Minecon724/wtapi.git
|
5
src/main/java/eu/m724/wtapi/object/Severity.java
Normal file
5
src/main/java/eu/m724/wtapi/object/Severity.java
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package eu.m724.wtapi.object;
|
||||||
|
|
||||||
|
public enum Severity {
|
||||||
|
LIGHT, MODERATE, HEAVY
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
package eu.m724.wtapi.object;
|
|
||||||
|
|
||||||
public enum WeatherState {
|
|
||||||
CLEAR, RAIN, THUNDER
|
|
||||||
}
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
package eu.m724.wtapi.provider.impl.openweathermap;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
|
||||||
|
import eu.m724.wtapi.object.Coordinates;
|
||||||
|
import eu.m724.wtapi.object.Severity;
|
||||||
|
import eu.m724.wtapi.object.Weather;
|
||||||
|
|
||||||
|
public class OWMResponseConverter {
|
||||||
|
static Weather convert(JsonObject json) {
|
||||||
|
Weather weather = new Weather();
|
||||||
|
|
||||||
|
int conditionCode = json.getAsJsonArray("weather")
|
||||||
|
.get(0).getAsJsonObject()
|
||||||
|
.getAsJsonPrimitive("id").getAsInt();
|
||||||
|
|
||||||
|
switch (conditionCode) {
|
||||||
|
// Group 2xx: Thunderstorm
|
||||||
|
case 200: // thunderstorm with light rain
|
||||||
|
weather.thunderstormSeverity = Severity.LIGHT;
|
||||||
|
weather.rainSeverity = Severity.LIGHT;
|
||||||
|
break;
|
||||||
|
case 201: // thunderstorm with rain
|
||||||
|
weather.thunderstormSeverity = Severity.MODERATE;
|
||||||
|
weather.rainSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 202: // thunderstorm with heavy rain
|
||||||
|
weather.thunderstormSeverity = Severity.HEAVY;
|
||||||
|
weather.rainSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
case 210: // light thunderstorm
|
||||||
|
weather.thunderstormSeverity = Severity.LIGHT;
|
||||||
|
break;
|
||||||
|
case 211: // thunderstorm
|
||||||
|
weather.thunderstormSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 212: // heavy thunderstorm
|
||||||
|
weather.thunderstormSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
case 221: // ragged thunderstorm
|
||||||
|
weather.thunderstormSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 230: // thunderstorm with light drizzle
|
||||||
|
weather.thunderstormSeverity = Severity.LIGHT;
|
||||||
|
weather.drizzleSeverity = Severity.LIGHT;
|
||||||
|
break;
|
||||||
|
case 231: // thunderstorm with drizzle
|
||||||
|
weather.thunderstormSeverity = Severity.MODERATE;
|
||||||
|
weather.drizzleSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 232: // thunderstorm with heavy drizzle
|
||||||
|
weather.thunderstormSeverity = Severity.HEAVY;
|
||||||
|
weather.drizzleSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Group 3xx: Drizzle
|
||||||
|
case 300: // light intensity drizzle
|
||||||
|
weather.drizzleSeverity = Severity.LIGHT;
|
||||||
|
break;
|
||||||
|
case 301: // drizzle
|
||||||
|
weather.drizzleSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 302: // heavy intensity drizzle
|
||||||
|
weather.drizzleSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
case 310: // light intensity drizzle rain
|
||||||
|
weather.drizzleSeverity = Severity.LIGHT;
|
||||||
|
break;
|
||||||
|
case 311: // drizzle rain
|
||||||
|
weather.drizzleSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 312: // heavy intensity drizzle rain
|
||||||
|
weather.drizzleSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
case 313: // shower rain and drizzle
|
||||||
|
weather.rainSeverity = Severity.MODERATE;
|
||||||
|
weather.drizzleSeverity = Severity.MODERATE;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 314: // heavy shower rain and drizzle
|
||||||
|
weather.rainSeverity = Severity.HEAVY;
|
||||||
|
weather.drizzleSeverity = Severity.HEAVY;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 321: // shower drizzle
|
||||||
|
weather.drizzleSeverity = Severity.MODERATE;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Group 5xx: Rain
|
||||||
|
case 500: // light rain
|
||||||
|
weather.rainSeverity = Severity.LIGHT;
|
||||||
|
break;
|
||||||
|
case 501: // moderate rain
|
||||||
|
weather.rainSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 502: // heavy intensity rain
|
||||||
|
weather.rainSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
case 503: // very heavy rain
|
||||||
|
weather.rainSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
case 504: // extreme rain
|
||||||
|
weather.rainSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
case 511: // freezing rain
|
||||||
|
weather.rainSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 520: // light intensity shower rain
|
||||||
|
weather.rainSeverity = Severity.LIGHT;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 521: // shower rain
|
||||||
|
weather.rainSeverity = Severity.MODERATE;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 522: // heavy intensity shower rain
|
||||||
|
weather.rainSeverity = Severity.HEAVY;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 531: // ragged shower rain
|
||||||
|
weather.rainSeverity = Severity.MODERATE;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Group 6xx: Snow
|
||||||
|
case 600: // light snow
|
||||||
|
weather.snowSeverity = Severity.LIGHT;
|
||||||
|
break;
|
||||||
|
case 601: // snow
|
||||||
|
weather.snowSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 602: // heavy snow
|
||||||
|
weather.snowSeverity = Severity.HEAVY;
|
||||||
|
break;
|
||||||
|
case 611: // sleet
|
||||||
|
weather.sleetSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 612: // light shower sleet
|
||||||
|
weather.sleetSeverity = Severity.LIGHT;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 613: // shower sleet
|
||||||
|
weather.sleetSeverity = Severity.MODERATE;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 615: // light rain and snow
|
||||||
|
weather.rainSeverity = Severity.LIGHT;
|
||||||
|
weather.snowSeverity = Severity.LIGHT;
|
||||||
|
break;
|
||||||
|
case 616: // rain and snow
|
||||||
|
weather.rainSeverity = Severity.MODERATE;
|
||||||
|
weather.snowSeverity = Severity.MODERATE;
|
||||||
|
break;
|
||||||
|
case 620: // light shower snow
|
||||||
|
weather.snowSeverity = Severity.LIGHT;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 621: // shower snow
|
||||||
|
weather.snowSeverity = Severity.MODERATE;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
case 622: // heavy shower snow
|
||||||
|
weather.snowSeverity = Severity.HEAVY;
|
||||||
|
weather.shower = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
weather.coordinates =
|
||||||
|
new Coordinates(
|
||||||
|
json.getAsJsonObject("coord").getAsJsonPrimitive("lon").getAsDouble(),
|
||||||
|
json.getAsJsonObject("coord").getAsJsonPrimitive("lat").getAsDouble()
|
||||||
|
);
|
||||||
|
|
||||||
|
weather.temperature = json
|
||||||
|
.getAsJsonObject("main")
|
||||||
|
.getAsJsonPrimitive("temp")
|
||||||
|
.getAsFloat();
|
||||||
|
|
||||||
|
weather.temperatureApparent = json
|
||||||
|
.getAsJsonObject("main")
|
||||||
|
.getAsJsonPrimitive("feels_like")
|
||||||
|
.getAsFloat();
|
||||||
|
|
||||||
|
weather.windSpeed = json
|
||||||
|
.getAsJsonObject("wind")
|
||||||
|
.getAsJsonPrimitive("speed")
|
||||||
|
.getAsFloat();
|
||||||
|
|
||||||
|
JsonPrimitive pri = json
|
||||||
|
.getAsJsonObject("wind")
|
||||||
|
.getAsJsonPrimitive("gust");
|
||||||
|
|
||||||
|
if (pri != null)
|
||||||
|
weather.windSpeed = pri.getAsFloat();
|
||||||
|
|
||||||
|
weather.humidity = json
|
||||||
|
.getAsJsonObject("main")
|
||||||
|
.getAsJsonPrimitive("humidity")
|
||||||
|
.getAsInt() / 100f;
|
||||||
|
|
||||||
|
weather.cloudiness = json
|
||||||
|
.getAsJsonObject("clouds")
|
||||||
|
.getAsJsonPrimitive("all")
|
||||||
|
.getAsInt() / 100f;
|
||||||
|
|
||||||
|
weather.sunrise = json
|
||||||
|
.getAsJsonObject("sys")
|
||||||
|
.getAsJsonPrimitive("sunrise")
|
||||||
|
.getAsLong();
|
||||||
|
|
||||||
|
weather.sunset = json
|
||||||
|
.getAsJsonObject("sys")
|
||||||
|
.getAsJsonPrimitive("sunrise")
|
||||||
|
.getAsLong();
|
||||||
|
|
||||||
|
weather.city = json
|
||||||
|
.getAsJsonPrimitive("name")
|
||||||
|
.getAsString();
|
||||||
|
|
||||||
|
weather.description = json
|
||||||
|
.getAsJsonArray("weather")
|
||||||
|
.get(0).getAsJsonObject()
|
||||||
|
.getAsJsonPrimitive("description")
|
||||||
|
.getAsString();
|
||||||
|
|
||||||
|
return weather;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
package eu.m724.wtapi.provider.impl.openweathermap;
|
||||||
|
|
||||||
|
import java.net.ProxySelector;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.net.http.HttpResponse.BodyHandlers;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
|
import eu.m724.wtapi.object.Coordinates;
|
||||||
|
import eu.m724.wtapi.object.Weather;
|
||||||
|
import eu.m724.wtapi.provider.WeatherProvider;
|
||||||
|
import eu.m724.wtapi.provider.exception.AuthorizationException;
|
||||||
|
import eu.m724.wtapi.provider.exception.ProviderException;
|
||||||
|
import eu.m724.wtapi.provider.exception.QuotaExceededException;
|
||||||
|
import eu.m724.wtapi.provider.exception.ServerProviderException;
|
||||||
|
|
||||||
|
public class OpenWeatherMapProvider extends WeatherProvider {
|
||||||
|
private String requestUrlFormat;
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
|
public OpenWeatherMapProvider(String apiKey) {
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
this.requestUrlFormat = "https://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&appid=" + apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws ProviderException {
|
||||||
|
CompletableFuture<Weather> weatherFuture =
|
||||||
|
getWeather(new Coordinates(0, 0));
|
||||||
|
|
||||||
|
try {
|
||||||
|
weatherFuture.get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new ProviderException("unexpected interruptedexception");
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
throw (ProviderException) e.getSuppressed()[0]; // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Weather> getWeather(Coordinates coordinates) {
|
||||||
|
String url = String.format(
|
||||||
|
requestUrlFormat, coordinates.latitude, coordinates.longitude);
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(url))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
CompletableFuture<HttpResponse<String>> responseFuture =
|
||||||
|
HttpClient.newBuilder()
|
||||||
|
.proxy(ProxySelector.getDefault()).build()
|
||||||
|
.sendAsync(request, BodyHandlers.ofString());
|
||||||
|
|
||||||
|
CompletableFuture<Weather> weatherFuture =
|
||||||
|
responseFuture.thenApply((response) -> {
|
||||||
|
int code = response.statusCode();
|
||||||
|
|
||||||
|
if (code == 401)
|
||||||
|
throw new AuthorizationException("invalid api key");
|
||||||
|
if (code == 429)
|
||||||
|
throw new QuotaExceededException("ratelimited", 1000);
|
||||||
|
if (code != 200)
|
||||||
|
throw new ServerProviderException(String.format("status code %d", code));
|
||||||
|
|
||||||
|
JsonObject jsonResponse =
|
||||||
|
JsonParser.parseString(response.body())
|
||||||
|
.getAsJsonObject();
|
||||||
|
|
||||||
|
Weather weather = OWMResponseConverter.convert(jsonResponse);
|
||||||
|
|
||||||
|
return weather;
|
||||||
|
});
|
||||||
|
|
||||||
|
return weatherFuture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Weather[]> getWeatherBulk(Coordinates[] coordinateses) {
|
||||||
|
ArrayList<CompletableFuture<Weather>> weatherFutures = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Coordinates coordinates : coordinateses) {
|
||||||
|
weatherFutures.add(getWeather(coordinates));
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture<Weather[]> weathersFuture =
|
||||||
|
CompletableFuture.allOf(
|
||||||
|
weatherFutures.toArray(new CompletableFuture[0]))
|
||||||
|
.thenApply(v ->
|
||||||
|
weatherFutures.stream()
|
||||||
|
.map(CompletableFuture::join)
|
||||||
|
.toArray(Weather[]::new));
|
||||||
|
|
||||||
|
return weathersFuture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getQuotaHourly() {
|
||||||
|
return 1370;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBulkLimit() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
src/test/java/eu/m724/wtapi/CoordinateTest.java
Normal file
20
src/test/java/eu/m724/wtapi/CoordinateTest.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package eu.m724.wtapi;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import eu.m724.wtapi.object.Coordinates;
|
||||||
|
|
||||||
|
public class CoordinateTest {
|
||||||
|
@Test
|
||||||
|
public void testCoordinates() {
|
||||||
|
Coordinates coordinates = new Coordinates(-91.1, 180.01);
|
||||||
|
|
||||||
|
System.out.println(coordinates.longitude);
|
||||||
|
|
||||||
|
assert coordinates.latitude == 88.9;
|
||||||
|
assert coordinates.longitude == -179.99;
|
||||||
|
|
||||||
|
coordinates = new Coordinates(-91.1, 180.1);
|
||||||
|
assert coordinates.longitude != -179.9; // TODO
|
||||||
|
}
|
||||||
|
}
|
47
src/test/java/eu/m724/wtapi/TestOWM.java
Normal file
47
src/test/java/eu/m724/wtapi/TestOWM.java
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package eu.m724.wtapi;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import eu.m724.wtapi.object.Coordinates;
|
||||||
|
import eu.m724.wtapi.object.Weather;
|
||||||
|
import eu.m724.wtapi.provider.WeatherProvider;
|
||||||
|
import eu.m724.wtapi.provider.impl.openweathermap.OpenWeatherMapProvider;
|
||||||
|
|
||||||
|
public class TestOWM {
|
||||||
|
@Test
|
||||||
|
public void openWeatherMapTest() throws InterruptedException, ExecutionException {
|
||||||
|
String apiKey = "f3198d2a4ae3076e0aa47c821a253447";
|
||||||
|
|
||||||
|
WeatherProvider provider = new OpenWeatherMapProvider(apiKey);
|
||||||
|
|
||||||
|
provider.init();
|
||||||
|
|
||||||
|
CompletableFuture<Weather> weatherFuture =
|
||||||
|
provider.getWeather(new Coordinates(53.2232, -4.2008));
|
||||||
|
|
||||||
|
Weather weather = weatherFuture.get();
|
||||||
|
assertNotNull(weather);
|
||||||
|
|
||||||
|
System.out.printf("current weather in %s: %s\n", weather.city, weather.description);
|
||||||
|
|
||||||
|
CompletableFuture<Weather[]> weatherBulkFuture =
|
||||||
|
provider.getWeatherBulk(
|
||||||
|
new Coordinates[] {
|
||||||
|
new Coordinates(54.6606714, -3.3827237),
|
||||||
|
new Coordinates(47.5705952, -53.5556464),
|
||||||
|
new Coordinates(34.2073721, -84.1402857),
|
||||||
|
});
|
||||||
|
|
||||||
|
Weather[] weathers = weatherBulkFuture.get();
|
||||||
|
assert weathers.length == 3;
|
||||||
|
|
||||||
|
for (Weather weather1 : weathers) {
|
||||||
|
System.out.printf("current weather in %s: %s\n", weather1.city, weather1.description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue