Compare commits

..

49 Commits

Author SHA1 Message Date
Prominence 2d81dadfad Fixed javadoc layout. 2022-05-02 22:35:52 +03:00
Prominence 5e4b34632e Reimplemented request executor. Added possibility to test requests with mocked http requests. 2022-05-02 20:12:34 +03:00
Prominence 6c1a1642f1 Implemented first part of Road Risk API. 2022-05-02 01:19:19 +03:00
Prominence 8a1daa0fe2 Updated 5 Day / 3 Hour Forecast functionality. 2022-05-01 21:21:24 +03:00
Prominence 7e88fe597c Updated javadocs. 2022-05-01 18:23:17 +03:00
Prominence aa48ac3aa0 Implemented Solar Radiation API functionality. Small refactoring. 2022-05-01 18:19:33 +03:00
Prominence 7f0866ffa2 Implemented climatic forecast for 30 days. Some refactoring. 2022-05-01 01:23:51 +03:00
Prominence 4fdb48986e A bunch of global refactoring and improvements.
Improved coverage reports generation.
Updated docs.
Moved logic out of large mappers into small deserializers.
Implemented Geocoding API functionality.
Implemented Hourly forecast functionality.
Implemented Daily forecast functionality.
Renamed Coordinate class.
Reimplemented Current Weather API: removed multiple locations requests. Marked officially deprecated methods as @Deprecated.
Updated tests.
2022-04-30 01:35:45 +03:00
Prominence 8ca55b15f7 Adjusted to use 17 source and 8 target version. Code refactoring. Docs improvements. 2022-04-19 22:15:19 +03:00
Prominence 5ca31780da Updated badges. 2022-04-19 00:03:42 +03:00
Prominence 91a5acdb43 Adjusted jacoco settings. 2022-04-18 23:42:58 +03:00
Prominence 3f5b7f6649 Updated script. 2022-04-18 23:36:42 +03:00
Prominence 9c2a127703 Renamed key. 2022-04-18 23:33:06 +03:00
Prominence e6833c3007 Added jacoco test coverage report generation. 2022-04-18 23:24:16 +03:00
Prominence d1bac609e8 Test commit for cirrus. 2022-04-18 21:55:11 +03:00
Prominence a17f687976 Test commit for cirrus. 2022-04-18 21:51:59 +03:00
Prominence 1ae02e0e49 Test commit for cirrus. 2022-04-18 21:49:06 +03:00
Prominence 46602e1f93 Test commit for cirrus. 2022-04-18 20:58:22 +03:00
Prominence 2553f13fbe Updated docs. 2022-04-18 11:44:54 +03:00
Prominence 905d3876c3 Merge remote-tracking branch 'origin/master' into dev 2022-04-18 11:43:01 +03:00
Prominence 45f0b494b3 Switched from maven to gradle 7.4.2 build tool. 2022-04-18 11:41:02 +03:00
Prominence 93b6b357c1 Switching to 17 version of java. 2022-04-17 01:13:11 +03:00
dependabot[bot] c0dd184965 Bump jacoco-maven-plugin from 0.8.7 to 0.8.8 (#32)
Bumps [jacoco-maven-plugin](https://github.com/jacoco/jacoco) from 0.8.7 to 0.8.8.
- [Release notes](https://github.com/jacoco/jacoco/releases)
- [Commits](https://github.com/jacoco/jacoco/compare/v0.8.7...v0.8.8)

---
updated-dependencies:
- dependency-name: org.jacoco:jacoco-maven-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-17 01:05:54 +03:00
dependabot[bot] 08d0aa091d Bump maven-jar-plugin from 3.2.0 to 3.2.2 (#33)
Bumps [maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.2.0 to 3.2.2.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.2.0...maven-jar-plugin-3.2.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-17 01:05:36 +03:00
dependabot[bot] 93ae514550 Bump maven-compiler-plugin from 3.8.1 to 3.10.1 (#35)
Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.8.1 to 3.10.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.8.1...maven-compiler-plugin-3.10.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-17 01:05:17 +03:00
dependabot[bot] 2a15788569 Bump maven-javadoc-plugin from 3.3.0 to 3.3.2 (#36)
Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.3.0 to 3.3.2.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.3.0...maven-javadoc-plugin-3.3.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-17 01:04:27 +03:00
Prominence 37d7a2b3f5 Merge remote-tracking branch 'origin/master' into dev 2022-04-17 00:59:49 +03:00
dependabot[bot] 6790848c32 Bump nexus-staging-maven-plugin from 1.6.8 to 1.6.12 (#34)
* Merged changes from dev branch.

* Updated README.md

* Releasing 2.3.0 version.

* Bump nexus-staging-maven-plugin from 1.6.8 to 1.6.12

Bumps nexus-staging-maven-plugin from 1.6.8 to 1.6.12.

---
updated-dependencies:
- dependency-name: org.sonatype.plugins:nexus-staging-maven-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Alexey Zinchenko <Prominence@users.noreply.github.com>
Co-authored-by: Prominence <alexey.zinchenko@protonmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-17 00:49:21 +03:00
Prominence 23a1fa5a7b Preparing for merge. 2022-04-17 00:23:16 +03:00
Prominence 1cac951aaa Preparing for merge. 2022-04-17 00:20:23 +03:00
Prominence 58e648be42 Updated SNAPSHOT version. 2022-04-16 22:32:10 +03:00
Prominence f30bcad5dc Updated SNAPSHOT version. 2022-04-16 22:26:32 +03:00
Prominence 5793722181 Updated docs about timeout settings. 2022-04-15 00:40:51 +03:00
Prominence 40462397c1 Added methods and fields to represent daily moonrise/moonset information. Added tests. Fixed UKRAINIAN language constant name. Updated docs. 2022-04-15 00:37:04 +03:00
Prominence 44b543e65c Another portion of refactoring. Updated dependencies. 2022-04-14 23:30:44 +03:00
Prominence 13b20fc7e9 Moved mappers into separate package. 2022-04-14 20:28:23 +03:00
Prominence 2a531dd683 Started global refactoring. Added timeout parameters for requests. 2022-04-13 00:13:27 +03:00
dependabot-preview[bot] 1e1054903e Bump slf4j-api from 1.7.31 to 1.7.32 (#30)
Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.31 to 1.7.32.
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-07-21 11:00:43 +03:00
dependabot-preview[bot] ff5b6c7a33 Bump jackson-databind from 2.12.3 to 2.12.4 (#29)
Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.12.3 to 2.12.4.
- [Release notes](https://github.com/FasterXML/jackson/releases)
- [Commits](https://github.com/FasterXML/jackson/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-07-07 10:55:04 +03:00
dependabot-preview[bot] db1cf858d8 Bump slf4j-api from 1.7.30 to 1.7.31 (#28)
Bumps [slf4j-api](https://github.com/qos-ch/slf4j) from 1.7.30 to 1.7.31.
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-06-21 09:13:57 +03:00
dependabot-preview[bot] c2cc110dab Bump maven-javadoc-plugin from 3.2.0 to 3.3.0 (#27)
Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.2.0 to 3.3.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.2.0...maven-javadoc-plugin-3.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-05-24 10:58:02 +03:00
dependabot-preview[bot] d4c2472254 Bump junit-jupiter-engine from 5.7.1 to 5.7.2 (#26)
Bumps [junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.7.1...r5.7.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-05-17 11:01:01 +03:00
dependabot-preview[bot] 380e3e458b Bump junit-platform-runner from 1.7.1 to 1.7.2 (#25)
Bumps [junit-platform-runner](https://github.com/junit-team/junit5) from 1.7.1 to 1.7.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-05-17 11:00:48 +03:00
dependabot-preview[bot] 246c07db97 Bump maven-gpg-plugin from 1.6 to 3.0.1 (#24)
Bumps [maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 1.6 to 3.0.1.
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-1.6...maven-gpg-plugin-3.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-05-10 18:40:15 +03:00
dependabot-preview[bot] f19a627313 Bump jacoco-maven-plugin from 0.8.6 to 0.8.7 (#23)
Bumps [jacoco-maven-plugin](https://github.com/jacoco/jacoco) from 0.8.6 to 0.8.7.
- [Release notes](https://github.com/jacoco/jacoco/releases)
- [Commits](https://github.com/jacoco/jacoco/compare/v0.8.6...v0.8.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-05-05 11:03:47 +03:00
dependabot-preview[bot] 6438c323ff Upgrade to GitHub-native Dependabot (#22)
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-04-29 01:49:29 +03:00
dependabot-preview[bot] 1cbff68338 Bump jackson-databind from 2.12.2 to 2.12.3 (#21)
Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.12.2 to 2.12.3.
- [Release notes](https://github.com/FasterXML/jackson/releases)
- [Commits](https://github.com/FasterXML/jackson/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-04-22 11:05:09 +03:00
Prominence 1e08f4f8ae Switched to snapshot version. 2021-04-17 17:23:57 +03:00
Prominence bfa15fd9fe Made rebase onto master branch.
Implemented Air Pollution API functionality.

Preparing for merge.
2021-04-17 17:22:12 +03:00
251 changed files with 12701 additions and 3907 deletions
+13
View File
@@ -0,0 +1,13 @@
container:
image: gradle:jdk17
testCoverage_task:
gradle_cache:
folder: ~/.gradle/caches
testCoverage_script: gradle jacocoTestReport && bash <(curl -s https://codecov.io/bash)
cleanup_before_cache_script:
- rm -rf ~/.gradle/caches/$GRADLE_VERSION/
- rm -rf ~/.gradle/caches/transforms-1
- rm -rf ~/.gradle/caches/journal-1
- rm -rf ~/.gradle/caches/jars-3/*/buildSrc.jar
- find ~/.gradle/caches/ -name "*.lock" -type f -delete
-31
View File
@@ -1,31 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG] Change me"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
-10
View File
@@ -1,10 +0,0 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---
-20
View File
@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE] Change me"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+9
View File
@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: maven
directory: "/"
schedule:
interval: daily
time: "03:00"
open-pull-requests-limit: 10
target-branch: dev
+2 -2
View File
@@ -13,10 +13,10 @@ name: "CodeQL"
on: on:
push: push:
branches: [ master ] branches: [ dev ]
pull_request: pull_request:
# The branches below must be a subset of the branches above # The branches below must be a subset of the branches above
branches: [ master ] branches: [ dev ]
schedule: schedule:
- cron: '27 20 * * 1' - cron: '27 20 * * 1'
+5 -23
View File
@@ -1,24 +1,6 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*.iml *.iml
.idea/ .idea
target/ .gradle
build
target
out
-11
View File
@@ -1,11 +0,0 @@
language: java
jdk:
- openjdk8
- openjdk11
install: mvn install -DskipTests -Dgpg.skip -B
script: mvn test -Dmaven.skip.deploy=true -B
after_success:
- bash <(curl -s https://codecov.io/bash)
-128
View File
@@ -1,128 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
alexey.zinchenko@protonmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+52 -12
View File
@@ -1,4 +1,4 @@
# OpenWeatherMap Java API [![Build Status][ci-shield]][ci-link] [![codecov][codecov-shield]][codecov-link] # OpenWeatherMap Java API [![Build Status][ci-shield]][ci-link] [![codecov][codecov-shield]][codecov-link] [![FOSSA Status][FOSSA-shield]][FOSSA-link]
Java API for OpenWeatherMap services. Java API for OpenWeatherMap services.
### Implemented features: ### Implemented features:
@@ -7,6 +7,14 @@ Free:
* 5 day / 3-hour forecast * 5 day / 3-hour forecast
* One Call API * One Call API
* Air pollution * Air pollution
* Geocoding API
Paid:
* Hourly Forecast 4 days
* Daily Forecast 16 days
* Climatic Forecast 30 days
* Solar Radiation API
* Road Risk API
Other: Other:
* Request timeout settings * Request timeout settings
@@ -14,14 +22,12 @@ Other:
### Will be implemented later: ### Will be implemented later:
Free: Free:
* Geocoding API
* Weather Stations * Weather Stations
* Weather Triggers * Weather Triggers
Paid: Paid:
* Daily Forecast 16 days * Bulk Downloading
* Hourly Forecast 4 days * Global Weather Alerts / Push notifications
* probably others...
### Maven coordinates: ### Maven coordinates:
@@ -29,14 +35,46 @@ Paid:
<dependency> <dependency>
<groupId>com.github.prominence</groupId> <groupId>com.github.prominence</groupId>
<artifactId>openweathermap-api</artifactId> <artifactId>openweathermap-api</artifactId>
<version>2.4.1`</version> <version>3.0.0-SNAPSHOT</version>
</dependency> </dependency>
``` ```
```xml
<repositories>
...
<!-- Repository for snapshot versions -->
<repository>
<id>oss.sonatype.org-snapshot</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
...
</repositories>
```
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
implementation 'com.github.prominence:openweathermap-api:2.4.1' implementation 'com.github.prominence:openweathermap-api:3.0.0-SNAPSHOT'
```
```groovy
repositories {
...
// Repository for snapshot versions
maven {
url "https://oss.sonatype.org/content/repositories/snapshots"
mavenContent {
snapshotsOnly()
}
}
...
}
``` ```
### Documentation ### Documentation
@@ -49,15 +87,17 @@ implementation 'com.github.prominence:openweathermap-api:2.4.1'
* [OpenWeatherMap Java API - 2.1.1](docs/Release_2.1.1.md) * [OpenWeatherMap Java API - 2.1.1](docs/Release_2.1.1.md)
* [OpenWeatherMap Java API - 2.2.0](docs/Release_2.2.0.md) * [OpenWeatherMap Java API - 2.2.0](docs/Release_2.2.0.md)
* [OpenWeatherMap Java API - 2.3.0](docs/Release_2.3.0.md) * [OpenWeatherMap Java API - 2.3.0](docs/Release_2.3.0.md)
* [OpenWeatherMap Java API - 2.4.0](docs/Release_2.4.0.md) * [OpenWeatherMap Java API - SNAPSHOT](docs/SNAPSHOT.md)
* [OpenWeatherMap Java API - 2.4.1](docs/Release_2.4.1.md)
### License ### License
MIT MIT
[ci-shield]: https://travis-ci.org/Prominence/openweathermap-java-api.svg?branch=master [ci-shield]: https://api.cirrus-ci.com/github/Prominence/openweathermap-java-api.svg?branch=dev
[ci-link]: https://travis-ci.org/Prominence/openweathermap-java-api [ci-link]: https://api.cirrus-ci.com/github/Prominence/openweathermap-java-api
[codecov-shield]: https://codecov.io/gh/Prominence/openweathermap-java-api/branch/master/graph/badge.svg [codecov-shield]: https://codecov.io/gh/Prominence/openweathermap-java-api/branch/dev/graph/badge.svg
[codecov-link]: https://codecov.io/gh/Prominence/openweathermap-java-api [codecov-link]: https://codecov.io/gh/Prominence/openweathermap-java-api
[FOSSA-shield]: https://app.fossa.com/api/projects/git%2Bgithub.com%2FProminence%2Fopenweathermap-java-api.svg?type=shield
[FOSSA-link]: https://app.fossa.com/projects/git%2Bgithub.com%2FProminence%2Fopenweathermap-java-api?ref=badge_shield
+122
View File
@@ -0,0 +1,122 @@
plugins {
id 'java-library'
id 'maven-publish'
id 'signing'
id 'jacoco'
}
repositories {
mavenLocal()
maven {
url = uri('https://repo.maven.apache.org/maven2/')
}
}
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2.2'
implementation 'org.slf4j:slf4j-api:1.7.36'
testImplementation 'org.junit.platform:junit-platform-runner:1.8.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2'
}
group = 'com.github.prominence'
version = '3.0.0-SNAPSHOT'
description = 'Java OpenWeatherMap API'
configure([tasks.compileJava]) {
sourceCompatibility = 17 // for the IDE support
options.release = 8
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(17)
}
}
ext {
isReleaseVersion = !version.endsWith("SNAPSHOT")
}
java {
withSourcesJar()
withJavadocJar()
}
test {
useJUnitPlatform()
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom {
name = 'Java OpenWeatherMap API'
description = 'Java API for OpenWeatherMap services.'
url = 'https://github.com/Prominence/openweathermap-java-api'
licenses {
license {
name = 'MIT License'
url = 'https://www.opensource.org/licenses/mit-license.php'
}
}
developers {
developer {
id = 'Prominence'
name = 'Alexey Zinchenko'
email = 'alexey.zinchenko@protonmail.com'
url = 'https://github.com/prominence'
}
}
scm {
connection = 'scm:git:git://github.com/Prominence/openweathermap-java-api.git'
developerConnection = 'scm:git:git@github.com:prominence/openweathermap-java-api.git'
url = 'https://github.com/Prominence/openweathermap-java-api'
}
issueManagement {
url = 'https://github.com/Prominence/openweathermap-java-api/issues'
system = 'GitHub Issues'
}
}
}
}
repositories {
maven {
credentials {
username = project.findProperty('ossrhUsername')
password = project.findProperty('ossrhPassword')
}
url = isReleaseVersion ?
'https://oss.sonatype.org/service/local/staging/deploy/maven2/' :
'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
}
signing {
sign publishing.publications.mavenJava
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
tasks.withType(GenerateModuleMetadata) {
enabled = false
}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
reports {
csv.required = false
xml.required = true
xml.outputLocation = layout.buildDirectory.file('reports/jacoco/report.xml')
html.outputLocation = layout.buildDirectory.dir('jacocoHtml')
}
}
+1 -1
View File
@@ -15,7 +15,7 @@
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:1.0') implementation 'com.github.prominence:openweathermap-api:1.0'
``` ```
### How to use: ### How to use:
+1 -1
View File
@@ -18,7 +18,7 @@
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:1.1') implementation 'com.github.prominence:openweathermap-api:1.1'
``` ```
### How to use: ### How to use:
+1 -1
View File
@@ -18,7 +18,7 @@
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:1.2') implementation 'com.github.prominence:openweathermap-api:1.2'
``` ```
### How to use: ### How to use:
+1 -1
View File
@@ -15,7 +15,7 @@
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:2.0.0') implementation 'com.github.prominence:openweathermap-api:2.0.0'
``` ```
### How to use: ### How to use:
+1 -1
View File
@@ -15,7 +15,7 @@
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:2.0.1') implementation 'com.github.prominence:openweathermap-api:2.0.1'
``` ```
### How to use: ### How to use:
+1 -1
View File
@@ -16,7 +16,7 @@
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:2.1.0') implementation 'com.github.prominence:openweathermap-api:2.1.0'
``` ```
### How to use: ### How to use:
+1 -1
View File
@@ -16,7 +16,7 @@
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:2.1.1') implementation 'com.github.prominence:openweathermap-api:2.1.1'
``` ```
### How to use: ### How to use:
+1 -1
View File
@@ -17,7 +17,7 @@
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:2.2.0') implementation 'com.github.prominence:openweathermap-api:2.2.0'
``` ```
### How to use: ### How to use:
+1 -1
View File
@@ -21,7 +21,7 @@ Other:
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:2.3.0') implementation 'com.github.prominence:openweathermap-api:2.3.0'
``` ```
### How to use: ### How to use:
-566
View File
@@ -1,566 +0,0 @@
### Implemented features:
* Current weather data
* 5 day / 3-hour forecast
* One Call API
* One Call 3 API
* Air Pollution
Other:
* Request timeout settings
### Maven coordinates:
```xml
<dependency>
<groupId>com.github.prominence</groupId>
<artifactId>openweathermap-api</artifactId>
<version>2.4.1</version>
</dependency>
```
### Gradle coordinates:
```groovy
compile('com.github.prominence:openweathermap-api:2.4.1')
```
### How to use:
Firstly, you need to create the instance of `OpenWeatherMapClient` class:
```java
OpenWeatherMapClient openWeatherClient = new OpenWeatherMapClient(API_TOKEN);
```
where `API_TOKEN` is your token([you can get it here](https://home.openweathermap.org/api_keys)) as `String`.
Currently, available APIs are:
* `currentWeather()`
* `forecast5Day3HourStep()`
* `oneCall()`
* `airPollution()`
Also, it is possible to set timeouts for the requests on `openWeatherClient` object:
```java
openWeatherClient.setReadTimeout(1000);
openWeatherClient.setConnectTimeout(1000);
```
Timeout settings are passed to the requesters as a copy.
Default(more or less) customization points:
```java
...
// response language
.language(Language.RUSSIAN)
...
// response units of measure
.unitSystem(UnitSystem.IMPERIAL)
...
```
Available output forms:
* `asJava()`
* `asJSON()`
Additional output forms, available for several APIs:
* `asXML()`
* `asHTML()`
_All response forms can be in **sync** and **async** variants._
#### Current weather data
Examples:
```java
final String weatherJson = openWeatherClient
.currentWeather()
.single()
.byCityName("Minsk")
.language(Language.RUSSIAN)
.unitSystem(UnitSystem.IMPERIAL)
.retrieve()
.asJSON();
```
```java
final Weather weather = openWeatherClient
.currentWeather()
.single()
.byCityName("Minsk")
.language(Language.RUSSIAN)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava();
```
```java
final List<Weather> weatherList = openWeatherClient
.currentWeather()
.multiple()
.byCitiesInCycle(Coordinate.of(55.5, 37.5))
.language(Language.GERMAN)
.unitSystem(UnitSystem.IMPERIAL)
.retrieve()
.asJava();
```
```java
final CompletableFuture<String> weatherXmlFuture = openWeatherClient
.currentWeather()
.single()
.byZipCodeAndCountry("220015", "by")
.language(Language.RUSSIAN)
.unitSystem(UnitSystem.METRIC)
.retrieveAsync()
.asXML();
```
You are able to set preferable options(via chain methods) and execute appropriate request.
`com.github.prominence.openweathermap.api.model.weather.Weather`'s useful public methods(setters are not listed):
| Method | Description |
|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `getCalculationTime()` | Returns `LocalDateTime` object with data calculation time. |
| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. |
| `getTemperature()` | Returns `Temperature` instance that contains information about temperature. Available fields: `value`, `maxTemperature`, `minTemperature`, `feelsLike` and `unit`. |
| `getAtmosphericPressure()`| Returns `AtmosphericPressure` instance that contains information about atmospheric pressure. Available fields: `value`, `seaLevelValue`, `groundLevelValue` and `unit`. |
| `getHumidity()` | Returns `Humidity` instance that contains humidity percentage information. |
| `getWind()` | Returns `Wind` instance that contains wind information: `speed`, `degrees`, `gust` and `unit`. |
| `getRain()` | Returns `Rain` instance that contains information about rain volume for the last one hour and/or the last 3 hours. Can be absent in case of no data. |
| `getSnow()` | Returns `Snow` instance that contains information about snow volume for the last one hour and/or the last 3 hours. Can be absent in case of no data. |
| `getClouds()` | Returns `Clouds` instance that contains information about cloudiness percentage. |
| `getLocation()` | Returns `Location` object. Available fields: `id`, `name`, `countryCode`, `sunrise` and `sunset` time, `zoneOffset` and `coordinate`. |
| `toString()` | Returns informative string for the whole available weather information. |
`toString()` output example:
```
Location: Minsk(BY), Weather: clear sky, -4.22 ℃, 1020.0 hPa, Clouds: 0%
```
#### 5 day / 3-hour forecast
Examples:
```java
final Forecast forecast = openWeatherClient
.forecast5Day3HourStep()
.byCityName("Minsk")
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.count(15)
.retrieve()
.asJava();
```
```java
final String forecastJson = getClient()
.forecast5Day3HourStep()
.byCityName("New York", "NY", "US")
.language(Language.SPANISH)
.unitSystem(UnitSystem.IMPERIAL)
.count(15)
.retrieve()
.asJSON();
```
```java
CompletableFuture<String> forecastFuture = getClient()
.forecast5Day3HourStep()
.byCityId(350001514)
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.count(15)
.retrieveAsync()
.asXML();
```
```java
final String forecastXml = getClient()
.forecast5Day3HourStep()
.byZipCodeInUSA("10005")
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asXML();
```
You are able to set preferable options(via chain methods) and execute appropriate request.
`com.github.prominence.openweathermap.api.model.forecast.free.Forecast`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| `getLocation()` | Returns `Location` object. Available fields: `id`, `name`, `countryCode`, `sunrise` and `sunset` time, `zoneOffset`, `coordinate` and `population`. |
| `getWeatherForecasts()` | Returns list of `WeatherForecast` objects with forecast information. |
| `toString()` | Returns informative string for the whole available forecast information. |
`toString()` output example:
```
A forecast for Minsk with 15 timestamps.
```
`com.github.prominence.openweathermap.api.model.forecast.WeatherForecast`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. |
| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. |
| `getTemperature()` | Returns `Temperature` instance that contains information about temperature. Available fields: `value`, `maxTemperature`, `minTemperature`, `feelsLike` and `unit`. |
| `getAtmosphericPressure()` | Returns `AtmosphericPressure` instance that contains information about atmospheric pressure. Available fields: `value`, `seaLevelValue`, `groundLevelValue` and `unit`. |
| `getHumidity()` | Returns `Humidity` instance that contains humidity percentage information. |
| `getWind()` | Returns `Wind` instance that contains wind information: `speed`, `degrees` and `unit`. |
| `getRain()` | Returns `Rain` instance that contains information about rain volume for the last 3 hours. Can be absent in case of no data. |
| `getSnow()` | Returns `Snow` instance that contains information about snow volume for the last 3 hours. Can be absent in case of no data. |
| `getClouds()` | Returns `Clouds` instance that contains information about cloudiness percentage. |
| `getForecastTimeISO()` | Returns String with time of data forecasted, ISO, UTC. |
| `getDayTime()` | Returns enumerations representing the part of day(day, night). |
| `toString()` | Returns informative string for the forecast of particular timestamp. |
#### One Call 3 API
Examples:
```java
final CurrentWeatherData currentWeatherData = getClient()
.oneCall3()
.current()
.byCoordinate(Coordinate.of(53.54, 27.34))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava();
```
#### One Call API (Deprecated)
Examples:
```java
final CurrentWeatherData currentWeatherData = openWeatherClient
.oneCall()
.current()
.byCoordinate(Coordinate.of(53.54, 27.34))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava();
```
```java
final CurrentWeatherData currentWeatherData = openWeatherClient
.oneCall()
.current()
.byCoordinate(Coordinate.of(53.54, 27.34))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.exclude(OneCallResultOptions.CURRENT, OneCallResultOptions.MINUTELY)
.retrieve()
.asJava();
```
```java
final CompletableFuture<CurrentWeatherData> currentWeatherDataFuture = openWeatherClient
.oneCall()
.current()
.byCoordinate(Coordinate.of(53.54, 27.34))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieveAsync()
.asJava();
```
```java
final String responseJson = openWeatherClient
.oneCall()
.current()
.byCoordinate(Coordinate.of(53.54, 27.34))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJSON();
```
```java
final HistoricalWeatherData historicalWeatherData = openWeatherClient
.oneCall()
.historical()
.byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava();
```
```java
final String responseJson = openWeatherClient
.oneCall()
.historical()
.byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJSON();
```
```java
final CompletableFuture<HistoricalWeatherData> historicalWeatherDataFuture = openWeatherClient
.oneCall()
.historical()
.byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieveAsync()
.asJava();
```
```java
final CompletableFuture<String> responseJsonFuture = openWeatherClient
.oneCall()
.historical()
.byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieveAsync()
.asJSON();
```
You are able to set preferable options(via chain methods) and execute appropriate request.
`com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|--------------------------------------------------------------------------------|
| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. |
| `getTimezone()` | Returns location timezone object. |
| `getTimezoneOffset()` | Returns zone offset. |
| `getCurrent()` | Returns `Current` object with current weather state if available. |
| `getMinutelyList()` | Returns list of `Minutely` objects if available. |
| `getHourlyList()` | Returns list of `Houlry` objects if available. |
| `getDailyList()` | Returns list of `Daily` objects if available. |
| `getAlerts()` | Returns list of `Alert` objects if available. |
`com.github.prominence.openweathermap.api.model.onecall.Current`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|-------------------------------------------------------------------------------------------------|
| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. |
| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. |
| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. |
| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. |
| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. |
| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. |
| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. |
| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. |
| `getUvIndex()` | Returns UV index value. |
| `getVisibilityInMetres()` | Returns visibility in metres. |
| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. |
| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. |
| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. |
`com.github.prominence.openweathermap.api.model.onecall.current.Minutely`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|---------------------------------------------------------------|
| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. |
| `getPrecipitationVolume()` | Returns precipitation volume. |
`com.github.prominence.openweathermap.api.model.onecall.current.Hourly`'s useful public methods(setters are not listed):
| Method | Description |
|-----------------------------------------------|---------------------------------------------------------------------------------------------------|
| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. |
| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. |
| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. |
| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. |
| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. |
| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. |
| `getUvIndex()` | Returns UV index value. |
| `getVisibilityInMetres()` | Returns visibility in metres. |
| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. |
| `getProbabilityOfPrecipitation()` | Returns probability of precipitation(not percentage). |
| `getProbabilityOfPrecipitationPercentage()` | Returns probability of precipitation percentage. |
| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. |
| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. |
`com.github.prominence.openweathermap.api.model.onecall.current.Daily`'s useful public methods(setters are not listed):
| Method | Description |
|---------------------------------------------|---------------------------------------------------------------------------------------------------|
| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. |
| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. |
| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. |
| `getMoonriseTime()` | Returns `LocalDateTime` object with moonrise time. |
| `getMoonsetTime()` | Returns `LocalDateTime` object with moonset time. |
| `getMoonPhase()` | Returns `MoonPhase` object with `MoonType` info and value. |
| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. |
| `getTemperature()` | Returns `DailyTemperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. |
| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. |
| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. |
| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. |
| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. |
| `getUvIndex()` | Returns UV index value. |
| `getProbabilityOfPrecipitation()` | Returns probability of precipitation(not percentage). |
| `getProbabilityOfPrecipitationPercentage()` | Returns probability of precipitation percentage. |
| `getRain()` | Returns `DailyRain` object. Available fields: `value`. |
| `getSnow()` | Returns `DailySnow` object. Available fields: `value`. |
`com.github.prominence.openweathermap.api.model.onecall.current.Alert`'s useful public methods(setters are not listed):
| Method | Description |
|------------------------------|--------------------------------------------------------|
| `getSenderName()` | Returns alert sender name. |
| `getEventName()` | Returns alert event name. |
| `getStartTime()` | Returns `LocalDateTime` when event should start. |
| `getEndTime()` | Returns `LocalDateTime` when event should end. |
| `getDescription()` | Returns alert description. |
`com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|-------------------------------------------------------------------------------|
| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. |
| `getTimezone()` | Returns location timezone object. |
| `getTimezoneOffset()` | Returns zone offset. |
| `getHistoricalWeather()` | Returns `HistoricalWeather` object with historical weather state. |
| `getHourlyList()` | Returns list of `HourlyHistorical` objects. |
`com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeather`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|-------------------------------------------------------------------------------------------------|
| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. |
| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. |
| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. |
| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. |
| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. |
| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. |
| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. |
| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. |
| `getUvIndex()` | Returns UV index value. |
| `getVisibilityInMetres()` | Returns visibility in metres. |
| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. |
| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. |
| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. |
`com.github.prominence.openweathermap.api.model.onecall.historical.HourlyHistorical`'s useful public methods(setters are not listed):
| Method | Description |
|-----------------------------------|---------------------------------------------------------------------------------------------------|
| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. |
| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. |
| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. |
| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. |
| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. |
| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. |
| `getVisibilityInMetres()` | Returns visibility in metres. |
| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. |
| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. |
| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. |
#### Air Pollution API
Examples:
```java
final AirPollutionDetails airPollutionDetails = openWeatherClient
.airPollution()
.current()
.byCoordinate(Coordinate.of(53.54, 27.34))
.retrieve()
.asJava();
```
```java
final AirPollutionDetails airPollutionDetails = openWeatherClient
.airPollution()
.historical()
.byCoordinateAndPeriod(Coordinate.of(53.54, 27.34), 1606223802, 1606482999)
.retrieve()
.asJava();
```
`com.github.prominence.openweathermap.api.model.air.pollution.AirPollutionDetails`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|---------------------------------------------------------------------------|
| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. |
| `getAirPollutionRecords()` | Returns list of `AirPollutionRecord` objects. |
`com.github.prominence.openweathermap.api.model.air.pollution.AirPollutionRecord`'s useful public methods(setters are not listed):
| Method | Description |
|-------------------------------|---------------------------------------------------------------------------|
| `getForecastTime()` | Returns `LocalDateTime` object with air pollution forecast time. |
| `getAirQualityIndex()` | Returns `AirQualityIndex` object. |
| `getCO()` | Returns carbon monoxide concentration value in μg/m^3.s. |
| `getCarbonMonoxide()` | An alias for `getCO()` method. |
| `getNO()` | Returns nitrogen monoxide concentration value in μg/m^3. |
| `getNitrogenMonoxide()` | An alias for `getNO()` method. |
| `getNO2()` | Returns nitrogen dioxide concentration value in μg/m^3. |
| `getNitrogenDioxide()` | An alias for `getNO2()` method. |
| `getO3()` | Returns ozone concentration value in μg/m^3. |
| `getOzone()` | An alias for `getO3()` method. |
| `getSO2()` | Returns sulphur dioxide concentration value in μg/m^3. |
| `getSulphurDioxide()` | An alias for `getSO2()` method. |
| `getPM2_5()` | Returns fine particles matter concentration value in μg/m^3. |
| `getFineParticlesMatter()` | An alias for `getPM2_5()` method. |
| `getPM10()` | Returns coarse particulate matter concentration value in μg/m^3. |
| `getCoarseParticulateMatter()`| An alias for `getPM10()` method. |
| `getNH3()` | Returns ammonia concentration value in μg/m^3. |
| `getAmmonia()` | An alias for `getNH3()` method. |
### Constants and options
#### Language
| Constant | Description |
|------------------------------|-------------------------------|
| Language.AFRIKAANS | Afrikaans language. |
| Language.ALBANIAN | ALBANIAN language. |
| Language.ARABIC | Arabic language. |
| Language.AZERBAIJANI | Azerbaijani language. |
| Language.BULGARIAN | Bulgarian language. |
| Language.CATALAN | Catalan language. |
| Language.CZECH | Czech language. |
| Language.DANISH | Danish language. |
| Language.GERMAN | German language. |
| Language.GREEK | Greek language. |
| Language.ENGLISH | English language. |
| Language.BASQUE | Basque language. |
| Language.PERSIAN | Persian (Farsi) language. |
| Language.FINNISH | Finnish language. |
| Language.FRENCH | French language. |
| Language.GALICIAN | Galician language. |
| Language.HEBREW | Hebrew language. |
| Language.HINDI | Hindi language. |
| Language.CROATIAN | Croatian language. |
| Language.HUNGARIAN | Hungarian language. |
| Language.INDONESIAN | Indonesian language. |
| Language.ITALIAN | Italian language. |
| Language.JAPANESE | Japanese language. |
| Language.KOREAN | Korean language. |
| Language.LATVIAN | Latvian language. |
| Language.LITHUANIAN | Lithuanian language. |
| Language.MACEDONIAN | Macedonian language. |
| Language.NORWEGIAN | Norwegian language. |
| Language.DUTCH | Dutch language. |
| Language.POLISH | Polish language. |
| Language.PORTUGUESE | Portuguese language. |
| Language.PORTUGUES_BRAZIL | Português Brasil language. |
| Language.ROMANIAN | Romanian language. |
| Language.RUSSIAN | Russian language. |
| Language.SWEDISH | Swedish language. |
| Language.SLOVAK | Slovak language. |
| Language.SLOVENIAN | Slovenian language. |
| Language.SPANISH | Spanish language. |
| Language.SERBIAN | Serbian language. |
| Language.THAI | Thai language. |
| Language.TURKISH | Turkish language. |
| Language.UKRAINIAN | Ukrainian language. |
| Language.VIETNAMESE | Vietnamese language. |
| Language.CHINESE_SIMPLIFIED | Chinese Simplified language. |
| Language.CHINESE_TRADITIONAL | Chinese Traditional language. |
| Language.ZULU | Zulu language. |
#### Unit
| Constant | Description |
|----------------------|------------------------------------------------|
| Unit.METRIC_SYSTEM | Celsius, meter/sec, hPa, mm(rain, snow). |
| Unit.IMPERIAL_SYSTEM | Fahrenheit, miles/hour, hPa, mm(rain, snow). |
| Unit.STANDARD_SYSTEM | Kelvin, meter/sec, hPa, mm(rain, snow). |
### Dependencies
* com.fasterxml.jackson.core:jackson-databind:2.13.4.2
* org.slf4j:slf4j-api:1.7.36 (*compile*)
* org.junit.jupiter:junit-jupiter-engine:5.8.2 (*test*)
* org.junit.platform:junit-platform-runner:1.8.2 (*test*)
+48 -25
View File
@@ -1,9 +1,13 @@
### Implemented features: ### Implemented features:
* Current weather data * Current weather data
* 5 day / 3-hour forecast * Hourly forecast
* One Call API * One Call API
* One Call 3 API * Daily forecast
* Solar Radiation API
* 5 day / 3-hour forecast
* Road Risk API
* Air Pollution * Air Pollution
* Geocoding API
Other: Other:
@@ -15,14 +19,46 @@ Other:
<dependency> <dependency>
<groupId>com.github.prominence</groupId> <groupId>com.github.prominence</groupId>
<artifactId>openweathermap-api</artifactId> <artifactId>openweathermap-api</artifactId>
<version>2.4.0</version> <version>3.0.0-SNAPSHOT</version>
</dependency> </dependency>
``` ```
```xml
<repositories>
...
<!-- Repository for snapshot versions -->
<repository>
<id>oss.sonatype.org-snapshot</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
...
</repositories>
```
### Gradle coordinates: ### Gradle coordinates:
```groovy ```groovy
compile('com.github.prominence:openweathermap-api:2.4.0') implementation 'com.github.prominence:openweathermap-api:3.0.0-SNAPSHOT'
```
```groovy
repositories {
...
// Repository for snapshot versions
maven {
url "https://oss.sonatype.org/content/repositories/snapshots"
mavenContent {
snapshotsOnly()
}
}
...
}
``` ```
### How to use: ### How to use:
@@ -128,7 +164,7 @@ You are able to set preferable options(via chain methods) and execute appropriat
| `getRain()` | Returns `Rain` instance that contains information about rain volume for the last one hour and/or the last 3 hours. Can be absent in case of no data. | | `getRain()` | Returns `Rain` instance that contains information about rain volume for the last one hour and/or the last 3 hours. Can be absent in case of no data. |
| `getSnow()` | Returns `Snow` instance that contains information about snow volume for the last one hour and/or the last 3 hours. Can be absent in case of no data. | | `getSnow()` | Returns `Snow` instance that contains information about snow volume for the last one hour and/or the last 3 hours. Can be absent in case of no data. |
| `getClouds()` | Returns `Clouds` instance that contains information about cloudiness percentage. | | `getClouds()` | Returns `Clouds` instance that contains information about cloudiness percentage. |
| `getLocation()` | Returns `Location` object. Available fields: `id`, `name`, `countryCode`, `sunrise` and `sunset` time, `zoneOffset` and `coordinate`. | | `getLocation()` | Returns `Location` object. Available fields: `id`, `name`, `countryCode`, `sunrise` and `sunset` time, `zoneOffset` and `coordinates`. |
| `toString()` | Returns informative string for the whole available weather information. | | `toString()` | Returns informative string for the whole available weather information. |
`toString()` output example: `toString()` output example:
@@ -187,7 +223,7 @@ You are able to set preferable options(via chain methods) and execute appropriat
| Method | Description | | Method | Description |
|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| |-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| `getLocation()` | Returns `Location` object. Available fields: `id`, `name`, `countryCode`, `sunrise` and `sunset` time, `zoneOffset`, `coordinate` and `population`. | | `getLocation()` | Returns `Location` object. Available fields: `id`, `name`, `countryCode`, `sunrise` and `sunset` time, `zoneOffset`, `coordinates` and `population`. |
| `getWeatherForecasts()` | Returns list of `WeatherForecast` objects with forecast information. | | `getWeatherForecasts()` | Returns list of `WeatherForecast` objects with forecast information. |
| `toString()` | Returns informative string for the whole available forecast information. | | `toString()` | Returns informative string for the whole available forecast information. |
@@ -196,7 +232,7 @@ You are able to set preferable options(via chain methods) and execute appropriat
A forecast for Minsk with 15 timestamps. A forecast for Minsk with 15 timestamps.
``` ```
`com.github.prominence.openweathermap.api.model.forecast.WeatherForecast`'s useful public methods(setters are not listed): `com.github.prominence.openweathermap.api.model.forecast.free.WeatherForecast`'s useful public methods(setters are not listed):
| Method | Description | | Method | Description |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
@@ -213,20 +249,7 @@ A forecast for Minsk with 15 timestamps.
| `getDayTime()` | Returns enumerations representing the part of day(day, night). | | `getDayTime()` | Returns enumerations representing the part of day(day, night). |
| `toString()` | Returns informative string for the forecast of particular timestamp. | | `toString()` | Returns informative string for the forecast of particular timestamp. |
#### One Call 3 API #### One Call API
Examples:
```java
final CurrentWeatherData currentWeatherData = getClient()
.oneCall3()
.current()
.byCoordinate(Coordinate.of(53.54, 27.34))
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava();
```
#### One Call API (Deprecated)
Examples: Examples:
```java ```java
final CurrentWeatherData currentWeatherData = openWeatherClient final CurrentWeatherData currentWeatherData = openWeatherClient
@@ -323,7 +346,7 @@ You are able to set preferable options(via chain methods) and execute appropriat
| Method | Description | | Method | Description |
|-------------------------------|--------------------------------------------------------------------------------| |-------------------------------|--------------------------------------------------------------------------------|
| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. | | `getCoordinates()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. |
| `getTimezone()` | Returns location timezone object. | | `getTimezone()` | Returns location timezone object. |
| `getTimezoneOffset()` | Returns zone offset. | | `getTimezoneOffset()` | Returns zone offset. |
| `getCurrent()` | Returns `Current` object with current weather state if available. | | `getCurrent()` | Returns `Current` object with current weather state if available. |
@@ -411,7 +434,7 @@ You are able to set preferable options(via chain methods) and execute appropriat
| Method | Description | | Method | Description |
|-------------------------------|-------------------------------------------------------------------------------| |-------------------------------|-------------------------------------------------------------------------------|
| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. | | `getCoordinates()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. |
| `getTimezone()` | Returns location timezone object. | | `getTimezone()` | Returns location timezone object. |
| `getTimezoneOffset()` | Returns zone offset. | | `getTimezoneOffset()` | Returns zone offset. |
| `getHistoricalWeather()` | Returns `HistoricalWeather` object with historical weather state. | | `getHistoricalWeather()` | Returns `HistoricalWeather` object with historical weather state. |
@@ -474,7 +497,7 @@ final AirPollutionDetails airPollutionDetails = openWeatherClient
| Method | Description | | Method | Description |
|-------------------------------|---------------------------------------------------------------------------| |-------------------------------|---------------------------------------------------------------------------|
| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. | | `getCoordinates()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. |
| `getAirPollutionRecords()` | Returns list of `AirPollutionRecord` objects. | | `getAirPollutionRecords()` | Returns list of `AirPollutionRecord` objects. |
`com.github.prominence.openweathermap.api.model.air.pollution.AirPollutionRecord`'s useful public methods(setters are not listed): `com.github.prominence.openweathermap.api.model.air.pollution.AirPollutionRecord`'s useful public methods(setters are not listed):
@@ -560,7 +583,7 @@ final AirPollutionDetails airPollutionDetails = openWeatherClient
| Unit.STANDARD_SYSTEM | Kelvin, meter/sec, hPa, mm(rain, snow). | | Unit.STANDARD_SYSTEM | Kelvin, meter/sec, hPa, mm(rain, snow). |
### Dependencies ### Dependencies
* com.fasterxml.jackson.core:jackson-databind:2.13.4.2 * com.fasterxml.jackson.core:jackson-databind:2.13.2.2
* org.slf4j:slf4j-api:1.7.36 (*compile*) * org.slf4j:slf4j-api:1.7.36 (*compile*)
* org.junit.jupiter:junit-jupiter-engine:5.8.2 (*test*) * org.junit.jupiter:junit-jupiter-engine:5.8.2 (*test*)
* org.junit.platform:junit-platform-runner:1.8.2 (*test*) * org.junit.platform:junit-platform-runner:1.8.2 (*test*)
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+234
View File
@@ -0,0 +1,234 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
+89
View File
@@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
-187
View File
@@ -1,187 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.prominence</groupId>
<artifactId>openweathermap-api</artifactId>
<version>2.4.1</version>
<packaging>jar</packaging>
<name>Java OpenWeatherMap API</name>
<description>Java API for OpenWeatherMap services.</description>
<url>https://github.com/Prominence/openweathermap-java-api</url>
<scm>
<url>https://github.com/Prominence/openweathermap-java-api</url>
<connection>scm:git:git://github.com/Prominence/openweathermap-java-api.git</connection>
<developerConnection>scm:git:git@github.com:prominence/openweathermap-java-api.git</developerConnection>
</scm>
<issueManagement>
<url>https://github.com/Prominence/openweathermap-java-api/issues</url>
<system>GitHub Issues</system>
</issueManagement>
<licenses>
<license>
<name>MIT License</name>
<url>https://www.opensource.org/licenses/mit-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<email>alexey.zinchenko@protonmail.com</email>
<name>Alexey Zinchenko</name>
<url>https://github.com/prominence</url>
<id>Prominence</id>
</developer>
</developers>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<excludes>
<exclude>**/test/*</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.13</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<source>8</source>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.8.2</version>
</dependency>
</dependencies>
</project>
+1
View File
@@ -0,0 +1 @@
rootProject.name = 'openweathermap-api'
@@ -24,14 +24,21 @@ package com.github.prominence.openweathermap.api;
import com.github.prominence.openweathermap.api.annotation.SubscriptionAvailability; import com.github.prominence.openweathermap.api.annotation.SubscriptionAvailability;
import com.github.prominence.openweathermap.api.conf.TimeoutSettings; import com.github.prominence.openweathermap.api.conf.TimeoutSettings;
import com.github.prominence.openweathermap.api.core.net.HttpClient;
import com.github.prominence.openweathermap.api.core.net.HttpURLConnectionBasedHttpClient;
import com.github.prominence.openweathermap.api.request.RequestSettings; 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.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.free.FiveDayThreeHourStepForecastRequester;
import com.github.prominence.openweathermap.api.request.forecast.hourly.FourDaysHourlyForecastRequester;
import com.github.prominence.openweathermap.api.request.geocoding.GeocodingRequester;
import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherRequester; import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherRequester;
import com.github.prominence.openweathermap.api.request.radiation.SolarRadiationRequester;
import com.github.prominence.openweathermap.api.request.roadrisk.RoadRiskRequester;
import com.github.prominence.openweathermap.api.request.weather.CurrentWeatherRequester; 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.*;
import static com.github.prominence.openweathermap.api.enums.SubscriptionPlan.SPECIAL;
/** /**
* The main public API client to communicate with OpenWeatherMap services. * The main public API client to communicate with OpenWeatherMap services.
@@ -41,6 +48,8 @@ public class OpenWeatherMapClient {
private final String apiKey; private final String apiKey;
private final TimeoutSettings timeoutSettings = new TimeoutSettings(); private final TimeoutSettings timeoutSettings = new TimeoutSettings();
private HttpClient httpClient = new HttpURLConnectionBasedHttpClient();
/** /**
* Created OpenWeatherMap client object. * Created OpenWeatherMap client object.
* @param apiKey API key obtained on <a href="https://home.openweathermap.org/api_keys">OpenWeatherMap site</a>. * @param apiKey API key obtained on <a href="https://home.openweathermap.org/api_keys">OpenWeatherMap site</a>.
@@ -57,22 +66,26 @@ public class OpenWeatherMapClient {
timeoutSettings.setReadTimeout(readTimeout); timeoutSettings.setReadTimeout(readTimeout);
} }
public void setHttpClient(HttpClient httpClient) {
this.httpClient = httpClient;
}
/** /**
* Current Weather <a href="https://openweathermap.org/current">API</a>. * Current Weather <a href="https://openweathermap.org/current">API</a>.
* @return requester for retrieving current weather information. * @return requester for retrieving current weather information.
*/ */
@SubscriptionAvailability(plans = ALL) @SubscriptionAvailability(plans = ALL)
public CurrentWeatherRequester currentWeather() { public CurrentWeatherRequester currentWeather() {
return new CurrentWeatherRequester(new RequestSettings(apiKey, timeoutSettings)); return new CurrentWeatherRequester(getRequestSettings());
} }
/** /**
* 5 Day / 3 Hour Forecast <a href="https://openweathermap.org/forecast5">API</a>. * Hourly forecast <a href="https://openweathermap.org/api/hourly-forecast">API</a>.
* @return requester for retrieving 5 day/3-hour weather forecast information. * @return requester for retrieving hourly weather forecast information for 4 days.
*/ */
@SubscriptionAvailability(plans = ALL) @SubscriptionAvailability(plans = { DEVELOPER, PROFESSIONAL, ENTERPRISE })
public FiveDayThreeHourStepForecastRequester forecast5Day3HourStep() { public FourDaysHourlyForecastRequester forecastHourly4Days() {
return new FiveDayThreeHourStepForecastRequester(new RequestSettings(apiKey, timeoutSettings)); return new FourDaysHourlyForecastRequester(getRequestSettings());
} }
/** /**
@@ -81,27 +94,53 @@ public class OpenWeatherMapClient {
* @return requester for retrieving one call weather information. * @return requester for retrieving one call weather information.
*/ */
@SubscriptionAvailability(plans = ALL) @SubscriptionAvailability(plans = ALL)
@Deprecated
public OneCallWeatherRequester oneCall() { public OneCallWeatherRequester oneCall() {
return new OneCallWeatherRequester(new RequestSettings(apiKey, timeoutSettings)); return new OneCallWeatherRequester(getRequestSettings());
} }
/** /**
* One Call 3 API <a href="https://openweathermap.org/api/one-call-3">API</a>. * Daily forecast <a href="https://openweathermap.org/api/hourly-forecast">API</a>.
* Includes a weather summary statement in addition to the information provided by {@link #oneCall()} * @return requester for retrieving daily weather forecast information for 16 days.
* */
* Please note, that One Call API 3.0 is included in the "One Call by Call" subscription only. @SubscriptionAvailability(plans = PAID)
* 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. public DailyForecastRequester forecastDaily16Days() {
* 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. return new DailyForecastRequester(getRequestSettings());
* 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. /**
* Climatic forecast <a href="https://openweathermap.org/api/forecast30">API</a>.
* @return requester for retrieving climatic weather forecast information for 30 days.
*/
@SubscriptionAvailability(plans = { DEVELOPER, PROFESSIONAL, ENTERPRISE })
public ClimaticForecastRequester climaticForecast30Days() {
return new ClimaticForecastRequester(getRequestSettings());
}
/**
* Solar Radiation <a href="https://openweathermap.org/api/solar-radiation">API</a>.
* @return requester for retrieving solar radiation information.
*/ */
@SubscriptionAvailability(plans = SPECIAL) @SubscriptionAvailability(plans = SPECIAL)
public OneCallWeatherRequester oneCall3() { public SolarRadiationRequester solarRadiation() {
RequestSettings requestSettings = new RequestSettings(apiKey, timeoutSettings); return new SolarRadiationRequester(getRequestSettings());
requestSettings.setUseApi3(); }
return new OneCallWeatherRequester(requestSettings);
/**
* 5 Day / 3 Hour Forecast <a href="https://openweathermap.org/forecast5">API</a>.
* @return requester for retrieving 5 day/3-hour weather forecast information.
*/
@SubscriptionAvailability(plans = ALL)
public FiveDayThreeHourStepForecastRequester forecast5Day3HourStep() {
return new FiveDayThreeHourStepForecastRequester(getRequestSettings());
}
/**
* Road Risk <a href="https://openweathermap.org/api/road-risk">API</a>.
* @return requester for retrieving road risk information.
*/
@SubscriptionAvailability(plans = SPECIAL)
public RoadRiskRequester roadRisk() {
return new RoadRiskRequester(getRequestSettings());
} }
/** /**
@@ -111,6 +150,17 @@ public class OpenWeatherMapClient {
*/ */
@SubscriptionAvailability(plans = ALL) @SubscriptionAvailability(plans = ALL)
public AirPollutionRequester airPollution() { public AirPollutionRequester airPollution() {
return new AirPollutionRequester(new RequestSettings(apiKey, timeoutSettings)); return new AirPollutionRequester(getRequestSettings());
}
@SubscriptionAvailability(plans = ALL)
public GeocodingRequester geocoding() {
return new GeocodingRequester(getRequestSettings());
}
private RequestSettings getRequestSettings() {
final RequestSettings requestSettings = new RequestSettings(apiKey, timeoutSettings);
requestSettings.setHttpClient(httpClient);
return requestSettings;
} }
} }
@@ -0,0 +1,10 @@
package com.github.prominence.openweathermap.api.core.net;
import com.github.prominence.openweathermap.api.conf.TimeoutSettings;
public interface HttpClient {
void setTimeoutSettings(TimeoutSettings timeoutSettings);
String executeGetRequest(String url);
String executePostRequest(String url, String body);
}
@@ -0,0 +1,126 @@
package com.github.prominence.openweathermap.api.core.net;
import com.github.prominence.openweathermap.api.conf.TimeoutSettings;
import com.github.prominence.openweathermap.api.exception.InvalidAuthTokenException;
import com.github.prominence.openweathermap.api.exception.NoDataFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class HttpURLConnectionBasedHttpClient implements HttpClient {
private static final Logger logger = LoggerFactory.getLogger(HttpURLConnectionBasedHttpClient.class);
private TimeoutSettings timeoutSettings;
@Override
public void setTimeoutSettings(TimeoutSettings timeoutSettings) {
this.timeoutSettings = timeoutSettings;
}
@Override
public String executeGetRequest(String url) {
InputStream resultStream;
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
if (timeoutSettings != null) {
if (timeoutSettings.getConnectionTimeout() != null) {
connection.setConnectTimeout(timeoutSettings.getConnectionTimeout());
}
if (timeoutSettings.getReadTimeout() != null) {
connection.setReadTimeout(timeoutSettings.getReadTimeout());
}
}
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type", "application/json; utf-8");
connection.setRequestProperty("Accept", "application/json");
resultStream = switch (connection.getResponseCode()) {
case HttpURLConnection.HTTP_OK -> connection.getInputStream();
case HttpURLConnection.HTTP_UNAUTHORIZED -> throw new InvalidAuthTokenException();
case HttpURLConnection.HTTP_NOT_FOUND, HttpURLConnection.HTTP_BAD_REQUEST ->
throw new NoDataFoundException();
default -> throw new IllegalStateException("Unexpected value: " + connection.getResponseCode());
};
} catch (IllegalStateException | IOException ex) {
logger.error("An error occurred during OpenWeatherMap API response parsing: ", ex);
throw new NoDataFoundException(ex);
}
logger.debug("Executing OpenWeatherMap API request: " + url);
return convertInputStreamToString(resultStream);
}
@Override
public String executePostRequest(String url, String body) {
InputStream resultStream;
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
if (timeoutSettings != null) {
if (timeoutSettings.getConnectionTimeout() != null) {
connection.setConnectTimeout(timeoutSettings.getConnectionTimeout());
}
if (timeoutSettings.getReadTimeout() != null) {
connection.setReadTimeout(timeoutSettings.getReadTimeout());
}
}
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; utf-8");
connection.setRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
try(OutputStream os = connection.getOutputStream()) {
byte[] input = body.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
resultStream = switch (connection.getResponseCode()) {
case HttpURLConnection.HTTP_OK -> connection.getInputStream();
case HttpURLConnection.HTTP_UNAUTHORIZED -> throw new InvalidAuthTokenException();
case HttpURLConnection.HTTP_NOT_FOUND, HttpURLConnection.HTTP_BAD_REQUEST ->
throw new NoDataFoundException();
default -> throw new IllegalStateException("Unexpected value: " + connection.getResponseCode());
};
} catch (IllegalStateException | IOException ex) {
logger.error("An error occurred during OpenWeatherMap API response parsing: ", ex);
throw new NoDataFoundException(ex);
}
logger.debug("Executing OpenWeatherMap API request: " + url);
return convertInputStreamToString(resultStream);
}
/**
* Reads the input stream line-by-line and returns its content in <code>String</code> representation.
*
* @param inputStream input stream to convert.
* @return converted <code>InputStream</code> content.
* @throws IllegalArgumentException in case if input stream is unable to be read.
*/
private static String convertInputStreamToString(InputStream inputStream) {
StringBuilder result = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
} catch (IOException ex) {
logger.error("Error during response reading: ", ex);
throw new IllegalArgumentException(ex);
}
return result.toString();
}
}
@@ -0,0 +1,97 @@
/*
* 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.core.net;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.github.prominence.openweathermap.api.request.RequestSettings;
import java.net.URL;
import java.util.stream.Collectors;
public final class RequestExecutor {
private static final String OWM_URL_BASE = "https://SUBDOMAIN.openweathermap.org/";
private final RequestSettings requestSettings;
public RequestExecutor(RequestSettings requestSettings) {
this.requestSettings = requestSettings;
}
public String getResponse() {
return getResponse(Method.GET);
}
public String getResponse(Method httpMethod) {
return getResponse(buildRequestUrl(), httpMethod);
}
/**
* Executes call to provided API url and retrieves response in <code>String</code> representation.
*
* @param url the url to make API request.
* @param httpMethod HTTP method to execute.
* @return response from the request in <code>String</code> representation.
* @throws IllegalArgumentException in case if provided parameter isn't a valid url for {@link URL} instance.
*/
private String getResponse(String url, Method httpMethod) {
final HttpClient httpClient = requestSettings.getHttpClient();
httpClient.setTimeoutSettings(requestSettings.getTimeoutSettings());
if (httpMethod == Method.GET) {
return httpClient.executeGetRequest(url);
} else {
return httpClient.executePostRequest(url, getSerializedPayload());
}
}
private String buildRequestUrl() {
StringBuilder requestUrlBuilder = new StringBuilder(OWM_URL_BASE.replace("SUBDOMAIN", requestSettings.getSubdomain()));
requestUrlBuilder.append(requestSettings.getUrlAppender());
requestUrlBuilder.append('?');
String parameters = requestSettings.getRequestParameters().entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("&"));
requestUrlBuilder.append(parameters);
return requestUrlBuilder.toString();
}
private String getSerializedPayload() {
final ObjectMapper objectMapper = new ObjectMapper();
final SimpleModule module = new SimpleModule();
module.addSerializer(requestSettings.getPayloadClass(), requestSettings.getPayloadSerializer());
objectMapper.registerModule(module);
try {
return objectMapper.writeValueAsString(requestSettings.getPayloadObject());
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public enum Method {
GET,
POST
}
}
@@ -0,0 +1,52 @@
/*
* 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;
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.AtmosphericPressure;
import java.io.IOException;
public class AtmosphericPressureDeserializer extends JsonDeserializer<AtmosphericPressure> {
@Override
public AtmosphericPressure deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode mainNode = p.getCodec().readTree(p);
final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(mainNode.get("pressure").asDouble());
final JsonNode seaLevelNode = mainNode.get("sea_level");
final JsonNode groundLevelNode = mainNode.get("grnd_level");
if (seaLevelNode != null) {
atmosphericPressure.setSeaLevelValue(seaLevelNode.asDouble());
}
if (groundLevelNode != null) {
atmosphericPressure.setGroundLevelValue(groundLevelNode.asDouble());
}
return atmosphericPressure;
}
}
@@ -0,0 +1,45 @@
/*
* 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;
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 CloudsDeserializer extends JsonDeserializer<Clouds> {
@Override
public Clouds deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode cloudsNode = p.getCodec().readTree(p);
final JsonNode allValueNode = cloudsNode.get("all");
if (allValueNode != null) {
return Clouds.withValue((byte) allValueNode.asInt());
}
return null;
}
}
@@ -0,0 +1,43 @@
/*
* 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;
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.Coordinates;
import java.io.IOException;
public class CoordinatesDeserializer extends JsonDeserializer<Coordinates> {
@Override
public Coordinates deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode rootNode = jp.getCodec().readTree(jp);
if (rootNode.has("lat") && rootNode.has("lon")) {
return Coordinates.of(rootNode.get("lat").asDouble(), rootNode.get("lon").asDouble());
}
return null;
}
}
@@ -0,0 +1,57 @@
/*
* 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;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
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.model.Coordinates;
import com.github.prominence.openweathermap.api.model.geocoding.GeocodingRecord;
import java.io.IOException;
import java.util.Map;
public class GeocodingRecordDeserializer extends JsonDeserializer<GeocodingRecord> {
private static final ObjectMapper objectMapper = new ObjectMapper();
public GeocodingRecordDeserializer() {
final SimpleModule module = new SimpleModule();
module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
objectMapper.registerModule(module);
}
@Override
public GeocodingRecord deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode rootNode = jp.getCodec().readTree(jp);
String name = rootNode.get("name").asText();
String country = rootNode.get("country").asText();
Map<String, String> localNames = objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("local_names")), new TypeReference<Map<String, String>>() {});
Coordinates coordinates = objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Coordinates.class);
return new GeocodingRecord(name, localNames, coordinates, country);
}
}
@@ -0,0 +1,41 @@
/*
* 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;
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.Humidity;
import java.io.IOException;
public class HumidityDeserializer extends JsonDeserializer<Humidity> {
@Override
public Humidity deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
return Humidity.withValue((byte) (rootNode.get("humidity").asInt()));
}
}
@@ -0,0 +1,59 @@
/*
* 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;
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.Temperature;
import java.io.IOException;
public class TemperatureDeserializer extends JsonDeserializer<Temperature> {
@Override
public Temperature deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode mainNode = p.getCodec().readTree(p);
final UnitSystem unitSystem = (UnitSystem) ctxt.findInjectableValue("unitSystem", null, null);
final double tempValue = mainNode.get("temp").asDouble();
final Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit());
final JsonNode feelsLikeNode = mainNode.get("feels_like");
if (feelsLikeNode != null) {
temperature.setFeelsLike(feelsLikeNode.asDouble());
}
final JsonNode tempMaxNode = mainNode.get("temp_max");
if (tempMaxNode != null) {
temperature.setMaxTemperature(tempMaxNode.asDouble());
}
final JsonNode tempMinNode = mainNode.get("temp_min");
if (tempMinNode != null) {
temperature.setMinTemperature(tempMinNode.asDouble());
}
return temperature;
}
}
@@ -0,0 +1,46 @@
/*
* 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;
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.WeatherState;
import java.io.IOException;
public class WeatherStateDeserializer extends JsonDeserializer<WeatherState> {
@Override
public WeatherState deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode weatherNode = p.getCodec().readTree(p);
final WeatherState weatherState = new WeatherState(
weatherNode.get("id").asInt(),
weatherNode.get("main").asText(),
weatherNode.get("description").asText()
);
weatherState.setIconId(weatherNode.get("icon").asText());
return weatherState;
}
}
@@ -0,0 +1,66 @@
/*
* 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;
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 WindDeserializer extends JsonDeserializer<Wind> {
@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());
}
JsonNode gustNode = windNode.get("gust");
if (gustNode == null) {
gustNode = windNode.get("wind_gust");
}
if (gustNode != null) {
wind.setGust(gustNode.asDouble());
}
return wind;
}
}
@@ -0,0 +1,57 @@
/*
* 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;
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.model.Coordinates;
import com.github.prominence.openweathermap.api.model.geocoding.ZipCodeGeocodingRecord;
import java.io.IOException;
public class ZipCodeGeocodingDeserializer extends JsonDeserializer<ZipCodeGeocodingRecord> {
private static final ObjectMapper objectMapper = new ObjectMapper();
public ZipCodeGeocodingDeserializer() {
final SimpleModule module = new SimpleModule();
module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
objectMapper.registerModule(module);
}
@Override
public ZipCodeGeocodingRecord deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode rootNode = p.getCodec().readTree(p);
String zip = rootNode.get("zip").asText();
String name = rootNode.get("name").asText();
String country = rootNode.get("country").asText();
Coordinates coordinates = objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Coordinates.class);
return new ZipCodeGeocodingRecord(zip, name, coordinates, country);
}
}
@@ -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<AtmosphericPressure> {
@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());
}
}
@@ -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<Clouds> {
@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;
}
}
@@ -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<Location> {
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.setCoordinates(objectMapper.readValue(objectMapper.treeAsTokens(coordNode), Coordinates.class));
}
final JsonNode populationNode = rootNode.get("population");
if (populationNode != null) {
location.setPopulation(populationNode.asLong());
}
return location;
}
}
@@ -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<Rain> {
@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;
}
}
@@ -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<Snow> {
@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;
}
}
@@ -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<Temperature> {
@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;
}
}
@@ -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<Wind> {
@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;
}
}
@@ -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<AtmosphericPressure> {
@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());
}
}
@@ -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<Clouds> {
@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;
}
}
@@ -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<Location> {
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.setCoordinates(objectMapper.readValue(objectMapper.treeAsTokens(coordNode), Coordinates.class));
}
final JsonNode populationNode = rootNode.get("population");
if (populationNode != null) {
location.setPopulation(populationNode.asLong());
}
return location;
}
}
@@ -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<Rain> {
@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;
}
}
@@ -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<Snow> {
@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;
}
}
@@ -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<Temperature> {
@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;
}
}
@@ -0,0 +1,87 @@
/*
* 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.free;
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.free.Location;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.TimeZone;
public class FreeForecastLocationDeserializer extends JsonDeserializer<Location> {
private final ObjectMapper objectMapper = new ObjectMapper();
public FreeForecastLocationDeserializer() {
final SimpleModule module = new SimpleModule();
module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
objectMapper.registerModule(module);
}
@Override
public Location deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
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 sunriseNode = rootNode.get("sunrise");
final JsonNode sunsetNode = rootNode.get("sunset");
if (sunriseNode != null) {
location.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asLong()), TimeZone.getDefault().toZoneId()));
}
if (sunsetNode != null) {
location.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asLong()), TimeZone.getDefault().toZoneId()));
}
final JsonNode coordNode = rootNode.get("coord");
if (coordNode != null) {
location.setCoordinates(objectMapper.readValue(objectMapper.treeAsTokens(coordNode), Coordinates.class));
}
final JsonNode populationNode = rootNode.get("population");
if (populationNode != null) {
location.setPopulation(populationNode.asLong());
}
return location;
}
}
@@ -0,0 +1,44 @@
/*
* 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.free;
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.free.Rain;
import java.io.IOException;
public class FreeForecastRainDeserializer extends JsonDeserializer<Rain> {
@Override
public Rain deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rainNode = p.getCodec().readTree(p);
final JsonNode oneHourNode = rainNode.get("3h");
if (oneHourNode != null) {
return Rain.withThreeHourLevelValue(oneHourNode.asDouble());
}
return null;
}
}
@@ -0,0 +1,44 @@
/*
* 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.free;
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.free.Snow;
import java.io.IOException;
public class FreeForecastSnowDeserializer extends JsonDeserializer<Snow> {
@Override
public Snow deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode snowNode = p.getCodec().readTree(p);
final JsonNode oneHourNode = snowNode.get("3h");
if (oneHourNode != null) {
return Snow.withThreeHourLevelValue(oneHourNode.asDouble());
}
return null;
}
}
@@ -0,0 +1,82 @@
/*
* 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.hourly;
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.hourly.Location;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.TimeZone;
public class HourlyForecastLocationDeserializer extends JsonDeserializer<Location> {
private final ObjectMapper objectMapper = new ObjectMapper();
public HourlyForecastLocationDeserializer() {
final SimpleModule module = new SimpleModule();
module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
objectMapper.registerModule(module);
}
@Override
public Location deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
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 sunriseNode = rootNode.get("sunrise");
final JsonNode sunsetNode = rootNode.get("sunset");
if (sunriseNode != null) {
location.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asLong()), TimeZone.getDefault().toZoneId()));
}
if (sunsetNode != null) {
location.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asLong()), TimeZone.getDefault().toZoneId()));
}
final JsonNode coordNode = rootNode.get("coord");
if (coordNode != null) {
location.setCoordinates(objectMapper.readValue(objectMapper.treeAsTokens(coordNode), Coordinates.class));
}
return location;
}
}
@@ -0,0 +1,44 @@
/*
* 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.hourly;
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.hourly.Rain;
import java.io.IOException;
public class HourlyForecastRainDeserializer extends JsonDeserializer<Rain> {
@Override
public Rain deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rainNode = p.getCodec().readTree(p);
final JsonNode oneHourNode = rainNode.get("1h");
if (oneHourNode != null) {
return Rain.withOneHourLevelValue(oneHourNode.asDouble());
}
return null;
}
}
@@ -0,0 +1,44 @@
/*
* 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.hourly;
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.hourly.Snow;
import java.io.IOException;
public class HourlyForecastSnowDeserializer extends JsonDeserializer<Snow> {
@Override
public Snow deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode snowNode = p.getCodec().readTree(p);
final JsonNode oneHourNode = snowNode.get("1h");
if (oneHourNode != null) {
return Snow.withOneHourLevelValue(oneHourNode.asDouble());
}
return null;
}
}
@@ -0,0 +1,60 @@
/*
* 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.onecall;
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.onecall.current.Alert;
import com.github.prominence.openweathermap.api.utils.JsonDeserializationUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class AlertDeserializer extends JsonDeserializer<Alert> {
@Override
public Alert deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode alertNode = p.getCodec().readTree(p);
Alert alert = new Alert();
alert.setSenderName(alertNode.get("sender_name").asText());
alert.setEventName(alertNode.get("event").asText());
alert.setStartTime(JsonDeserializationUtils.parseDateTime(alertNode.get("start")));
alert.setEndTime(JsonDeserializationUtils.parseDateTime(alertNode.get("end")));
alert.setDescription(alertNode.get("description").asText());
final JsonNode tagsNode = alertNode.get("tags");
if (tagsNode != null) {
List<String> tags = new ArrayList<>();
for (JsonNode tagNode : tagsNode) {
tags.add(tagNode.asText());
}
alert.setTags(tags);
}
return alert;
}
}
@@ -0,0 +1,40 @@
/*
* 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.onecall;
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.onecall.AtmosphericPressure;
import java.io.IOException;
public class OneCallAtmosphericPressureDeserializer extends JsonDeserializer<AtmosphericPressure> {
@Override
public AtmosphericPressure deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
return AtmosphericPressure.withValue(rootNode.get("pressure").asDouble());
}
}
@@ -0,0 +1,44 @@
/*
* 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.onecall;
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.onecall.current.DailyRain;
import java.io.IOException;
public class OneCallDailyRainDeserializer extends JsonDeserializer<DailyRain> {
@Override
public DailyRain deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
final JsonNode valueNode = rootNode.get("rain");
if (valueNode != null) {
return DailyRain.withValue(valueNode.asDouble());
}
return null;
}
}
@@ -0,0 +1,45 @@
/*
* 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.onecall;
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.onecall.current.DailySnow;
import java.io.IOException;
public class OneCallDailySnowDeserializer extends JsonDeserializer<DailySnow> {
@Override
public DailySnow deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
final JsonNode valueNode = rootNode.get("snow");
if (valueNode != null) {
return DailySnow.withValue(valueNode.asDouble());
}
return null;
}
}
@@ -0,0 +1,56 @@
/*
* 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.onecall;
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.onecall.current.DailyTemperature;
import java.io.IOException;
public class OneCallDailyTemperatureDeserializer extends JsonDeserializer<DailyTemperature> {
@Override
public DailyTemperature deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
final DailyTemperature temperature = new DailyTemperature();
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;
}
}
@@ -0,0 +1,47 @@
/*
* 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.onecall;
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.onecall.Rain;
import java.io.IOException;
public class OneCallRainDeserializer extends JsonDeserializer<Rain> {
@Override
public Rain deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
final JsonNode rainNode = rootNode.get("rain");
if (rainNode != null) {
final JsonNode oneHourNode = rainNode.get("1h");
if (oneHourNode != null) {
return Rain.withOneHourLevelValue(oneHourNode.asDouble());
}
}
return null;
}
}
@@ -0,0 +1,48 @@
/*
* 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.onecall;
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.onecall.Rain;
import com.github.prominence.openweathermap.api.model.onecall.Snow;
import java.io.IOException;
public class OneCallSnowDeserializer extends JsonDeserializer<Snow> {
@Override
public Snow deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
final JsonNode snowNode = rootNode.get("snow");
if (snowNode != null) {
final JsonNode OneHourNode = snowNode.get("1h");
if (OneHourNode != null) {
Rain.withOneHourLevelValue(OneHourNode.asDouble());
}
}
return null;
}
}
@@ -0,0 +1,55 @@
/*
* 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.onecall;
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.onecall.Temperature;
import java.io.IOException;
public class OneCallTemperatureDeserializer extends JsonDeserializer<Temperature> {
@Override
public Temperature deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
final UnitSystem unitSystem = (UnitSystem) ctxt.findInjectableValue("unitSystem", null, null);
final double tempValue = rootNode.get("temp").asDouble();
final Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit());
final JsonNode tempFeelsLike = rootNode.get("feels_like");
if (tempFeelsLike != null) {
temperature.setFeelsLike(tempFeelsLike.asDouble());
}
final JsonNode dewPoint = rootNode.get("dew_point");
if (dewPoint != null) {
temperature.setDewPoint(dewPoint.asDouble());
}
return temperature;
}
}
@@ -0,0 +1,29 @@
package com.github.prominence.openweathermap.api.deserializer.radiation;
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.radiation.SolarRadiationRecord;
import com.github.prominence.openweathermap.api.utils.JsonDeserializationUtils;
import java.io.IOException;
public class SolarRadiationRecordDeserializer extends JsonDeserializer<SolarRadiationRecord> {
@Override
public SolarRadiationRecord deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
SolarRadiationRecord record = new SolarRadiationRecord();
final JsonNode radiationNode = rootNode.get("radiation");
record.setMeasurementTime(JsonDeserializationUtils.parseDateTime(rootNode.get("dt")));
record.setCloudSkyGlobalHorizontalIrradiance(radiationNode.get("ghi").asDouble());
record.setCloudSkyDirectNormalIrradiance(radiationNode.get("dni").asDouble());
record.setCloudSkyDiffuseHorizontalIrradiance(radiationNode.get("dhi").asDouble());
record.setClearSkyGlobalHorizontalIrradiance(radiationNode.get("ghi_cs").asDouble());
record.setClearSkyDirectNormalIrradiance(radiationNode.get("dni_cs").asDouble());
record.setClearSkyDiffuseHorizontalIrradiance(radiationNode.get("dhi_cs").asDouble());
return record;
}
}
@@ -0,0 +1,23 @@
package com.github.prominence.openweathermap.api.deserializer.roadrisk;
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.EventLevel;
import com.github.prominence.openweathermap.api.model.roadrisk.Alert;
import java.io.IOException;
public class RoadRiskAlertDeserializer extends JsonDeserializer<Alert> {
@Override
public Alert deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
final Alert alert = new Alert();
alert.setEvent(rootNode.get("event").asText());
alert.setSenderName(rootNode.get("sender_name").asText());
alert.setEventLevel(EventLevel.findByValue(rootNode.get("event_level").asInt()));
return alert;
}
}
@@ -0,0 +1,23 @@
package com.github.prominence.openweathermap.api.deserializer.roadrisk;
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.RoadState;
import com.github.prominence.openweathermap.api.model.roadrisk.RoadDetails;
import java.io.IOException;
public class RoadRiskRoadDetailsDeserializer extends JsonDeserializer<RoadDetails> {
@Override
public RoadDetails deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
final RoadDetails roadDetails = new RoadDetails();
roadDetails.setSurfaceTemperature(rootNode.get("temp").asDouble());
roadDetails.setRoadState(RoadState.findByValue(rootNode.get("state").asInt()));
return roadDetails;
}
}
@@ -0,0 +1,31 @@
package com.github.prominence.openweathermap.api.deserializer.roadrisk;
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.roadrisk.Weather;
import java.io.IOException;
public class RoadRiskWeatherDeserializer extends JsonDeserializer<Weather> {
@Override
public Weather deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
final JsonNode rootNode = jsonParser.getCodec().readTree(jsonParser);
final Weather weather = new Weather();
weather.setTemperature(rootNode.get("temp").asDouble());
weather.setDewPoint(rootNode.get("dew_point").asDouble());
weather.setWindSpeed(rootNode.get("wind_speed").asDouble());
weather.setWindDegrees(rootNode.get("wind_deg").asDouble());
if (rootNode.has("precipitation_intensity")) {
weather.setPrecipitationIntensity(rootNode.get("precipitation_intensity").asDouble());
}
if (rootNode.has("visibility")) {
weather.setVisibilityInMetres(rootNode.get("visibility").asDouble());
}
return weather;
}
}
@@ -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.deserializer.weather;
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.weather.Location;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.TimeZone;
public class WeatherLocationDeserializer extends JsonDeserializer<Location> {
private final ObjectMapper objectMapper = new ObjectMapper();
public WeatherLocationDeserializer() {
final SimpleModule module = new SimpleModule();
module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
objectMapper.registerModule(module);
}
@Override
public Location deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rootNode = p.getCodec().readTree(p);
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 sysNode = rootNode.get("sys");
if (sysNode != null) {
final JsonNode countryNode = sysNode.get("country");
if (countryNode != null) {
location.setCountryCode(countryNode.asText());
}
final JsonNode sunriseNode = sysNode.get("sunrise");
final JsonNode sunsetNode = sysNode.get("sunset");
if (sunriseNode != null) {
location.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asInt()), TimeZone.getDefault().toZoneId()));
}
if (sunsetNode != null) {
location.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asInt()), TimeZone.getDefault().toZoneId()));
}
}
final JsonNode coordNode = rootNode.get("coord");
if (coordNode != null) {
location.setCoordinates(objectMapper.readValue(objectMapper.treeAsTokens(coordNode), Coordinates.class));
}
return location;
}
}
@@ -0,0 +1,51 @@
/*
* 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.weather;
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.weather.Rain;
import java.io.IOException;
public class WeatherRainDeserializer extends JsonDeserializer<Rain> {
@Override
public Rain deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode rainNode = p.getCodec().readTree(p);
if (rainNode != null) {
final JsonNode oneHourNode = rainNode.get("1h");
final JsonNode threeHourNode = rainNode.get("3h");
if (oneHourNode != null && threeHourNode != null) {
return Rain.withValues(oneHourNode.asDouble(), threeHourNode.asDouble());
} else if (oneHourNode != null) {
return Rain.withOneHourLevelValue(oneHourNode.asDouble());
} else if (threeHourNode != null) {
return Rain.withThreeHourLevelValue(threeHourNode.asDouble());
}
}
return null;
}
}
@@ -0,0 +1,51 @@
/*
* 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.weather;
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.weather.Snow;
import java.io.IOException;
public class WeatherSnowDeserializer extends JsonDeserializer<Snow> {
@Override
public Snow deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
final JsonNode snowNode = p.getCodec().readTree(p);
if (snowNode != null) {
final JsonNode oneHourNode = snowNode.get("1h");
final JsonNode threeHourNode = snowNode.get("3h");
if (oneHourNode != null && threeHourNode != null) {
return Snow.withValues(oneHourNode.asDouble(), threeHourNode.asDouble());
} else if (oneHourNode != null) {
return Snow.withOneHourLevelValue(oneHourNode.asDouble());
} else if (threeHourNode != null) {
return Snow.withThreeHourLevelValue(threeHourNode.asDouble());
}
}
return null;
}
}
@@ -0,0 +1,25 @@
package com.github.prominence.openweathermap.api.enums;
import java.util.Arrays;
public enum EventLevel {
UNKNOWN(0),
GREEN(1),
YELLOW(2),
ORANGE(3),
RED(4);
private final int value;
EventLevel(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static EventLevel findByValue(int value) {
return Arrays.stream(values()).filter(eventLevel -> eventLevel.getValue() == value).findFirst().orElse(null);
}
}
@@ -0,0 +1,39 @@
package com.github.prominence.openweathermap.api.enums;
import java.util.Arrays;
public enum RoadState {
NO_REPORT(0),
DRY(1),
MOIST(2),
MOIST_AND_CHEMICALLY_TREATED(3),
WET(4),
WET_AND_CHEMICALLY_TREATED(5),
ICE(6),
FROST(7),
SNOW(8),
SNOW_OR_ICE_WATCH(9),
SNOW_OR_ICE_WARNING(10),
WET_ABOVE_FREEZING(11),
WET_BELOW_FREEZING(12),
ABSORPTION(13),
ABSORPTION_AT_DEWPOINT(14),
DEW(15),
BLACK_ICE_WARNING(16),
OTHER(17),
SLUSH(18);
private final int value;
RoadState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static RoadState findByValue(int value) {
return Arrays.stream(values()).filter(roadState -> roadState.getValue() == value).findFirst().orElse(null);
}
}
@@ -28,9 +28,9 @@ package com.github.prominence.openweathermap.api.enums;
*/ */
public enum SubscriptionPlan { public enum SubscriptionPlan {
/** /**
* Free subscription plan. * An alias that represents any of paid plans: startup, developer, professional or enterprise.
*/ */
FREE, PAID,
/** /**
* Startup subscription plan. * Startup subscription plan.
@@ -52,13 +52,14 @@ public enum SubscriptionPlan {
*/ */
ENTERPRISE, ENTERPRISE,
/**
* Special subscription plan. You should contact a manager to get an access.
*/
SPECIAL,
/** /**
* All existing subscription plans. * All existing subscription plans.
*/ */
ALL, ALL,
/**
* Special subscription cases.
*/
SPECIAL,
} }
@@ -52,14 +52,10 @@ public enum UnitSystem {
* @return wind unit. * @return wind unit.
*/ */
public String getWindUnit() { public String getWindUnit() {
switch (this) { return switch (this) {
case IMPERIAL: case IMPERIAL -> "miles/hour";
return "miles/hour"; case STANDARD, METRIC -> "meter/sec";
case STANDARD: };
case METRIC:
default:
return "meter/sec";
}
} }
/** /**
@@ -67,15 +63,11 @@ public enum UnitSystem {
* @return temperature unit. * @return temperature unit.
*/ */
public String getTemperatureUnit() { public String getTemperatureUnit() {
switch (this) { return switch (this) {
case METRIC: case METRIC -> "°C";
return "°C"; case IMPERIAL -> "°F";
case IMPERIAL: case STANDARD -> "";
return "°F"; };
case STANDARD:
default:
return "";
}
} }
/** /**
@@ -0,0 +1,61 @@
/*
* 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.mapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.utils.JsonDeserializationUtils;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractMapper {
protected final ObjectMapper objectMapper = new ObjectMapper();
protected LocalDateTime parseDateTime(JsonNode dateTimeNode) {
return JsonDeserializationUtils.parseDateTime(dateTimeNode);
}
protected ZoneId parseZoneId(JsonNode zoneIdNode) {
return JsonDeserializationUtils.parseZoneId(zoneIdNode);
}
protected ZoneOffset parseZoneOffset(JsonNode zoneOffsetNode) {
return JsonDeserializationUtils.parseZoneOffset(zoneOffsetNode);
}
protected List<WeatherState> parseWeatherStates(JsonNode weatherArrayNode) throws IOException {
List<WeatherState> weatherStateList = new ArrayList<>();
if (weatherArrayNode != null && weatherArrayNode.isArray()) {
for (JsonNode weatherNode : weatherArrayNode) {
weatherStateList.add(objectMapper.readValue(objectMapper.treeAsTokens(weatherNode), WeatherState.class));
}
}
return weatherStateList;
}
}
@@ -26,7 +26,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.prominence.openweathermap.api.enums.AirQualityIndex; import com.github.prominence.openweathermap.api.enums.AirQualityIndex;
import com.github.prominence.openweathermap.api.model.Coordinate; import com.github.prominence.openweathermap.api.model.Coordinates;
import com.github.prominence.openweathermap.api.model.air.pollution.AirPollutionDetails; import com.github.prominence.openweathermap.api.model.air.pollution.AirPollutionDetails;
import com.github.prominence.openweathermap.api.model.air.pollution.AirPollutionRecord; import com.github.prominence.openweathermap.api.model.air.pollution.AirPollutionRecord;
@@ -37,7 +37,7 @@ import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
/** /**
* The type Air pollution response mapper. * Official API response documentation: <a href="https://openweathermap.org/api/air-pollution#fields">https://openweathermap.org/api/air-pollution#fields</a>.
*/ */
public class AirPollutionResponseMapper { public class AirPollutionResponseMapper {
/** /**
@@ -61,7 +61,7 @@ public class AirPollutionResponseMapper {
private AirPollutionDetails mapToAirPollution(JsonNode rootNode) { private AirPollutionDetails mapToAirPollution(JsonNode rootNode) {
final AirPollutionDetails airPollutionDetails = new AirPollutionDetails(); final AirPollutionDetails airPollutionDetails = new AirPollutionDetails();
airPollutionDetails.setCoordinate(parseCoordinate(rootNode.get("coord"))); airPollutionDetails.setCoordinates(parseCoordinate(rootNode.get("coord")));
final List<AirPollutionRecord> sampleList = new ArrayList<>(); final List<AirPollutionRecord> sampleList = new ArrayList<>();
final JsonNode sampleListNode = rootNode.get("list"); final JsonNode sampleListNode = rootNode.get("list");
@@ -91,11 +91,11 @@ public class AirPollutionResponseMapper {
return airPollutionRecord; return airPollutionRecord;
} }
private Coordinate parseCoordinate(JsonNode rootNode) { private Coordinates parseCoordinate(JsonNode rootNode) {
final JsonNode latitudeNode = rootNode.get("lat"); final JsonNode latitudeNode = rootNode.get("lat");
final JsonNode longitudeNode = rootNode.get("lon"); final JsonNode longitudeNode = rootNode.get("lon");
if (latitudeNode != null && longitudeNode != null) { if (latitudeNode != null && longitudeNode != null) {
return Coordinate.of(latitudeNode.asDouble(), longitudeNode.asDouble()); return Coordinates.of(latitudeNode.asDouble(), longitudeNode.asDouble());
} }
return null; return null;
} }
@@ -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<WeatherForecast> 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;
}
}
@@ -22,76 +22,45 @@
package com.github.prominence.openweathermap.api.mapper; package com.github.prominence.openweathermap.api.mapper;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonNode; 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.model.weather.*; 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.enums.UnitSystem; import com.github.prominence.openweathermap.api.enums.UnitSystem;
import com.github.prominence.openweathermap.api.model.*; 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.time.Instant; import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
/** /**
* Official API response documentation: * Official API response documentation: <a href="https://openweathermap.org/current#current_JSON">https://openweathermap.org/current#current_JSON</a>.
* Parameters: * Ignored internal parameters: "root.cod", "sys.type", "sys.id", "sys.message".
* --- coord
* |- coord.lon City geo location, longitude
* |- coord.lat City geo location, latitude
* --- weather (more info Weather condition codes)
* |- weather.id Weather condition id
* |- weather.main Group of weather parameters (Rain, Snow, Extreme etc.)
* |- weather.description Weather condition within the group
* |- weather.icon Weather icon id
* --- base Internal parameter
* --- main
* |- main.temp Temperature. UnitSystem Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
* |- main.feels_like Temperature. This temperature parameter accounts for the human perception of weather. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
* |- main.pressure Atmospheric pressure (on the sea level, if there is no sea_level or grnd_level data), hPa
* |- main.humidity Humidity, %
* |- main.temp_min Minimum temperature at the moment. This is deviation from current temp that is possible for large cities and megalopolises geographically expanded (use these parameter optionally). UnitSystem Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
* |- main.temp_max Maximum temperature at the moment. This is deviation from current temp that is possible for large cities and megalopolises geographically expanded (use these parameter optionally). UnitSystem Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
* |- main.sea_level Atmospheric pressure on the sea level, hPa
* |- main.grnd_level Atmospheric pressure on the ground level, hPa
* --- wind
* |- wind.speed Wind speed. UnitSystem Default: meter/sec, Metric: meter/sec, Imperial: miles/hour.
* |- wind.deg Wind direction, degrees (meteorological)
* |- wind.gust Wind gust. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour
* --- clouds
* |- clouds.all Cloudiness, %
* --- rain
* |- rain.1h Rain volume for the last 1 hour, mm
* |- rain.3h Rain volume for the last 3 hours, mm
* --- snow
* |- snow.1h Snow volume for the last 1 hour, mm
* |- snow.3h Snow volume for the last 3 hours, mm
* --- dt Time of data calculation, unix, UTC
* --- sys
* |- sys.type Internal parameter
* |- sys.id Internal parameter
* |- sys.message Internal parameter
* |- sys.country Country code (GB, JP etc.)
* |- sys.sunrise Sunrise time, unix, UTC
* |- sys.sunset Sunset time, unix, UTC
* --- timezone Shift in seconds from UTC
* --- id City ID
* --- name City name
* --- cod Internal parameter
*/ */
public class CurrentWeatherResponseMapper { public class CurrentWeatherResponseMapper extends AbstractMapper {
private final UnitSystem unitSystem;
/** /**
* Instantiates a new Current weather response mapper. * Instantiates a new Current weather response mapper.
* *
* @param unitSystem the unit system * @param unitSystem the unit system
*/ */
public CurrentWeatherResponseMapper(UnitSystem unitSystem) { public CurrentWeatherResponseMapper(UnitSystem unitSystem) {
this.unitSystem = unitSystem != null ? unitSystem : UnitSystem.STANDARD; 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 TemperatureDeserializer());
module.addDeserializer(AtmosphericPressure.class, new AtmosphericPressureDeserializer());
module.addDeserializer(Humidity.class, new HumidityDeserializer());
module.addDeserializer(Wind.class, new WindDeserializer());
module.addDeserializer(Rain.class, new WeatherRainDeserializer());
module.addDeserializer(Snow.class, new WeatherSnowDeserializer());
module.addDeserializer(Clouds.class, new CloudsDeserializer());
module.addDeserializer(Location.class, new WeatherLocationDeserializer());
objectMapper.registerModule(module);
} }
/** /**
@@ -100,218 +69,44 @@ public class CurrentWeatherResponseMapper {
* @param json the json string * @param json the json string
* @return the weather object * @return the weather object
*/ */
public Weather getSingle(String json) { public Weather mapToWeather(String json) {
final ObjectMapper objectMapper = new ObjectMapper();
Weather weather; Weather weather;
try { try {
final JsonNode root = objectMapper.readTree(json); final JsonNode root = objectMapper.readTree(json);
weather = getSingle(root); weather = mapToWeather(root);
} catch (JsonProcessingException e) { } catch (IOException e) {
throw new RuntimeException("Cannot parse Weather response"); throw new RuntimeException("Cannot parse Weather response", e);
} }
return weather; return weather;
} }
private Weather getSingle(JsonNode rootNode) { private Weather mapToWeather(JsonNode rootNode) throws IOException {
final JsonNode weatherArrayNode = rootNode.get("weather"); final JsonNode weatherArrayNode = rootNode.get("weather");
final JsonNode weatherNode = weatherArrayNode != null ? weatherArrayNode.get(0) : null;
final Weather weather = new Weather(); final Weather weather = new Weather();
weather.setWeatherState(parseWeatherState(weatherNode)); weather.setWeatherStates(parseWeatherStates(weatherArrayNode));
weather.setTemperature(parseTemperature(rootNode));
weather.setAtmosphericPressure(parsePressure(rootNode)); weather.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("main")), Temperature.class));
weather.setHumidity(parseHumidity(rootNode)); weather.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("main")), AtmosphericPressure.class));
weather.setWind(parseWind(rootNode)); weather.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("main")), Humidity.class));
weather.setRain(parseRain(rootNode)); weather.setWind(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("wind")), Wind.class));
weather.setSnow(parseSnow(rootNode)); if (rootNode.has("rain")) {
weather.setClouds(parseClouds(rootNode)); weather.setRain(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("rain")), Rain.class));
weather.setLocation(parseLocation(rootNode)); }
if (rootNode.has("snow")) {
weather.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("snow")), Snow.class));
}
weather.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("clouds")), Clouds.class));
weather.setLocation(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Location.class));
final JsonNode dtNode = rootNode.get("dt"); final JsonNode dtNode = rootNode.get("dt");
if (dtNode != null) { if (dtNode != null) {
weather.setCalculationTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(dtNode.asInt()), TimeZone.getDefault().toZoneId())); weather.setCalculationTime(parseDateTime(dtNode));
} }
weather.setBase(rootNode.get("base").asText());
return weather; return weather;
} }
/**
* Gets list of results.
*
* @param json the json string
* @return the list of weathers
*/
public List<Weather> getList(String json) {
final ObjectMapper objectMapper = new ObjectMapper();
final List<Weather> weatherList = new ArrayList<>();
try {
final JsonNode root = objectMapper.readTree(json);
final JsonNode listNode = root.get("list");
listNode.forEach(jsonNode -> weatherList.add(getSingle(jsonNode)));
} catch (JsonProcessingException e) {
throw new RuntimeException("Cannot parse Weather response");
}
return weatherList;
}
private WeatherState parseWeatherState(JsonNode weatherNode) {
if (weatherNode == null) {
return null;
}
final WeatherState weatherState = new WeatherState(
weatherNode.get("id").asInt(),
weatherNode.get("main").asText(),
weatherNode.get("description").asText()
);
weatherState.setIconId(weatherNode.get("icon").asText());
return weatherState;
}
private Temperature parseTemperature(JsonNode rootNode) {
final JsonNode mainNode = rootNode.get("main");
final double tempValue = mainNode.get("temp").asDouble();
final Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit());
final JsonNode feelsLikeNode = mainNode.get("feels_like");
if (feelsLikeNode != null) {
temperature.setFeelsLike(feelsLikeNode.asDouble());
}
final JsonNode tempMaxNode = mainNode.get("temp_max");
if (tempMaxNode != null) {
temperature.setMaxTemperature(tempMaxNode.asDouble());
}
final JsonNode tempMinNode = mainNode.get("temp_min");
if (tempMinNode != null) {
temperature.setMinTemperature(tempMinNode.asDouble());
}
return temperature;
}
private AtmosphericPressure parsePressure(JsonNode rootNode) {
final JsonNode mainNode = rootNode.get("main");
final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(mainNode.get("pressure").asDouble());
final JsonNode seaLevelNode = mainNode.get("sea_level");
final JsonNode groundLevelNode = mainNode.get("grnd_level");
if (seaLevelNode != null) {
atmosphericPressure.setSeaLevelValue(seaLevelNode.asDouble());
}
if (groundLevelNode != null) {
atmosphericPressure.setGroundLevelValue(groundLevelNode.asDouble());
}
return atmosphericPressure;
}
private Humidity parseHumidity(JsonNode rootNode) {
final JsonNode mainNode = rootNode.get("main");
return Humidity.withValue((byte) (mainNode.get("humidity").asInt()));
}
private Wind parseWind(JsonNode rootNode) {
final JsonNode windNode = rootNode.get("wind");
double speed = windNode.get("speed").asDouble();
final Wind wind = Wind.withValue(speed, unitSystem.getWindUnit());
final JsonNode degNode = windNode.get("deg");
if (degNode != null) {
wind.setDegrees(degNode.asDouble());
}
final JsonNode gustNode = windNode.get("gust");
if (gustNode != null) {
wind.setGust(gustNode.asDouble());
}
return wind;
}
private Rain parseRain(JsonNode rootNode) {
final JsonNode rainNode = rootNode.get("rain");
if (rainNode != null) {
final JsonNode oneHourNode = rainNode.get("1h");
final JsonNode threeHourNode = rainNode.get("3h");
if (oneHourNode != null && threeHourNode != null) {
return Rain.withValues(oneHourNode.asDouble(), threeHourNode.asDouble());
} else if (oneHourNode != null) {
return Rain.withOneHourLevelValue(oneHourNode.asDouble());
} else if (threeHourNode != null) {
return Rain.withThreeHourLevelValue(threeHourNode.asDouble());
}
}
return null;
}
private Snow parseSnow(JsonNode rootNode) {
final JsonNode snowNode = rootNode.get("snow");
if (snowNode != null) {
final JsonNode oneHourNode = snowNode.get("1h");
final JsonNode threeHourNode = snowNode.get("3h");
if (oneHourNode != null && threeHourNode != null) {
return Snow.withValues(oneHourNode.asDouble(), threeHourNode.asDouble());
} else if (oneHourNode != null) {
return Snow.withOneHourLevelValue(oneHourNode.asDouble());
} else 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 sysNode = rootNode.get("sys");
if (sysNode != null) {
final JsonNode countryNode = sysNode.get("country");
if (countryNode != null) {
location.setCountryCode(countryNode.asText());
}
final JsonNode sunriseNode = sysNode.get("sunrise");
final JsonNode sunsetNode = sysNode.get("sunset");
if (sunriseNode != null) {
location.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asInt()), TimeZone.getDefault().toZoneId()));
}
if (sunsetNode != null) {
location.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asInt()), TimeZone.getDefault().toZoneId()));
}
}
final JsonNode coordNode = rootNode.get("coord");
if (coordNode != null) {
location.setCoordinate(parseCoordinate(coordNode));
}
return location;
}
private Coordinate parseCoordinate(JsonNode rootNode) {
final JsonNode latitudeNode = rootNode.get("lat");
final JsonNode longitudeNode = rootNode.get("lon");
if (latitudeNode != null && longitudeNode != null) {
return Coordinate.of(latitudeNode.asDouble(), longitudeNode.asDouble());
}
return null;
}
} }
@@ -0,0 +1,119 @@
/*
* 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.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.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.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.util.ArrayList;
import java.util.List;
/**
* Official API response documentation: <a href="https://openweathermap.org/forecast16#JSON">https://openweathermap.org/forecast16#JSON</a>.
*/
public class DailyForecastResponseMapper extends AbstractMapper {
public DailyForecastResponseMapper(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);
}
/**
* Maps forecast response into java object.
*
* @param json the json string
* @return the forecast
*/
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<WeatherForecast> forecasts = new ArrayList<>(root.get("cnt").asInt());
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));
if (rootNode.has("pop")) {
weatherForecast.setProbabilityOfPrecipitation(rootNode.get("pop").asDouble());
}
return weatherForecast;
}
}
@@ -22,80 +22,44 @@
package com.github.prominence.openweathermap.api.mapper; package com.github.prominence.openweathermap.api.mapper;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonNode; 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.*;
import com.github.prominence.openweathermap.api.deserializer.forecast.free.FreeForecastLocationDeserializer;
import com.github.prominence.openweathermap.api.deserializer.forecast.free.FreeForecastRainDeserializer;
import com.github.prominence.openweathermap.api.deserializer.forecast.free.FreeForecastSnowDeserializer;
import com.github.prominence.openweathermap.api.enums.UnitSystem; import com.github.prominence.openweathermap.api.enums.UnitSystem;
import com.github.prominence.openweathermap.api.model.*; import com.github.prominence.openweathermap.api.model.*;
import com.github.prominence.openweathermap.api.model.forecast.*; import com.github.prominence.openweathermap.api.model.forecast.free.*;
import com.github.prominence.openweathermap.api.model.forecast.Location;
import com.github.prominence.openweathermap.api.model.forecast.Rain;
import com.github.prominence.openweathermap.api.model.forecast.Snow;
import com.github.prominence.openweathermap.api.model.Temperature;
import java.time.Instant; import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.TimeZone;
/** /**
* Official API response documentation. * Official API response documentation: <a href="https://openweathermap.org/forecast5#JSON">https://openweathermap.org/forecast5#JSON</a>.
* Parameters(but the real response can differ):
* --- cod Internal parameter
* --- message Internal parameter
* --- cnt A number of timestamps returned in the API response
* --- list
* |- list.dt Time of data forecasted, unix, UTC
* |- list.main
* |- list.main.temp Temperature. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
* |- list.main.feels_like This temperature parameter accounts for the human perception of weather. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
* |- list.main.temp_min Minimum temperature at the moment of calculation. This is minimal forecasted temperature (within large megalopolises and urban areas), use this parameter optionally. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
* |- list.main.temp_max Maximum temperature at the moment of calculation. This is maximal forecasted temperature (within large megalopolises and urban areas), use this parameter optionally. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
* |- list.main.pressure Atmospheric pressure on the sea level by default, hPa
* |- list.main.sea_level Atmospheric pressure on the sea level, hPa
* |- list.main.grnd_level Atmospheric pressure on the ground level, hPa
* |- list.main.humidity Humidity, %
* |- list.main.temp_kf Internal par
* |- list.weather
* |- list.weather.id Weather condition id
* |- list.weather.main Group of weather parameters (Rain, Snow, Extreme etc.)
* |- list.weather.description Weather condition within the group. You can get the output in your language.
* |- list.weather.icon Weather icon id
* |- list.clouds
* |- list.clouds.all Cloudiness, %
* |- list.wind
* |- list.wind.speed Wind speed. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour.
* |- list.wind.deg Wind direction, degrees (meteorological)
* |- list.visibility Average visibility, metres
* |- list.pop Probability of precipitation
* |- list.rain
* |- list.rain.3h Rain volume for last 3 hours, mm
* |- list.snow
* |- list.snow.3h Snow volume for last 3 hours
* |- list.sys
* |- list.sys.pod Part of the day (n - night, d - day)
* |- list.dt_txt Time of data forecasted, ISO, UTC
* --- city
* |- city.id City ID
* |- city.name City name
* |- city.coord
* |- city.coord.lat City geo location, latitude
* |- city.coord.lon City geo location, longitude
* |- city.country Country code (GB, JP etc.)
* |- city.timezone Shift in seconds from UTC
*/ */
public class FiveDayThreeHourStepForecastResponseMapper { public class FiveDayThreeHourStepForecastResponseMapper extends AbstractMapper {
private final UnitSystem unitSystem;
/** /**
* Instantiates a new forecast response mapper. * Instantiates a new forecast response mapper.
* *
* @param unitSystem the unit system * @param unitSystem the unit system
*/ */
public FiveDayThreeHourStepForecastResponseMapper(UnitSystem unitSystem) { public FiveDayThreeHourStepForecastResponseMapper(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 TemperatureDeserializer());
module.addDeserializer(AtmosphericPressure.class, new AtmosphericPressureDeserializer());
module.addDeserializer(Humidity.class, new HumidityDeserializer());
module.addDeserializer(Clouds.class, new CloudsDeserializer());
module.addDeserializer(Wind.class, new WindDeserializer());
module.addDeserializer(Rain.class, new FreeForecastRainDeserializer());
module.addDeserializer(Snow.class, new FreeForecastSnowDeserializer());
module.addDeserializer(Location.class, new FreeForecastLocationDeserializer());
objectMapper.registerModule(module);
} }
/** /**
@@ -105,199 +69,69 @@ public class FiveDayThreeHourStepForecastResponseMapper {
* @return the forecast * @return the forecast
*/ */
public Forecast mapToForecast(String json) { public Forecast mapToForecast(String json) {
final ObjectMapper objectMapper = new ObjectMapper();
Forecast forecast; Forecast forecast;
try { try {
final JsonNode root = objectMapper.readTree(json); final JsonNode root = objectMapper.readTree(json);
forecast = mapToForecast(root); forecast = mapToForecast(root);
} catch (JsonProcessingException e) { } catch (IOException e) {
throw new RuntimeException("Cannot parse Forecast response"); throw new RuntimeException("Cannot parse Forecast response", e);
} }
return forecast; return forecast;
} }
private Forecast mapToForecast(JsonNode root) { private Forecast mapToForecast(JsonNode rootNode) throws IOException {
final Forecast forecast = new Forecast(); final Forecast forecast = new Forecast();
forecast.setLocation(parseLocation(root.get("city"))); forecast.setLocation(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("city")), Location.class));
final List<WeatherForecast> forecasts = new ArrayList<>(root.get("cnt").asInt()); final List<WeatherForecast> forecasts = new ArrayList<>(rootNode.get("cnt").asInt());
final JsonNode forecastListNode = root.get("list"); final JsonNode forecastListNode = rootNode.get("list");
forecastListNode.forEach(forecastNode -> forecasts.add(parseWeatherForecast(forecastNode))); for (JsonNode forecastNode : forecastListNode) {
forecasts.add(parseWeatherForecast(forecastNode));
}
forecast.setWeatherForecasts(forecasts); forecast.setWeatherForecasts(forecasts);
return forecast; return forecast;
} }
private WeatherForecast parseWeatherForecast(JsonNode rootNode) { private WeatherForecast parseWeatherForecast(JsonNode rootNode) throws IOException {
final WeatherForecast weatherForecast = new WeatherForecast(); final WeatherForecast weatherForecast = new WeatherForecast();
final JsonNode weatherArrayNode = rootNode.get("weather"); final JsonNode weatherArrayNode = rootNode.get("weather");
if (weatherArrayNode != null) { weatherForecast.setWeatherStates(parseWeatherStates(weatherArrayNode));
final JsonNode weatherNode = weatherArrayNode.get(0);
weatherForecast.setWeatherState(parseWeatherState(weatherNode));
}
final JsonNode mainNode = rootNode.get("main"); final JsonNode mainNode = rootNode.get("main");
weatherForecast.setTemperature(parseTemperature(mainNode)); weatherForecast.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(mainNode), Temperature.class));
weatherForecast.setAtmosphericPressure(parsePressure(mainNode)); weatherForecast.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(mainNode), AtmosphericPressure.class));
weatherForecast.setHumidity(parseHumidity(mainNode)); weatherForecast.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(mainNode), Humidity.class));
weatherForecast.setClouds(parseClouds(rootNode)); weatherForecast.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("clouds")), Clouds.class));
weatherForecast.setWind(parseWind(rootNode)); weatherForecast.setWind(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("wind")), Wind.class));
weatherForecast.setRain(parseRain(rootNode)); if (rootNode.has("rain")) {
weatherForecast.setSnow(parseSnow(rootNode)); weatherForecast.setRain(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("rain")), Rain.class));
}
if (rootNode.has("snow")) {
weatherForecast.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("snow")), Snow.class));
}
final JsonNode sysNode = rootNode.get("sys"); final JsonNode sysNode = rootNode.get("sys");
if (sysNode != null) { if (sysNode != null) {
weatherForecast.setDayTime("d".equals(sysNode.get("pod").asText()) ? DayTime.DAY : DayTime.NIGHT); weatherForecast.setDayTime("d".equals(sysNode.get("pod").asText()) ? DayTime.DAY : DayTime.NIGHT);
} }
weatherForecast.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(rootNode.get("dt").asLong()), TimeZone.getDefault().toZoneId())); final JsonNode visibilityNode = rootNode.get("visibility");
if (visibilityNode != null) {
weatherForecast.setVisibilityInMetres(visibilityNode.asDouble());
}
final JsonNode popNode = rootNode.get("pop");
if (popNode != null) {
weatherForecast.setProbabilityOfPrecipitation(popNode.asDouble());
}
weatherForecast.setForecastTime(parseDateTime(rootNode.get("dt")));
weatherForecast.setForecastTimeISO(rootNode.get("dt_txt").asText()); weatherForecast.setForecastTimeISO(rootNode.get("dt_txt").asText());
return weatherForecast; return weatherForecast;
} }
private WeatherState parseWeatherState(JsonNode weatherNode) {
if (weatherNode == null) {
return null;
}
final WeatherState weatherState = new WeatherState(
weatherNode.get("id").asInt(),
weatherNode.get("main").asText(),
weatherNode.get("description").asText()
);
weatherState.setIconId(weatherNode.get("icon").asText());
return weatherState;
}
private Temperature parseTemperature(JsonNode rootNode) {
final double tempValue = rootNode.get("temp").asDouble();
final Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit());
final JsonNode tempMaxNode = rootNode.get("temp_max");
if (tempMaxNode != null) {
temperature.setMaxTemperature(tempMaxNode.asDouble());
}
final JsonNode tempMinNode = rootNode.get("temp_min");
if (tempMinNode != null) {
temperature.setMinTemperature(tempMinNode.asDouble());
}
final JsonNode tempFeelsLike = rootNode.get("feels_like");
if (tempFeelsLike != null) {
temperature.setFeelsLike(tempFeelsLike.asDouble());
}
return temperature;
}
private AtmosphericPressure parsePressure(JsonNode rootNode) {
final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(rootNode.get("pressure").asDouble());
final JsonNode seaLevelNode = rootNode.get("sea_level");
final JsonNode groundLevelNode = rootNode.get("grnd_level");
if (seaLevelNode != null) {
atmosphericPressure.setSeaLevelValue(seaLevelNode.asDouble());
}
if (groundLevelNode != null) {
atmosphericPressure.setGroundLevelValue(groundLevelNode.asDouble());
}
return atmosphericPressure;
}
private Humidity parseHumidity(JsonNode rootNode) {
return Humidity.withValue((byte) (rootNode.get("humidity").asInt()));
}
private Wind parseWind(JsonNode root) {
final JsonNode windNode = root.get("wind");
double speed = windNode.get("speed").asDouble();
final Wind wind = Wind.withValue(speed, unitSystem.getWindUnit());
final JsonNode degNode = windNode.get("deg");
if (degNode != null) {
wind.setDegrees(degNode.asDouble());
}
return wind;
}
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 sunriseNode = rootNode.get("sunrise");
final JsonNode sunsetNode = rootNode.get("sunset");
if (sunriseNode != null) {
location.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asLong()), TimeZone.getDefault().toZoneId()));
}
if (sunsetNode != null) {
location.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asLong()), TimeZone.getDefault().toZoneId()));
}
final JsonNode coordNode = rootNode.get("coord");
if (coordNode != null) {
location.setCoordinate(parseCoordinate(coordNode));
}
final JsonNode populationNode = rootNode.get("population");
if (populationNode != null) {
location.setPopulation(populationNode.asLong());
}
return location;
}
private Coordinate parseCoordinate(JsonNode rootNode) {
final JsonNode latitudeNode = rootNode.get("lat");
final JsonNode longitudeNode = rootNode.get("lon");
if (latitudeNode != null && longitudeNode != null) {
return Coordinate.of(latitudeNode.asDouble(), longitudeNode.asDouble());
}
return null;
}
} }
@@ -0,0 +1,64 @@
/*
* 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.mapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
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.GeocodingRecord;
import com.github.prominence.openweathermap.api.model.geocoding.ZipCodeGeocodingRecord;
import java.util.List;
/**
* Official API response documentation: <a href="https://openweathermap.org/api/geocoding-api">https://openweathermap.org/api/geocoding-api</a>.
*/
public class GeocodingResponseMapper {
private static final ObjectMapper objectMapper = new ObjectMapper();
public GeocodingResponseMapper() {
final SimpleModule module = new SimpleModule();
module.addDeserializer(GeocodingRecord.class, new GeocodingRecordDeserializer());
module.addDeserializer(ZipCodeGeocodingRecord.class, new ZipCodeGeocodingDeserializer());
objectMapper.registerModule(module);
}
public List<GeocodingRecord> mapGeocodingResponse(String json) {
try {
return objectMapper.readValue(json, new TypeReference<List<GeocodingRecord>>() {});
} catch (JsonProcessingException e) {
throw new RuntimeException("Cannot parse ReverseGeocoding response.", e);
}
}
public ZipCodeGeocodingRecord mapZipCodeGeocodingResponse(String json) {
try {
return objectMapper.readValue(json, ZipCodeGeocodingRecord.class);
} catch (JsonProcessingException e) {
throw new RuntimeException("Cannot parse GeocodingInfo response.", e);
}
}
}
@@ -0,0 +1,143 @@
/*
* 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.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.*;
import com.github.prominence.openweathermap.api.deserializer.forecast.hourly.HourlyForecastLocationDeserializer;
import com.github.prominence.openweathermap.api.deserializer.forecast.hourly.HourlyForecastRainDeserializer;
import com.github.prominence.openweathermap.api.deserializer.forecast.hourly.HourlyForecastSnowDeserializer;
import com.github.prominence.openweathermap.api.enums.UnitSystem;
import com.github.prominence.openweathermap.api.model.*;
import com.github.prominence.openweathermap.api.model.forecast.hourly.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Official API response documentation: <a href="https://openweathermap.org/api/hourly-forecast#JSON">https://openweathermap.org/api/hourly-forecast#JSON</a>.
*/
public class HourlyForecastResponseMapper extends AbstractMapper {
/**
* Instantiates a new forecast response mapper.
*
* @param unitSystem the unit system
*/
public HourlyForecastResponseMapper(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 TemperatureDeserializer());
module.addDeserializer(AtmosphericPressure.class, new AtmosphericPressureDeserializer());
module.addDeserializer(Wind.class, new WindDeserializer());
module.addDeserializer(Humidity.class, new HumidityDeserializer());
module.addDeserializer(Clouds.class, new CloudsDeserializer());
module.addDeserializer(Rain.class, new HourlyForecastRainDeserializer());
module.addDeserializer(Snow.class, new HourlyForecastSnowDeserializer());
module.addDeserializer(Location.class, new HourlyForecastLocationDeserializer());
objectMapper.registerModule(module);
}
/**
* Maps forecast response into java object.
*
* @param json the json string
* @return the forecast
*/
public HourlyForecast mapToForecast(String json) {
HourlyForecast hourlyForecast;
try {
final JsonNode root = objectMapper.readTree(json);
hourlyForecast = mapToForecast(root);
} catch (IOException e) {
throw new RuntimeException("Cannot parse Forecast response");
}
return hourlyForecast;
}
private HourlyForecast mapToForecast(JsonNode root) throws IOException {
final HourlyForecast hourlyForecast = new HourlyForecast();
hourlyForecast.setLocation(objectMapper.readValue(objectMapper.treeAsTokens(root.get("city")), Location.class));
final List<WeatherForecast> forecasts = new ArrayList<>(root.get("cnt").asInt());
final JsonNode forecastListNode = root.get("list");
for (JsonNode forecastNode : forecastListNode) {
forecasts.add(parseWeatherForecast(forecastNode));
}
hourlyForecast.setWeatherForecasts(forecasts);
return hourlyForecast;
}
private WeatherForecast parseWeatherForecast(JsonNode rootNode) throws IOException {
final WeatherForecast weatherForecast = new WeatherForecast();
final JsonNode weatherArrayNode = rootNode.get("weather");
if (weatherArrayNode != null && weatherArrayNode.isArray()) {
List<WeatherState> weatherStateList = new ArrayList<>();
for (JsonNode weatherNode : weatherArrayNode) {
weatherStateList.add(objectMapper.readValue(objectMapper.treeAsTokens(weatherNode), WeatherState.class));
}
weatherForecast.setWeatherStates(weatherStateList);
}
final JsonNode mainNode = rootNode.get("main");
weatherForecast.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(mainNode), Temperature.class));
weatherForecast.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(mainNode), AtmosphericPressure.class));
weatherForecast.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(mainNode), Humidity.class));
weatherForecast.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("clouds")), Clouds.class));
weatherForecast.setWind(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("wind")), Wind.class));
if (rootNode.has("rain")) {
weatherForecast.setRain(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("rain")), Rain.class));
}
if (rootNode.has("snow")) {
weatherForecast.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("snow")), Snow.class));
}
final JsonNode sysNode = rootNode.get("sys");
if (sysNode != null) {
weatherForecast.setDayTime("d".equals(sysNode.get("pod").asText()) ? DayTime.DAY : DayTime.NIGHT);
}
if (rootNode.has("visibility")) {
weatherForecast.setAverageVisibilityInMetres(rootNode.get("visibility").asInt());
}
if (rootNode.has("pop")) {
weatherForecast.setProbabilityOfPrecipitation(rootNode.get("pop").asDouble());
}
weatherForecast.setForecastTime(parseDateTime(rootNode.get("dt")));
weatherForecast.setForecastTimeISO(rootNode.get("dt_txt").asText());
return weatherForecast;
}
}
@@ -22,41 +22,55 @@
package com.github.prominence.openweathermap.api.mapper; package com.github.prominence.openweathermap.api.mapper;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonNode; 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.*;
import com.github.prominence.openweathermap.api.deserializer.onecall.*;
import com.github.prominence.openweathermap.api.enums.UnitSystem; import com.github.prominence.openweathermap.api.enums.UnitSystem;
import com.github.prominence.openweathermap.api.model.Clouds; import com.github.prominence.openweathermap.api.model.*;
import com.github.prominence.openweathermap.api.model.Coordinate; import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure;
import com.github.prominence.openweathermap.api.model.Humidity; import com.github.prominence.openweathermap.api.model.onecall.Temperature;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.onecall.*; import com.github.prominence.openweathermap.api.model.onecall.*;
import com.github.prominence.openweathermap.api.model.onecall.current.*; import com.github.prominence.openweathermap.api.model.onecall.current.*;
import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeather; import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeather;
import com.github.prominence.openweathermap.api.model.onecall.historical.HourlyHistorical;
import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData; import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData;
import com.github.prominence.openweathermap.api.model.onecall.historical.HourlyHistorical;
import java.time.Instant; import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.TimeZone;
/** /**
* Object mapper for OneCall API response. * Official API response documentation:
* <ul>
* <li><a href="https://openweathermap.org/api/one-call-api#parameter">https://openweathermap.org/api/one-call-api#parameter</a></li>
* <li><a href="https://openweathermap.org/api/one-call-api#hist_parameter">https://openweathermap.org/api/one-call-api#hist_parameter</a></li>
* </ul>
*/ */
public class OneCallWeatherResponseMapper { public class OneCallWeatherResponseMapper extends AbstractMapper {
private final UnitSystem unitSystem;
/** /**
* Instantiates a new forecast response mapper. * Instantiates a new forecast response mapper.
* *
* @param unitSystem the unit system * @param unitSystem the unit system
*/ */
public OneCallWeatherResponseMapper(UnitSystem unitSystem) { public OneCallWeatherResponseMapper(UnitSystem unitSystem) {
this.unitSystem = unitSystem; objectMapper.setInjectableValues(new InjectableValues.Std().addValue("unitSystem", unitSystem != null ? unitSystem : UnitSystem.STANDARD));
final SimpleModule module = new SimpleModule();
module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
module.addDeserializer(AtmosphericPressure.class, new OneCallAtmosphericPressureDeserializer());
module.addDeserializer(Temperature.class, new OneCallTemperatureDeserializer());
module.addDeserializer(WeatherState.class, new WeatherStateDeserializer());
module.addDeserializer(Humidity.class, new HumidityDeserializer());
module.addDeserializer(Wind.class, new WindDeserializer());
module.addDeserializer(Clouds.class, new CloudsDeserializer());
module.addDeserializer(Rain.class, new OneCallRainDeserializer());
module.addDeserializer(Snow.class, new OneCallSnowDeserializer());
module.addDeserializer(DailyTemperature.class, new OneCallDailyTemperatureDeserializer());
module.addDeserializer(DailyRain.class, new OneCallDailyRainDeserializer());
module.addDeserializer(DailySnow.class, new OneCallDailySnowDeserializer());
module.addDeserializer(Alert.class, new AlertDeserializer());
objectMapper.registerModule(module);
} }
/** /**
@@ -66,13 +80,12 @@ public class OneCallWeatherResponseMapper {
* @return the current data object * @return the current data object
*/ */
public CurrentWeatherData mapToCurrent(String json) { public CurrentWeatherData mapToCurrent(String json) {
final ObjectMapper objectMapper = new ObjectMapper();
CurrentWeatherData currentData; CurrentWeatherData currentData;
try { try {
final JsonNode root = objectMapper.readTree(json); final JsonNode root = objectMapper.readTree(json);
currentData = mapToCurrent(root); currentData = mapToCurrent(root);
} catch (JsonProcessingException e) { } catch (IOException e) {
throw new RuntimeException("Cannot parse OneCall response"); throw new RuntimeException("Cannot parse OneCall response", e);
} }
return currentData; return currentData;
@@ -85,23 +98,23 @@ public class OneCallWeatherResponseMapper {
* @return the current data object * @return the current data object
*/ */
public HistoricalWeatherData mapToHistorical(String json) { public HistoricalWeatherData mapToHistorical(String json) {
final ObjectMapper objectMapper = new ObjectMapper();
HistoricalWeatherData historicalData; HistoricalWeatherData historicalData;
try { try {
final JsonNode root = objectMapper.readTree(json); final JsonNode root = objectMapper.readTree(json);
historicalData = mapToHistorical(root); historicalData = mapToHistorical(root);
} catch (JsonProcessingException e) { } catch (IOException e) {
throw new RuntimeException("Cannot parse OneCall response"); throw new RuntimeException("Cannot parse OneCall response");
} }
return historicalData; return historicalData;
} }
private CurrentWeatherData mapToCurrent(JsonNode rootNode) { private CurrentWeatherData mapToCurrent(JsonNode rootNode) throws IOException {
final CurrentWeatherData currentData = new CurrentWeatherData(); final CurrentWeatherData currentData = new CurrentWeatherData();
currentData.setCoordinate(Coordinate.of(rootNode.get("lat").asDouble(), rootNode.get("lon").asDouble())); currentData.setCoordinates(objectMapper.readValue(objectMapper.treeAsTokens(rootNode), Coordinates.class));
currentData.setTimezone(ZoneId.of(rootNode.get("timezone").asText())); currentData.setTimezone(parseZoneId(rootNode.get("timezone")));
currentData.setTimezoneOffset(ZoneOffset.ofTotalSeconds(rootNode.get("timezone_offset").asInt())); currentData.setTimezoneOffset(parseZoneOffset(rootNode.get("timezone_offset")));
currentData.setCurrent(parseCurrent(rootNode.get("current"))); currentData.setCurrent(parseCurrent(rootNode.get("current")));
currentData.setMinutelyList(parseMinutelyList(rootNode.get("minutely"))); currentData.setMinutelyList(parseMinutelyList(rootNode.get("minutely")));
currentData.setHourlyList(parseHourlyList(rootNode.get("hourly"))); currentData.setHourlyList(parseHourlyList(rootNode.get("hourly")));
@@ -111,28 +124,31 @@ public class OneCallWeatherResponseMapper {
return currentData; return currentData;
} }
private Current parseCurrent(JsonNode currentNode) { private Current parseCurrent(JsonNode currentNode) throws IOException {
if (currentNode == null) { if (currentNode == null) {
return null; return null;
} }
final Current current = new Current(); final Current current = new Current();
current.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); current.setForecastTime(parseDateTime(currentNode.get("dt")));
current.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("sunrise").asInt()), TimeZone.getDefault().toZoneId())); current.setSunriseTime(parseDateTime(currentNode.get("sunrise")));
current.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("sunset").asInt()), TimeZone.getDefault().toZoneId())); current.setSunsetTime(parseDateTime(currentNode.get("sunset")));
current.setWeatherStates(parseWeatherStates(currentNode.get("weather")));
current.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Temperature.class));
current.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), AtmosphericPressure.class));
current.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Humidity.class));
current.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Clouds.class));
current.setWeatherState(parseWeatherState(currentNode.get("weather").get(0)));
current.setTemperature(parseTemperature(currentNode));
current.setAtmosphericPressure(parsePressure(currentNode));
current.setHumidity(parseHumidity(currentNode));
current.setClouds(parseClouds(currentNode));
current.setUvIndex(currentNode.get("uvi").asDouble()); current.setUvIndex(currentNode.get("uvi").asDouble());
final JsonNode visibilityNode = currentNode.get("visibility"); final JsonNode visibilityNode = currentNode.get("visibility");
if (visibilityNode != null) { if (visibilityNode != null) {
current.setVisibilityInMetres(visibilityNode.asDouble()); current.setVisibilityInMetres(visibilityNode.asDouble());
} }
current.setWind(parseWind(currentNode));
current.setRain(parseRain(currentNode)); current.setWind(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Wind.class));
current.setSnow(parseSnow(currentNode)); current.setRain(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Rain.class));
current.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Snow.class));
return current; return current;
} }
@@ -144,7 +160,7 @@ public class OneCallWeatherResponseMapper {
final List<Minutely> minutelyList = new ArrayList<>(); final List<Minutely> minutelyList = new ArrayList<>();
for (final JsonNode minutelyNode : minutelyListNode) { for (final JsonNode minutelyNode : minutelyListNode) {
minutelyList.add(Minutely.withValue( minutelyList.add(Minutely.withValue(
LocalDateTime.ofInstant(Instant.ofEpochSecond(minutelyNode.get("dt").asInt()), TimeZone.getDefault().toZoneId()), parseDateTime(minutelyNode.get("dt")),
minutelyNode.get("precipitation").asDouble() minutelyNode.get("precipitation").asDouble()
)); ));
} }
@@ -152,20 +168,21 @@ public class OneCallWeatherResponseMapper {
return minutelyList; return minutelyList;
} }
private List<Hourly> parseHourlyList(JsonNode hourlyListNode) { private List<Hourly> parseHourlyList(JsonNode hourlyListNode) throws IOException {
if (hourlyListNode == null) { if (hourlyListNode == null) {
return null; return null;
} }
final List<Hourly> hourlyList = new ArrayList<>(); final List<Hourly> hourlyList = new ArrayList<>();
for (final JsonNode hourlyNode : hourlyListNode) { for (final JsonNode hourlyNode : hourlyListNode) {
final Hourly hourly = new Hourly(); final Hourly hourly = new Hourly();
hourly.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(hourlyNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); hourly.setForecastTime(parseDateTime(hourlyNode.get("dt")));
hourly.setWeatherState(parseWeatherState(hourlyNode.get("weather").get(0))); hourly.setWeatherStates(parseWeatherStates(hourlyNode.get("weather")));
hourly.setTemperature(parseTemperature(hourlyNode));
hourly.setAtmosphericPressure(parsePressure(hourlyNode)); hourly.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Temperature.class));
hourly.setHumidity(parseHumidity(hourlyNode)); hourly.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), AtmosphericPressure.class));
hourly.setClouds(parseClouds(hourlyNode)); hourly.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Humidity.class));
hourly.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Clouds.class));
final JsonNode uviNode = hourlyNode.get("uvi"); final JsonNode uviNode = hourlyNode.get("uvi");
if (uviNode != null) { if (uviNode != null) {
@@ -176,13 +193,13 @@ public class OneCallWeatherResponseMapper {
if (visibilityNode != null) { if (visibilityNode != null) {
hourly.setVisibilityInMetres(visibilityNode.asDouble()); hourly.setVisibilityInMetres(visibilityNode.asDouble());
} }
hourly.setWind(parseWind(hourlyNode)); hourly.setWind(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Wind.class));
final JsonNode popNode = hourlyNode.get("pop"); final JsonNode popNode = hourlyNode.get("pop");
if (popNode != null) { if (popNode != null) {
hourly.setProbabilityOfPrecipitation(popNode.asDouble()); hourly.setProbabilityOfPrecipitation(popNode.asDouble());
} }
hourly.setRain(parseRain(hourlyNode)); hourly.setRain(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Rain.class));
hourly.setSnow(parseSnow(hourlyNode)); hourly.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Snow.class));
hourlyList.add(hourly); hourlyList.add(hourly);
} }
@@ -190,40 +207,40 @@ public class OneCallWeatherResponseMapper {
return hourlyList; return hourlyList;
} }
private List<Daily> parseDailyList(JsonNode dailyListNode) { private List<Daily> parseDailyList(JsonNode dailyListNode) throws IOException {
if (dailyListNode == null) { if (dailyListNode == null) {
return null; return null;
} }
final List<Daily> dailyList = new ArrayList<>(); final List<Daily> dailyList = new ArrayList<>();
for (final JsonNode dailyNode : dailyListNode) { for (final JsonNode dailyNode : dailyListNode) {
final Daily daily = new Daily(); final Daily daily = new Daily();
daily.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(dailyNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); daily.setForecastTime(parseDateTime(dailyNode.get("dt")));
daily.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(dailyNode.get("sunrise").asInt()), TimeZone.getDefault().toZoneId())); daily.setSunriseTime(parseDateTime(dailyNode.get("sunrise")));
daily.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(dailyNode.get("sunset").asInt()), TimeZone.getDefault().toZoneId())); daily.setSunsetTime(parseDateTime(dailyNode.get("sunset")));
final JsonNode moonriseTimeNode = dailyNode.get("moonrise"); final JsonNode moonriseTimeNode = dailyNode.get("moonrise");
if (moonriseTimeNode != null) { if (moonriseTimeNode != null) {
daily.setMoonriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(moonriseTimeNode.asInt()), TimeZone.getDefault().toZoneId())); daily.setMoonriseTime(parseDateTime(moonriseTimeNode));
} }
final JsonNode moonsetTimeNode = dailyNode.get("moonset"); final JsonNode moonsetTimeNode = dailyNode.get("moonset");
if (moonsetTimeNode != null) { if (moonsetTimeNode != null) {
daily.setMoonsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(moonsetTimeNode.asInt()), TimeZone.getDefault().toZoneId())); daily.setMoonsetTime(parseDateTime(moonsetTimeNode));
} }
final JsonNode moonPhaseNode = dailyNode.get("moon_phase"); final JsonNode moonPhaseNode = dailyNode.get("moon_phase");
if (moonPhaseNode != null) { if (moonPhaseNode != null) {
daily.setMoonPhase(new MoonPhase(moonPhaseNode.asDouble())); daily.setMoonPhase(new MoonPhase(moonPhaseNode.asDouble()));
} }
daily.setSummary(parseSummary(dailyNode)); daily.setWeatherStates(parseWeatherStates(dailyNode.get("weather")));
daily.setWeatherState(parseWeatherState(dailyNode.get("weather").get(0)));
daily.setTemperature(parseDailyTemperature(dailyNode)); daily.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(dailyNode), DailyTemperature.class));
daily.setAtmosphericPressure(parsePressure(dailyNode)); daily.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(dailyNode), AtmosphericPressure.class));
daily.setHumidity(parseHumidity(dailyNode)); daily.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(dailyNode), Humidity.class));
daily.setWind(parseWind(dailyNode)); daily.setWind(objectMapper.readValue(objectMapper.treeAsTokens(dailyNode), Wind.class));
daily.setClouds(parseClouds(dailyNode)); daily.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(dailyNode), Clouds.class));
daily.setUvIndex(dailyNode.get("uvi").asDouble()); daily.setUvIndex(dailyNode.get("uvi").asDouble());
daily.setProbabilityOfPrecipitation(dailyNode.get("pop").asDouble()); daily.setProbabilityOfPrecipitation(dailyNode.get("pop").asDouble());
daily.setRain(parseDailyRain(dailyNode)); daily.setRain(objectMapper.readValue(objectMapper.treeAsTokens(dailyNode), DailyRain.class));
daily.setSnow(parseDailySnow(dailyNode)); daily.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(dailyNode), DailySnow.class));
dailyList.add(daily); dailyList.add(daily);
} }
@@ -231,221 +248,87 @@ public class OneCallWeatherResponseMapper {
return dailyList; return dailyList;
} }
private List<Alert> parseAlerts(JsonNode alertsNode) { private List<Alert> parseAlerts(JsonNode alertsNode) throws IOException {
if (alertsNode == null) { if (alertsNode == null || !alertsNode.isArray()) {
return null; return null;
} }
final List<Alert> alerts = new ArrayList<>(); final List<Alert> alerts = new ArrayList<>();
for (final JsonNode alertNode : alertsNode) { for (final JsonNode alertNode : alertsNode) {
Alert alert = new Alert(); alerts.add(objectMapper.readValue(objectMapper.treeAsTokens(alertNode), Alert.class));
alert.setSenderName(alertNode.get("sender_name").asText());
alert.setEventName(alertNode.get("event").asText());
alert.setStartTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(alertNode.get("start").asInt()), TimeZone.getDefault().toZoneId()));
alert.setEndTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(alertNode.get("end").asInt()), TimeZone.getDefault().toZoneId()));
alert.setDescription(alertNode.get("description").asText());
alerts.add(alert);
} }
return alerts; return alerts;
} }
private HistoricalWeatherData mapToHistorical(JsonNode rootNode) { private HistoricalWeatherData mapToHistorical(JsonNode rootNode) throws IOException {
final HistoricalWeatherData historicalData = new HistoricalWeatherData(); final HistoricalWeatherData historicalData = new HistoricalWeatherData();
historicalData.setCoordinate(Coordinate.of(rootNode.get("lat").asDouble(), rootNode.get("lon").asDouble())); historicalData.setCoordinates(Coordinates.of(rootNode.get("lat").asDouble(), rootNode.get("lon").asDouble()));
historicalData.setTimezone(ZoneId.of(rootNode.get("timezone").asText())); historicalData.setTimezone(parseZoneId(rootNode.get("timezone")));
historicalData.setTimezoneOffset(ZoneOffset.ofTotalSeconds(rootNode.get("timezone_offset").asInt())); historicalData.setTimezoneOffset(parseZoneOffset(rootNode.get("timezone_offset")));
historicalData.setHistoricalWeather(parseHistoricalWeather(rootNode.get("current"))); historicalData.setHistoricalWeather(parseHistoricalWeather(rootNode.get("current")));
historicalData.setHourlyList(parseHourlyHistoricalList(rootNode.get("hourly"))); historicalData.setHourlyList(parseHourlyHistoricalList(rootNode.get("hourly")));
return historicalData; return historicalData;
} }
private HistoricalWeather parseHistoricalWeather(JsonNode currentNode) { private HistoricalWeather parseHistoricalWeather(JsonNode currentNode) throws IOException {
if (currentNode == null) { if (currentNode == null) {
return null; return null;
} }
final HistoricalWeather historicalWeather = new HistoricalWeather(); final HistoricalWeather historicalWeather = new HistoricalWeather();
historicalWeather.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); historicalWeather.setForecastTime(parseDateTime(currentNode.get("dt")));
historicalWeather.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("sunrise").asInt()), TimeZone.getDefault().toZoneId())); historicalWeather.setSunriseTime(parseDateTime(currentNode.get("sunrise")));
historicalWeather.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("sunset").asInt()), TimeZone.getDefault().toZoneId())); historicalWeather.setSunsetTime(parseDateTime(currentNode.get("sunset")));
final JsonNode weatherListNode = currentNode.get("weather"); historicalWeather.setWeatherStates(parseWeatherStates(currentNode.get("weather")));
if (weatherListNode != null) {
historicalWeather.setWeatherState(parseWeatherState(weatherListNode.get(0))); historicalWeather.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Temperature.class));
historicalWeather.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), AtmosphericPressure.class));
historicalWeather.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Humidity.class));
historicalWeather.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Clouds.class));
final JsonNode uviNode = currentNode.get("uvi");
if (uviNode != null) {
historicalWeather.setUvIndex(uviNode.asDouble());
} }
historicalWeather.setTemperature(parseTemperature(currentNode));
historicalWeather.setAtmosphericPressure(parsePressure(currentNode)); final JsonNode visibilityNode = currentNode.get("visibility");
historicalWeather.setHumidity(parseHumidity(currentNode)); if (visibilityNode != null) {
historicalWeather.setClouds(parseClouds(currentNode)); historicalWeather.setVisibilityInMetres(visibilityNode.asDouble());
historicalWeather.setUvIndex(currentNode.get("uvi").asDouble());
final JsonNode visibilityMode = currentNode.get("visibility");
if (visibilityMode != null) {
historicalWeather.setVisibilityInMetres(visibilityMode.asDouble());
} }
historicalWeather.setWind(parseWind(currentNode)); historicalWeather.setWind(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Wind.class));
historicalWeather.setRain(parseRain(currentNode)); historicalWeather.setRain(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Rain.class));
historicalWeather.setSnow(parseSnow(currentNode)); historicalWeather.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(currentNode), Snow.class));
return historicalWeather; return historicalWeather;
} }
private List<HourlyHistorical> parseHourlyHistoricalList(JsonNode hourlyListNode) { private List<HourlyHistorical> parseHourlyHistoricalList(JsonNode hourlyListNode) throws IOException {
if (hourlyListNode == null) { if (hourlyListNode == null) {
return null; return null;
} }
final List<HourlyHistorical> hourlyList = new ArrayList<>(); final List<HourlyHistorical> hourlyList = new ArrayList<>();
for (final JsonNode hourlyNode : hourlyListNode) { for (final JsonNode hourlyNode : hourlyListNode) {
final HourlyHistorical hourly = new HourlyHistorical(); final HourlyHistorical hourly = new HourlyHistorical();
hourly.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(hourlyNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); hourly.setForecastTime(parseDateTime(hourlyNode.get("dt")));
hourly.setWeatherState(parseWeatherState(hourlyNode.get("weather").get(0))); hourly.setWeatherStates(parseWeatherStates(hourlyNode.get("weather")));
hourly.setTemperature(parseTemperature(hourlyNode));
hourly.setAtmosphericPressure(parsePressure(hourlyNode)); hourly.setTemperature(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Temperature.class));
hourly.setHumidity(parseHumidity(hourlyNode)); hourly.setAtmosphericPressure(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), AtmosphericPressure.class));
hourly.setClouds(parseClouds(hourlyNode)); hourly.setHumidity(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Humidity.class));
hourly.setClouds(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Clouds.class));
final JsonNode visibilityNode = hourlyNode.get("visibility"); final JsonNode visibilityNode = hourlyNode.get("visibility");
if (visibilityNode != null) { if (visibilityNode != null) {
hourly.setVisibilityInMetres(visibilityNode.asDouble()); hourly.setVisibilityInMetres(visibilityNode.asDouble());
} }
hourly.setWind(parseWind(hourlyNode)); hourly.setWind(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Wind.class));
hourly.setRain(parseRain(hourlyNode)); hourly.setRain(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Rain.class));
hourly.setSnow(parseSnow(hourlyNode)); hourly.setSnow(objectMapper.readValue(objectMapper.treeAsTokens(hourlyNode), Snow.class));
hourlyList.add(hourly); hourlyList.add(hourly);
} }
return hourlyList; return hourlyList;
} }
private WeatherState parseWeatherState(JsonNode weatherNode) {
if (weatherNode == null) {
return null;
}
final WeatherState weatherState = new WeatherState(
weatherNode.get("id").asInt(),
weatherNode.get("main").asText(),
weatherNode.get("description").asText()
);
weatherState.setIconId(weatherNode.get("icon").asText());
return weatherState;
}
private Temperature parseTemperature(JsonNode rootNode) {
final double tempValue = rootNode.get("temp").asDouble();
final Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit());
final JsonNode tempFeelsLike = rootNode.get("feels_like");
if (tempFeelsLike != null) {
temperature.setFeelsLike(tempFeelsLike.asDouble());
}
final JsonNode dewPoint = rootNode.get("dew_point");
if (dewPoint != null) {
temperature.setDewPoint(dewPoint.asDouble());
}
return temperature;
}
private DailyTemperature parseDailyTemperature(JsonNode dailyNode) {
final DailyTemperature temperature = new DailyTemperature();
final JsonNode tempNode = dailyNode.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 = dailyNode.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 rootNode) {
final JsonNode windSpeedNode = rootNode.get("wind_speed");
if (windSpeedNode == null) {
return null;
}
final Wind wind = Wind.withValue(windSpeedNode.asDouble(), unitSystem.getWindUnit());
final JsonNode degNode = rootNode.get("wind_deg");
if (degNode != null) {
wind.setDegrees(degNode.asDouble());
}
final JsonNode gustNode = rootNode.get("wind_gust");
if (gustNode != null) {
wind.setGust(gustNode.asDouble());
}
return wind;
}
private Rain parseRain(JsonNode root) {
final JsonNode rainNode = root.get("rain");
if (rainNode != null) {
final JsonNode oneHourNode = rainNode.get("1h");
if (oneHourNode != null) {
return Rain.withOneHourLevelValue(oneHourNode.asDouble());
}
}
return null;
}
private DailyRain parseDailyRain(JsonNode dailyNode) {
final JsonNode valueNode = dailyNode.get("rain");
if (valueNode != null) {
return DailyRain.withValue(valueNode.asDouble());
}
return null;
}
private Snow parseSnow(JsonNode root) {
final JsonNode snowNode = root.get("snow");
if (snowNode != null) {
final JsonNode OneHourNode = snowNode.get("1h");
if (OneHourNode != null) {
return Snow.withOneHourLevelValue(OneHourNode.asDouble());
}
}
return null;
}
private DailySnow parseDailySnow(JsonNode dailyNode) {
final JsonNode valueNode = dailyNode.get("snow");
if (valueNode != null) {
return DailySnow.withValue(valueNode.asDouble());
}
return null;
}
private Clouds parseClouds(JsonNode rootNode) {
final JsonNode cloudsNode = rootNode.get("clouds");
if (cloudsNode != null) {
return Clouds.withValue((byte) cloudsNode.asInt());
}
return null;
}
private String parseSummary(JsonNode dailyNode) {
final JsonNode summaryNode = dailyNode.get("summary");
if(summaryNode != null) {
return summaryNode.asText();
}
return null;
}
} }
@@ -0,0 +1,72 @@
package com.github.prominence.openweathermap.api.mapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.github.prominence.openweathermap.api.deserializer.roadrisk.RoadRiskAlertDeserializer;
import com.github.prominence.openweathermap.api.deserializer.roadrisk.RoadRiskRoadDetailsDeserializer;
import com.github.prominence.openweathermap.api.deserializer.roadrisk.RoadRiskWeatherDeserializer;
import com.github.prominence.openweathermap.api.model.Coordinates;
import com.github.prominence.openweathermap.api.model.roadrisk.Alert;
import com.github.prominence.openweathermap.api.model.roadrisk.RoadDetails;
import com.github.prominence.openweathermap.api.model.roadrisk.RoadRiskRecord;
import com.github.prominence.openweathermap.api.model.roadrisk.Weather;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class RoadRiskResponseMapper extends AbstractMapper {
public RoadRiskResponseMapper() {
final SimpleModule module = new SimpleModule();
module.addDeserializer(Weather.class, new RoadRiskWeatherDeserializer());
module.addDeserializer(RoadDetails.class, new RoadRiskRoadDetailsDeserializer());
module.addDeserializer(Alert.class, new RoadRiskAlertDeserializer());
objectMapper.registerModule(module);
}
public List<RoadRiskRecord> mapToObjects(String jsonResponse) {
List<RoadRiskRecord> roadRiskRecords;
try {
final JsonNode root = objectMapper.readTree(jsonResponse);
roadRiskRecords = mapToObjects(root);
} catch (IOException e) {
throw new RuntimeException("Cannot parse SolarRadiation response", e);
}
return roadRiskRecords;
}
private List<RoadRiskRecord> mapToObjects(JsonNode rootNode) throws IOException {
List<RoadRiskRecord> roadRiskRecords = new ArrayList<>();
if (rootNode.isArray()) {
for (JsonNode recordNode : rootNode) {
RoadRiskRecord roadRiskRecord = new RoadRiskRecord();
roadRiskRecord.setForecastTime(parseDateTime(recordNode.get("dt")));
final JsonNode coordNode = recordNode.get("coord");
roadRiskRecord.setCoordinates(Coordinates.of(coordNode.get(0).asDouble(), coordNode.get(1).asDouble()));
roadRiskRecord.setWeather(objectMapper.readValue(objectMapper.treeAsTokens(recordNode.get("weather")), Weather.class));
if (recordNode.has("road")) {
roadRiskRecord.setRoadDetails(objectMapper.readValue(objectMapper.treeAsTokens(recordNode.get("road")), RoadDetails.class));
}
final JsonNode alertsNode = recordNode.get("alerts");
if (alertsNode != null && alertsNode.isArray()) {
List<Alert> alerts = new ArrayList<>();
for (JsonNode alertNode : alertsNode) {
alerts.add(objectMapper.readValue(objectMapper.treeAsTokens(alertNode), Alert.class));
}
roadRiskRecord.setAlerts(alerts);
}
roadRiskRecords.add(roadRiskRecord);
}
}
return roadRiskRecords;
}
}
@@ -0,0 +1,49 @@
package com.github.prominence.openweathermap.api.mapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.github.prominence.openweathermap.api.deserializer.CoordinatesDeserializer;
import com.github.prominence.openweathermap.api.deserializer.radiation.SolarRadiationRecordDeserializer;
import com.github.prominence.openweathermap.api.model.Coordinates;
import com.github.prominence.openweathermap.api.model.radiation.SolarRadiation;
import com.github.prominence.openweathermap.api.model.radiation.SolarRadiationRecord;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class SolarRadiationResponseMapper extends AbstractMapper {
public SolarRadiationResponseMapper() {
final SimpleModule module = new SimpleModule();
module.addDeserializer(SolarRadiationRecord.class, new SolarRadiationRecordDeserializer());
module.addDeserializer(Coordinates.class, new CoordinatesDeserializer());
objectMapper.registerModule(module);
}
public SolarRadiation mapToObject(String jsonResponse) {
SolarRadiation solarRadiation;
try {
final JsonNode root = objectMapper.readTree(jsonResponse);
solarRadiation = mapToObject(root);
} catch (IOException e) {
throw new RuntimeException("Cannot parse SolarRadiation response", e);
}
return solarRadiation;
}
private SolarRadiation mapToObject(JsonNode rootNode) throws IOException {
final SolarRadiation solarRadiation = new SolarRadiation();
solarRadiation.setCoordinates(objectMapper.readValue(objectMapper.treeAsTokens(rootNode.get("coord")), Coordinates.class));
final JsonNode listRecordsNode = rootNode.get("list");
List<SolarRadiationRecord> radiationRecords = new ArrayList<>();
for (JsonNode recordNode : listRecordsNode) {
radiationRecords.add(objectMapper.readValue(objectMapper.treeAsTokens(recordNode), SolarRadiationRecord.class));
}
solarRadiation.setSolarRadiationRecords(radiationRecords);
return solarRadiation;
}
}
@@ -48,6 +48,7 @@ public class AtmosphericPressure {
/** /**
* Static method for {@link AtmosphericPressure} creation with value checking. * Static method for {@link AtmosphericPressure} creation with value checking.
*
* @param value atmospheric pressure value. * @param value atmospheric pressure value.
* @return instantiated {@link AtmosphericPressure} object. * @return instantiated {@link AtmosphericPressure} object.
*/ */
@@ -45,6 +45,7 @@ public class Clouds {
/** /**
* Static method for {@link Clouds} creation with value checking. * Static method for {@link Clouds} creation with value checking.
*
* @param value clouds percentage value. * @param value clouds percentage value.
* @return instantiated {@link Clouds} object. * @return instantiated {@link Clouds} object.
*/ */
@@ -22,34 +22,40 @@
package com.github.prominence.openweathermap.api.model; package com.github.prominence.openweathermap.api.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects; import java.util.Objects;
/** /**
* Represents some location by its latitude and longitude. * Represents some location by its latitude and longitude.
*/ */
public class Coordinate { public class Coordinates {
@JsonProperty("lat")
private double latitude; private double latitude;
@JsonProperty("lon")
private double longitude; private double longitude;
private Coordinate() { private Coordinates() {
} }
/** /**
* Method for {@link Coordinate} creation with correctness check. * Method for {@link Coordinates} creation with correctness check.
*
* @param latitude latitude * @param latitude latitude
* @param longitude longitude * @param longitude longitude
* @return coordinate object. * @return coordinate object.
*/ */
public static Coordinate of(double latitude, double longitude) { public static Coordinates of(double latitude, double longitude) {
final Coordinate coordinate = new Coordinate(); final Coordinates coordinates = new Coordinates();
coordinate.setLatitude(latitude); coordinates.setLatitude(latitude);
coordinate.setLongitude(longitude); coordinates.setLongitude(longitude);
return coordinate; return coordinates;
} }
/** /**
* Sets latitude with checks. * Sets latitude with checks.
*
* @param latitude latitude value * @param latitude latitude value
*/ */
public void setLatitude(double latitude) { public void setLatitude(double latitude) {
@@ -61,6 +67,7 @@ public class Coordinate {
/** /**
* Sets longitude with checks. * Sets longitude with checks.
*
* @param longitude longitude value * @param longitude longitude value
*/ */
public void setLongitude(double longitude) { public void setLongitude(double longitude) {
@@ -72,6 +79,7 @@ public class Coordinate {
/** /**
* Returns latitude. * Returns latitude.
*
* @return latitude * @return latitude
*/ */
public double getLatitude() { public double getLatitude() {
@@ -80,6 +88,7 @@ public class Coordinate {
/** /**
* Returns longitude. * Returns longitude.
*
* @return longitude * @return longitude
*/ */
public double getLongitude() { public double getLongitude() {
@@ -89,8 +98,8 @@ public class Coordinate {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof Coordinate)) return false; if (!(o instanceof Coordinates)) return false;
Coordinate that = (Coordinate) o; Coordinates that = (Coordinates) o;
return Double.compare(that.latitude, latitude) == 0 && return Double.compare(that.latitude, latitude) == 0 &&
Double.compare(that.longitude, longitude) == 0; Double.compare(that.longitude, longitude) == 0;
} }
@@ -27,13 +27,13 @@ import java.util.Objects;
/** /**
* Represents coordinate rectangle by its bottom-left and top-right coordinates. * Represents coordinate rectangle by its bottom-left and top-right coordinates.
*/ */
public class CoordinateRectangle { public class CoordinatesRectangle {
private final double longitudeLeft; private final double longitudeLeft;
private final double latitudeBottom; private final double latitudeBottom;
private final double longitudeRight; private final double longitudeRight;
private final double latitudeTop; private final double latitudeTop;
private CoordinateRectangle(double longitudeLeft, double latitudeBottom, double longitudeRight, double latitudeTop) { private CoordinatesRectangle(double longitudeLeft, double latitudeBottom, double longitudeRight, double latitudeTop) {
this.longitudeLeft = longitudeLeft; this.longitudeLeft = longitudeLeft;
this.latitudeBottom = latitudeBottom; this.latitudeBottom = latitudeBottom;
this.longitudeRight = longitudeRight; this.longitudeRight = longitudeRight;
@@ -41,21 +41,21 @@ public class CoordinateRectangle {
} }
/** /**
* Method for {@link CoordinateRectangle} creation with correctness check. * Method for {@link CoordinatesRectangle} creation with correctness check.
* @param longitudeLeft left longitude * @param longitudeLeft left longitude
* @param latitudeBottom bottom latitude * @param latitudeBottom bottom latitude
* @param longitudeRight right longitude * @param longitudeRight right longitude
* @param latitudeTop tip latitude * @param latitudeTop tip latitude
* @return coordinate rectangle object. * @return coordinate rectangle object.
*/ */
public static CoordinateRectangle withValues(double longitudeLeft, double latitudeBottom, double longitudeRight, double latitudeTop) { public static CoordinatesRectangle withValues(double longitudeLeft, double latitudeBottom, double longitudeRight, double latitudeTop) {
if (latitudeBottom < -90 || latitudeTop < -90 || latitudeBottom > 90 || latitudeTop > 90) { if (latitudeBottom < -90 || latitudeTop < -90 || latitudeBottom > 90 || latitudeTop > 90) {
throw new IllegalArgumentException("Latitude value must be in the next range: [-90.0; 90.0]."); throw new IllegalArgumentException("Latitude value must be in the next range: [-90.0; 90.0].");
} }
if (longitudeLeft < -180 || longitudeRight < -180 || longitudeLeft > 180 || longitudeRight > 180) { if (longitudeLeft < -180 || longitudeRight < -180 || longitudeLeft > 180 || longitudeRight > 180) {
throw new IllegalArgumentException("Longitude value must be in the next range: [-180.0; 180.0]."); throw new IllegalArgumentException("Longitude value must be in the next range: [-180.0; 180.0].");
} }
return new CoordinateRectangle(longitudeLeft, latitudeBottom, longitudeRight, latitudeTop); return new CoordinatesRectangle(longitudeLeft, latitudeBottom, longitudeRight, latitudeTop);
} }
/** /**
@@ -101,8 +101,8 @@ public class CoordinateRectangle {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof CoordinateRectangle)) return false; if (!(o instanceof CoordinatesRectangle)) return false;
CoordinateRectangle rectangle = (CoordinateRectangle) o; CoordinatesRectangle rectangle = (CoordinatesRectangle) o;
return Double.compare(rectangle.longitudeLeft, longitudeLeft) == 0 && return Double.compare(rectangle.longitudeLeft, longitudeLeft) == 0 &&
Double.compare(rectangle.latitudeBottom, latitudeBottom) == 0 && Double.compare(rectangle.latitudeBottom, latitudeBottom) == 0 &&
Double.compare(rectangle.longitudeRight, longitudeRight) == 0 && Double.compare(rectangle.longitudeRight, longitudeRight) == 0 &&
@@ -187,14 +187,14 @@ public class CoordinateRectangle {
} }
/** /**
* Builds {@link CoordinateRectangle} object with correctness check. * Builds {@link CoordinatesRectangle} object with correctness check.
* @return {@link CoordinateRectangle} built object. * @return {@link CoordinatesRectangle} built object.
*/ */
public CoordinateRectangle build() { public CoordinatesRectangle build() {
if (longitudeLeft == null || latitudeBottom == null || longitudeRight == null || latitudeTop == null) { if (longitudeLeft == null || latitudeBottom == null || longitudeRight == null || latitudeTop == null) {
throw new IllegalStateException("Not all fields were set."); throw new IllegalStateException("Not all fields were set.");
} }
return new CoordinateRectangle(longitudeLeft, latitudeBottom, longitudeRight, latitudeTop); return new CoordinatesRectangle(longitudeLeft, latitudeBottom, longitudeRight, latitudeTop);
} }
} }
} }
@@ -44,13 +44,16 @@ public class Humidity {
} }
/** /**
* Creates {@link Humidity} object with safeguard to have min 0 and max 100 as value * Creates {@link Humidity} object with correctness check.
*
* @param value humidity * @param value humidity
* @return created {@link Humidity} object * @return created {@link Humidity} object
*/ */
public static Humidity withValue(byte value) { public static Humidity withValue(byte value) {
int v = Math.max(0, Math.min(100, value)); if (value < 0 || value > 100) {
return new Humidity((byte) v); throw new IllegalArgumentException("Humidity value must be in [0, 100] range.");
}
return new Humidity(value);
} }
/** /**
@@ -66,10 +69,13 @@ public class Humidity {
* Sets humidity percentage value. * Sets humidity percentage value.
* *
* @param value new humidity value. * @param value new humidity value.
* Rounds to 0 or 100 if provided value isn't in allowed range. * @throws IllegalArgumentException in case if provided value isn't in allowed range.
*/ */
public void setValue(int value) { public void setValue(int value) {
this.value = Math.max(0, Math.min(100, value)); if (value < 0 || value > 100) {
throw new IllegalArgumentException("Humidity value must be in [0, 100] range.");
}
this.value = value;
} }
/** /**
@@ -41,6 +41,7 @@ public class Temperature {
/** /**
* Creates {@link Temperature} object with correctness check. * Creates {@link Temperature} object with correctness check.
*
* @param value temperature value * @param value temperature value
* @param unit temperature unit * @param unit temperature unit
* @return temperature object * @return temperature object
@@ -54,6 +55,7 @@ public class Temperature {
/** /**
* Returns temperature value. * Returns temperature value.
*
* @return value * @return value
*/ */
public double getValue() { public double getValue() {
@@ -62,6 +64,7 @@ public class Temperature {
/** /**
* Sets temperature value. * Sets temperature value.
*
* @param value temperature * @param value temperature
*/ */
public void setValue(double value) { public void setValue(double value) {
@@ -70,6 +73,7 @@ public class Temperature {
/** /**
* Returns maximal temperature value. * Returns maximal temperature value.
*
* @return maximal temperature value * @return maximal temperature value
*/ */
public Double getMaxTemperature() { public Double getMaxTemperature() {
@@ -78,6 +82,7 @@ public class Temperature {
/** /**
* Sets maximal temperature value. * Sets maximal temperature value.
*
* @param maxTemperature maximal temperature * @param maxTemperature maximal temperature
*/ */
public void setMaxTemperature(Double maxTemperature) { public void setMaxTemperature(Double maxTemperature) {
@@ -86,6 +91,7 @@ public class Temperature {
/** /**
* Returns minimal temperature value. * Returns minimal temperature value.
*
* @return minimal temperature value * @return minimal temperature value
*/ */
public Double getMinTemperature() { public Double getMinTemperature() {
@@ -94,6 +100,7 @@ public class Temperature {
/** /**
* Sets minimal temperature value. * Sets minimal temperature value.
*
* @param minTemperature minimal temperature * @param minTemperature minimal temperature
*/ */
public void setMinTemperature(Double minTemperature) { public void setMinTemperature(Double minTemperature) {
@@ -102,6 +109,7 @@ public class Temperature {
/** /**
* Returns 'feels like' temperature value. * Returns 'feels like' temperature value.
*
* @return 'feels like' temperature value * @return 'feels like' temperature value
*/ */
public Double getFeelsLike() { public Double getFeelsLike() {
@@ -110,6 +118,7 @@ public class Temperature {
/** /**
* Sets 'feels like' temperature value. * Sets 'feels like' temperature value.
*
* @param feelsLike 'feels like' temperature * @param feelsLike 'feels like' temperature
*/ */
public void setFeelsLike(Double feelsLike) { public void setFeelsLike(Double feelsLike) {
@@ -118,6 +127,7 @@ public class Temperature {
/** /**
* Returns temperature unit. * Returns temperature unit.
*
* @return unit * @return unit
*/ */
public String getUnit() { public String getUnit() {
@@ -126,6 +136,7 @@ public class Temperature {
/** /**
* Sets temperature unit with correctness check. * Sets temperature unit with correctness check.
*
* @param unit temperature unit * @param unit temperature unit
*/ */
public void setUnit(String unit) { public void setUnit(String unit) {
@@ -138,8 +149,7 @@ public class Temperature {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof Temperature)) return false; if (!(o instanceof Temperature that)) return false;
Temperature that = (Temperature) o;
return Double.compare(that.value, value) == 0 && return Double.compare(that.value, value) == 0 &&
Objects.equals(maxTemperature, that.maxTemperature) && Objects.equals(maxTemperature, that.maxTemperature) &&
Objects.equals(minTemperature, that.minTemperature) && Objects.equals(minTemperature, that.minTemperature) &&
@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Alexey Zinchenko * Copyright (c) 2022 Alexey Zinchenko
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -20,7 +20,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
package com.github.prominence.openweathermap.api.model.weather; package com.github.prominence.openweathermap.api.model;
import java.util.Objects; import java.util.Objects;
@@ -46,6 +46,7 @@ public class Wind {
/** /**
* Creates {@link Wind} object with correctness check. * Creates {@link Wind} object with correctness check.
*
* @param speed the speed * @param speed the speed
* @param unit the unitSystem * @param unit the unitSystem
* @return wind object * @return wind object
@@ -83,6 +84,7 @@ public class Wind {
/** /**
* Gets gust value. * Gets gust value.
*
* @return the gust * @return the gust
*/ */
public Double getGust() { public Double getGust() {
@@ -91,6 +93,7 @@ public class Wind {
/** /**
* Sets gust value. * Sets gust value.
*
* @param gust the gust. * @param gust the gust.
*/ */
public void setGust(double gust) { public void setGust(double gust) {
@@ -24,7 +24,7 @@
package com.github.prominence.openweathermap.api.model.air.pollution; package com.github.prominence.openweathermap.api.model.air.pollution;
import com.github.prominence.openweathermap.api.model.Coordinate; import com.github.prominence.openweathermap.api.model.Coordinates;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -33,7 +33,7 @@ import java.util.Objects;
* The type Air pollution. * The type Air pollution.
*/ */
public class AirPollutionDetails { public class AirPollutionDetails {
private Coordinate coordinate; private Coordinates coordinates;
private List<AirPollutionRecord> airPollutionRecords; private List<AirPollutionRecord> airPollutionRecords;
/** /**
@@ -41,17 +41,17 @@ public class AirPollutionDetails {
* *
* @return the coordinate * @return the coordinate
*/ */
public Coordinate getCoordinate() { public Coordinates getCoordinates() {
return coordinate; return coordinates;
} }
/** /**
* Sets coordinate. * Sets coordinate.
* *
* @param coordinate the coordinate * @param coordinates the coordinate
*/ */
public void setCoordinate(Coordinate coordinate) { public void setCoordinates(Coordinates coordinates) {
this.coordinate = coordinate; this.coordinates = coordinates;
} }
/** /**
@@ -77,11 +77,11 @@ public class AirPollutionDetails {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
AirPollutionDetails that = (AirPollutionDetails) o; AirPollutionDetails that = (AirPollutionDetails) o;
return Objects.equals(coordinate, that.coordinate) && Objects.equals(airPollutionRecords, that.airPollutionRecords); return Objects.equals(coordinates, that.coordinates) && Objects.equals(airPollutionRecords, that.airPollutionRecords);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(coordinate, airPollutionRecords); return Objects.hash(coordinates, airPollutionRecords);
} }
} }
@@ -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();
}
}
@@ -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.";
}
}

Some files were not shown because too many files have changed in this diff Show More