Compare commits

..

46 Commits

Author SHA1 Message Date
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
226 changed files with 11463 additions and 3144 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.
+56 -13
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,13 @@ 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 30 days
* Solar Radiation API
Other: Other:
* Request timeout settings * Request timeout settings
@@ -14,29 +21,62 @@ 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 * Climatic Forecast 30 days
* Hourly Forecast 4 days * Bulk Downloading
* probably others... * Solar Radiation API
* Global Weather Alerts / Push notifications
* Road Risk API
### Maven coordinates: ### Maven coordinates:
```xml ```xml
<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
implementation '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()
}
}
...
}
``` ```
### Documentation ### Documentation
@@ -49,14 +89,17 @@ implementation 'com.github.prominence:openweathermap-api:2.4.0'
* [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)
### 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:
+49 -27
View File
@@ -1,9 +1,12 @@
### 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
* Air Pollution * Air Pollution
* Geocoding API
Other: Other:
@@ -13,16 +16,48 @@ Other:
```xml ```xml
<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 +163,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 +222,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 +231,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 +248,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 +345,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 +433,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 +496,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 +582,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.0</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'
@@ -26,12 +26,16 @@ import com.github.prominence.openweathermap.api.annotation.SubscriptionAvailabil
import com.github.prominence.openweathermap.api.conf.TimeoutSettings; import com.github.prominence.openweathermap.api.conf.TimeoutSettings;
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.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.
@@ -67,12 +71,12 @@ public class OpenWeatherMapClient {
} }
/** /**
* 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(new RequestSettings(apiKey, timeoutSettings));
} }
/** /**
@@ -81,27 +85,44 @@ 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(new RequestSettings(apiKey, timeoutSettings));
} }
/** /**
* 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(new RequestSettings(apiKey, timeoutSettings));
* 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(new RequestSettings(apiKey, timeoutSettings));
}
/**
* 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(new RequestSettings(apiKey, timeoutSettings));
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(new RequestSettings(apiKey, timeoutSettings));
} }
/** /**
@@ -113,4 +134,9 @@ public class OpenWeatherMapClient {
public AirPollutionRequester airPollution() { public AirPollutionRequester airPollution() {
return new AirPollutionRequester(new RequestSettings(apiKey, timeoutSettings)); return new AirPollutionRequester(new RequestSettings(apiKey, timeoutSettings));
} }
@SubscriptionAvailability(plans = ALL)
public GeocodingRequester geocoding() {
return new GeocodingRequester(new RequestSettings(apiKey, timeoutSettings));
}
} }
@@ -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,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;
}
}
@@ -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></li><a href="https://openweathermap.org/api/one-call-api#parameter">https://openweathermap.org/api/one-call-api#parameter</a></li>
* <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) {
Rain.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,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,11 +48,12 @@ 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.
*/ */
public static AtmosphericPressure withValue(double value) { public static AtmosphericPressure withValue(double value) {
if (value < 0) { if (value < 0) {
throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range."); throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range.");
} }
return new AtmosphericPressure(value); return new AtmosphericPressure(value);
@@ -74,7 +75,7 @@ public class AtmosphericPressure {
* @throws IllegalArgumentException in case if provided value isn't in allowed range. * @throws IllegalArgumentException in case if provided value isn't in allowed range.
*/ */
public void setValue(double value) { public void setValue(double value) {
if (value < 0) { if (value < 0) {
throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range."); throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range.");
} }
this.value = value; this.value = value;
@@ -96,7 +97,7 @@ public class AtmosphericPressure {
* @throws IllegalArgumentException in case if provided value isn't in allowed range. * @throws IllegalArgumentException in case if provided value isn't in allowed range.
*/ */
public void setSeaLevelValue(double seaLevelValue) { public void setSeaLevelValue(double seaLevelValue) {
if (seaLevelValue < 0) { if (seaLevelValue < 0) {
throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range."); throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range.");
} }
this.seaLevelValue = seaLevelValue; this.seaLevelValue = seaLevelValue;
@@ -118,7 +119,7 @@ public class AtmosphericPressure {
* @throws IllegalArgumentException in case if provided value isn't in allowed range. * @throws IllegalArgumentException in case if provided value isn't in allowed range.
*/ */
public void setGroundLevelValue(double groundLevelValue) { public void setGroundLevelValue(double groundLevelValue) {
if (groundLevelValue < 0) { if (groundLevelValue < 0) {
throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range."); throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range.");
} }
this.groundLevelValue = groundLevelValue; this.groundLevelValue = groundLevelValue;
@@ -45,11 +45,12 @@ 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.
*/ */
public static Clouds withValue(byte value) { public static Clouds withValue(byte value) {
if (value < 0 || value > 100) { if (value < 0 || value > 100) {
throw new IllegalArgumentException("Cloudiness value must be in [0, 100] range."); throw new IllegalArgumentException("Cloudiness value must be in [0, 100] range.");
} }
return new Clouds(value); return new Clouds(value);
@@ -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);
} }
} }
} }
@@ -45,11 +45,12 @@ public class Humidity {
/** /**
* Creates {@link Humidity} object with correctness check. * 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) {
if (value < 0 || value > 100) { if (value < 0 || value > 100) {
throw new IllegalArgumentException("Humidity value must be in [0, 100] range."); throw new IllegalArgumentException("Humidity value must be in [0, 100] range.");
} }
return new Humidity(value); return new Humidity(value);
@@ -71,7 +72,7 @@ public class Humidity {
* @throws IllegalArgumentException in case 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) {
if (value < 0 || value > 100) { if (value < 0 || value > 100) {
throw new IllegalArgumentException("Humidity value must be in [0, 100] range."); throw new IllegalArgumentException("Humidity value must be in [0, 100] range.");
} }
this.value = value; this.value = value;
@@ -41,8 +41,9 @@ 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
*/ */
public static Temperature withValue(double value, String unit) { public static Temperature withValue(double value, String unit) {
@@ -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,8 +46,9 @@ 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
*/ */
public static Wind withValue(double speed, String unit) { public static Wind withValue(double speed, String unit) {
@@ -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) {
@@ -115,7 +118,7 @@ public class Wind {
* @param degrees the degrees * @param degrees the degrees
*/ */
public void setDegrees(double degrees) { public void setDegrees(double degrees) {
if (degrees < 0 || degrees > 360) { if (degrees < 0 || degrees > 360) {
throw new IllegalArgumentException("Wind direction value must be in [0, 360] range."); throw new IllegalArgumentException("Wind direction value must be in [0, 360] range.");
} }
this.degrees = degrees; this.degrees = degrees;
@@ -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.";
}
}
@@ -0,0 +1,198 @@
/*
* Copyright (c) 2022 Alexey Zinchenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.prominence.openweathermap.api.model.forecast.climatic;
import com.github.prominence.openweathermap.api.model.Coordinates;
import java.time.ZoneOffset;
import java.util.Objects;
/**
* Represents location information.
*/
public class Location {
private int id;
private String name;
private String countryCode;
private ZoneOffset zoneOffset;
private Coordinates coordinates;
private Long population;
protected Location(int id, String name) {
this.id = id;
this.name = name;
}
/**
* Creates {@link Location} object with correctness check.
* @param id location id
* @param name location name
* @return location object
*/
public static Location withValues(int id, String name) {
if (name == null) {
throw new IllegalArgumentException("Name must be set.");
}
return new Location(id, name);
}
/**
* Returns ID.
* @return location ID
*/
public int getId() {
return id;
}
/**
* Sets location ID.
* @param id location id
*/
public void setId(int id) {
this.id = id;
}
/**
* Returns location name.
* @return location name
*/
public String getName() {
return name;
}
/**
* Sets location name.
* @param name location name
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns country code.
* @return location country code
*/
public String getCountryCode() {
return countryCode;
}
/**
* Sets location country code.
* @param countryCode location country code
*/
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
/**
* Returns location timezone offset.
* @return timezone offset
*/
public ZoneOffset getZoneOffset() {
return zoneOffset;
}
/**
* Sets location timezone offset.
* @param zoneOffset timezone offset
*/
public void setZoneOffset(ZoneOffset zoneOffset) {
this.zoneOffset = zoneOffset;
}
/**
* Returns location coordinates.
* @return location coordinates.
*/
public Coordinates getCoordinates() {
return coordinates;
}
/**
* Sets location coordinates.
* @param coordinates location coordinates
*/
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}
/**
* Sets location population.
* @return location population
*/
public Long getPopulation() {
return population;
}
/**
* Sets location population.
* @param population location population
*/
public void setPopulation(Long population) {
this.population = population;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Location)) return false;
Location location = (Location) o;
return id == location.id &&
Objects.equals(name, location.name) &&
Objects.equals(countryCode, location.countryCode) &&
Objects.equals(zoneOffset, location.zoneOffset) &&
Objects.equals(coordinates, location.coordinates) &&
Objects.equals(population, location.population);
}
@Override
public int hashCode() {
return Objects.hash(id, name, countryCode, zoneOffset, coordinates, population);
}
@Override
public String toString() {
final StringBuilder stringBuilder = new StringBuilder();
if (coordinates != null) {
stringBuilder.append(coordinates);
stringBuilder.append(". ");
}
stringBuilder.append("ID: ");
stringBuilder.append(id);
stringBuilder.append(", Name: ");
stringBuilder.append(name);
if (countryCode != null) {
stringBuilder.append('(');
stringBuilder.append(countryCode);
stringBuilder.append(')');
}
if (population != null) {
stringBuilder.append(", Population: ");
stringBuilder.append(population);
}
return stringBuilder.toString();
}
}
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2022 Alexey Zinchenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.prominence.openweathermap.api.model.forecast.climatic;
import java.util.Objects;
/**
* Represents rain information.
*/
public class Rain {
private static final String DEFAULT_UNIT = "mm";
private double level;
protected Rain(double level) {
this.level = level;
}
/**
* Creates {@link Rain} object with correctness check.
* @param level rain level value
* @return rain object.
*/
public static Rain withValue(double level) {
if (level < 0) {
throw new IllegalArgumentException("Rain level value cannot be negative.");
}
return new Rain(level);
}
/**
* Returns rain level value.
* @return rain level value
*/
public double getLevel() {
return level;
}
/**
* Sets rain level value with correctness check.
* @param level rain level value
*/
public void setLevel(double level) {
if (level < 0) {
throw new IllegalArgumentException("Rain level value cannot be negative.");
}
this.level = level;
}
/**
* Returns rain level unit of measure. Currently, is constant.
* @return rain level unit of measure
*/
public String getUnit() {
return DEFAULT_UNIT;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Rain rain = (Rain) o;
return Double.compare(rain.level, level) == 0;
}
@Override
public int hashCode() {
return Objects.hash(level);
}
@Override
public String toString() {
return "Rain precipitation volume, mm: " +
level + ' ' +
getUnit();
}
}
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2022 Alexey Zinchenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.prominence.openweathermap.api.model.forecast.climatic;
import java.util.Objects;
/**
* Represents snow information.
*/
public class Snow {
private static final String DEFAULT_UNIT = "mm";
private double level;
protected Snow(double level) {
this.level = level;
}
/**
* Creates {@link Snow} object with correctness check.
* @param threeHourLevel snow level value
* @return snow object.
*/
public static Snow withValue(double threeHourLevel) {
if (threeHourLevel < 0) {
throw new IllegalArgumentException("Snow level value cannot be negative.");
}
return new Snow(threeHourLevel);
}
/**
* Returns snow level value.
* @return snow level value
*/
public double getLevel() {
return level;
}
/**
* Sets snow level value with correctness check.
* @param level snow level value
*/
public void setLevel(double level) {
if (level < 0) {
throw new IllegalArgumentException("Snow level value cannot be negative.");
}
this.level = level;
}
/**
* Returns snow level unit of measure. Currently, is constant.
* @return snow level unit of measure
*/
public String getUnit() {
return DEFAULT_UNIT;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Snow snow = (Snow) o;
return Double.compare(snow.level, level) == 0;
}
@Override
public int hashCode() {
return Objects.hash(level);
}
@Override
public String toString() {
return "Snow volume, mm: " +
level + ' ' +
getUnit();
}
}
@@ -0,0 +1,263 @@
/*
* Copyright (c) 2021 Alexey Zinchenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.prominence.openweathermap.api.model.forecast.climatic;
import java.util.Objects;
/**
* The type Daily temperature.
*/
public class Temperature {
private Double morning;
private Double morningFeelsLike;
private Double day;
private Double dayFeelsLike;
private Double eve;
private Double eveFeelsLike;
private Double night;
private Double nightFeelsLike;
private Double min;
private Double max;
private String unit;
/**
* Gets morning temperature.
*
* @return the morning
*/
public Double getMorning() {
return morning;
}
/**
* Sets morning temperature.
*
* @param morning the morning
*/
public void setMorning(Double morning) {
this.morning = morning;
}
/**
* Gets morning feels like temperature.
*
* @return the morning feels like temperature
*/
public Double getMorningFeelsLike() {
return morningFeelsLike;
}
/**
* Sets morning feels like temperature.
*
* @param morningFeelsLike the morning feels like temperature
*/
public void setMorningFeelsLike(Double morningFeelsLike) {
this.morningFeelsLike = morningFeelsLike;
}
/**
* Gets day temperature.
*
* @return the day temperature
*/
public Double getDay() {
return day;
}
/**
* Sets day temperature.
*
* @param day the day temperature
*/
public void setDay(Double day) {
this.day = day;
}
/**
* Gets day feels like temperature.
*
* @return the day feels like temperature
*/
public Double getDayFeelsLike() {
return dayFeelsLike;
}
/**
* Sets day feels like temperature.
*
* @param dayFeelsLike the day feels like temperature
*/
public void setDayFeelsLike(Double dayFeelsLike) {
this.dayFeelsLike = dayFeelsLike;
}
/**
* Gets eve temperature.
*
* @return the eve temperature
*/
public Double getEve() {
return eve;
}
/**
* Sets eve temperature.
*
* @param eve the eve temperature
*/
public void setEve(Double eve) {
this.eve = eve;
}
/**
* Gets eve feels like temperature.
*
* @return the eve feels like temperature
*/
public Double getEveFeelsLike() {
return eveFeelsLike;
}
/**
* Sets eve feels like temperature.
*
* @param eveFeelsLike the eve feels like temperature
*/
public void setEveFeelsLike(Double eveFeelsLike) {
this.eveFeelsLike = eveFeelsLike;
}
/**
* Gets night temperature.
*
* @return the night temperature
*/
public Double getNight() {
return night;
}
/**
* Sets night temperature.
*
* @param night the night temperature
*/
public void setNight(Double night) {
this.night = night;
}
/**
* Gets night feels like temperature.
*
* @return the night feels like temperature
*/
public Double getNightFeelsLike() {
return nightFeelsLike;
}
/**
* Sets night feels like temperature.
*
* @param nightFeelsLike the night feels like temperature
*/
public void setNightFeelsLike(Double nightFeelsLike) {
this.nightFeelsLike = nightFeelsLike;
}
/**
* Gets min temperature.
*
* @return the min temperature
*/
public Double getMin() {
return min;
}
/**
* Sets min temperature.
*
* @param min the min temperature
*/
public void setMin(Double min) {
this.min = min;
}
/**
* Gets max temperature.
*
* @return the max temperature
*/
public Double getMax() {
return max;
}
/**
* Sets max temperature.
*
* @param max the max temperature
*/
public void setMax(Double max) {
this.max = max;
}
/**
* Gets unit temperature.
*
* @return the unit temperature
*/
public String getUnit() {
return unit;
}
/**
* Sets unit temperature.
*
* @param unit the unit temperature
*/
public void setUnit(String unit) {
this.unit = unit;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Temperature that = (Temperature) o;
return Objects.equals(morning, that.morning) &&
Objects.equals(morningFeelsLike, that.morningFeelsLike) &&
Objects.equals(day, that.day) &&
Objects.equals(dayFeelsLike, that.dayFeelsLike) &&
Objects.equals(eve, that.eve) &&
Objects.equals(eveFeelsLike, that.eveFeelsLike) &&
Objects.equals(night, that.night) &&
Objects.equals(nightFeelsLike, that.nightFeelsLike) &&
Objects.equals(min, that.min) &&
Objects.equals(max, that.max) &&
Objects.equals(unit, that.unit);
}
@Override
public int hashCode() {
return Objects.hash(morning, morningFeelsLike, day, dayFeelsLike, eve, eveFeelsLike, night, nightFeelsLike, min, max, unit);
}
}
@@ -0,0 +1,295 @@
/*
* Copyright (c) 2022 Alexey Zinchenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.prominence.openweathermap.api.model.forecast.climatic;
import com.github.prominence.openweathermap.api.model.Clouds;
import com.github.prominence.openweathermap.api.model.Humidity;
import com.github.prominence.openweathermap.api.model.WeatherState;
import com.github.prominence.openweathermap.api.model.Wind;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* Represents weather forecast information for a particular timestamp.
*/
public class WeatherForecast {
private LocalDateTime forecastTime;
private LocalDateTime sunriseTime;
private LocalDateTime sunsetTime;
private List<WeatherState> weatherStates;
private Temperature temperature;
private AtmosphericPressure atmosphericPressure;
private Humidity humidity;
private Wind wind;
private Rain rain;
private Snow snow;
private Clouds clouds;
/**
* Gets forecast time.
*
* @return the forecast time
*/
public LocalDateTime getForecastTime() {
return forecastTime;
}
/**
* Sets forecast time.
*
* @param forecastTime the forecast time
*/
public void setForecastTime(LocalDateTime forecastTime) {
this.forecastTime = forecastTime;
}
public LocalDateTime getSunriseTime() {
return sunriseTime;
}
public void setSunriseTime(LocalDateTime sunriseTime) {
this.sunriseTime = sunriseTime;
}
public LocalDateTime getSunsetTime() {
return sunsetTime;
}
public void setSunsetTime(LocalDateTime sunsetTime) {
this.sunsetTime = sunsetTime;
}
/**
* Gets weather state.
*
* @return the weather state
*/
public List<WeatherState> getWeatherStates() {
return weatherStates;
}
/**
* Sets weather state.
*
* @param weatherStates the weather state
*/
public void setWeatherStates(List<WeatherState> weatherStates) {
this.weatherStates = weatherStates;
}
/**
* Gets temperature.
*
* @return the temperature
*/
public Temperature getTemperature() {
return temperature;
}
/**
* Sets temperature.
*
* @param temperature the temperature
*/
public void setTemperature(Temperature temperature) {
this.temperature = temperature;
}
/**
* Gets atmospheric pressure.
*
* @return the atmospheric pressure
*/
public AtmosphericPressure getAtmosphericPressure() {
return atmosphericPressure;
}
/**
* Sets atmospheric pressure.
*
* @param atmosphericPressure the atmospheric pressure
*/
public void setAtmosphericPressure(AtmosphericPressure atmosphericPressure) {
this.atmosphericPressure = atmosphericPressure;
}
/**
* Gets humidity.
*
* @return the humidity
*/
public Humidity getHumidity() {
return humidity;
}
/**
* Sets humidity.
*
* @param humidity the humidity
*/
public void setHumidity(Humidity humidity) {
this.humidity = humidity;
}
/**
* Gets wind.
*
* @return the wind
*/
public Wind getWind() {
return wind;
}
/**
* Sets wind.
*
* @param wind the wind
*/
public void setWind(Wind wind) {
this.wind = wind;
}
/**
* Gets rain.
*
* @return the rain
*/
public Rain getRain() {
return rain;
}
/**
* Sets rain.
*
* @param rain the rain
*/
public void setRain(Rain rain) {
this.rain = rain;
}
/**
* Gets snow.
*
* @return the snow
*/
public Snow getSnow() {
return snow;
}
/**
* Sets snow.
*
* @param snow the snow
*/
public void setSnow(Snow snow) {
this.snow = snow;
}
/**
* Gets clouds.
*
* @return the clouds
*/
public Clouds getClouds() {
return clouds;
}
/**
* Sets clouds.
*
* @param clouds the clouds
*/
public void setClouds(Clouds clouds) {
this.clouds = clouds;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WeatherForecast that = (WeatherForecast) o;
return Objects.equals(forecastTime, that.forecastTime) &&
Objects.equals(sunriseTime, that.sunriseTime) &&
Objects.equals(sunsetTime, that.sunsetTime) &&
Objects.equals(weatherStates, that.weatherStates) &&
Objects.equals(temperature, that.temperature) &&
Objects.equals(atmosphericPressure, that.atmosphericPressure) &&
Objects.equals(humidity, that.humidity) &&
Objects.equals(wind, that.wind) &&
Objects.equals(rain, that.rain) &&
Objects.equals(snow, that.snow) &&
Objects.equals(clouds, that.clouds);
}
@Override
public int hashCode() {
return Objects.hash(forecastTime, sunriseTime, sunsetTime, weatherStates, temperature, atmosphericPressure, humidity, wind, rain, snow, clouds);
}
@Override
public String toString() {
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Timestamp: ");
stringBuilder.append(forecastTime);
if (weatherStates != null && weatherStates.size() > 0) {
stringBuilder.append(", Weather: ");
stringBuilder.append(weatherStates.get(0).getDescription());
}
if (temperature != null) {
stringBuilder.append(", Min temperature: ");
stringBuilder.append(temperature.getMin());
stringBuilder.append(temperature.getUnit());
stringBuilder.append(", Max temperature: ");
stringBuilder.append(temperature.getMax());
stringBuilder.append(temperature.getUnit());
}
if (atmosphericPressure != null) {
stringBuilder.append(", ");
stringBuilder.append(atmosphericPressure.getSeaLevelValue());
stringBuilder.append(' ');
stringBuilder.append(atmosphericPressure.getUnit());
}
if (clouds != null) {
stringBuilder.append(", ");
stringBuilder.append(clouds);
}
if (rain != null) {
stringBuilder.append(", Rain: ");
stringBuilder.append(rain.getLevel());
stringBuilder.append(' ');
stringBuilder.append(rain.getUnit());
}
if (snow != null) {
stringBuilder.append(", Snow: ");
stringBuilder.append(snow.getLevel());
stringBuilder.append(' ');
stringBuilder.append(snow.getUnit());
}
return stringBuilder.toString();
}
}
@@ -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,12 +20,12 @@
* SOFTWARE. * SOFTWARE.
*/ */
package com.github.prominence.openweathermap.api.model.forecast; package com.github.prominence.openweathermap.api.model.forecast.climatic;
import java.util.Objects; import java.util.Objects;
/** /**
* Represents wind information. * The type Wind.
*/ */
public class Wind { public class Wind {
private double speed; private double speed;
@@ -44,10 +44,11 @@ public class Wind {
} }
/** /**
* Creates {@link Wind} object with correctness check * Creates {@link Wind} object with correctness check.
* @param speed the wind *
* @param unit the unitSystem * @param speed the speed
* @return created wind object * @param unit the unitSystem
* @return wind object
*/ */
public static Wind withValue(double speed, String unit) { public static Wind withValue(double speed, String unit) {
if (speed < 0) { if (speed < 0) {
@@ -95,7 +96,7 @@ public class Wind {
* @param degrees the degrees * @param degrees the degrees
*/ */
public void setDegrees(double degrees) { public void setDegrees(double degrees) {
if (degrees < 0 || degrees > 360) { if (degrees < 0 || degrees > 360) {
throw new IllegalArgumentException("Wind direction value must be in [0, 360] range."); throw new IllegalArgumentException("Wind direction value must be in [0, 360] range.");
} }
this.degrees = degrees; this.degrees = degrees;
@@ -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.daily;
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.daily;
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.";
}
}
@@ -0,0 +1,198 @@
/*
* Copyright (c) 2022 Alexey Zinchenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.prominence.openweathermap.api.model.forecast.daily;
import com.github.prominence.openweathermap.api.model.Coordinates;
import java.time.ZoneOffset;
import java.util.Objects;
/**
* Represents location information.
*/
public class Location {
private int id;
private String name;
private String countryCode;
private ZoneOffset zoneOffset;
private Coordinates coordinates;
private Long population;
protected Location(int id, String name) {
this.id = id;
this.name = name;
}
/**
* Creates {@link Location} object with correctness check.
* @param id location id
* @param name location name
* @return location object
*/
public static Location withValues(int id, String name) {
if (name == null) {
throw new IllegalArgumentException("Name must be set.");
}
return new Location(id, name);
}
/**
* Returns ID.
* @return location ID
*/
public int getId() {
return id;
}
/**
* Sets location ID.
* @param id location id
*/
public void setId(int id) {
this.id = id;
}
/**
* Returns location name.
* @return location name
*/
public String getName() {
return name;
}
/**
* Sets location name.
* @param name location name
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns country code.
* @return location country code
*/
public String getCountryCode() {
return countryCode;
}
/**
* Sets location country code.
* @param countryCode location country code
*/
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
/**
* Returns location timezone offset.
* @return timezone offset
*/
public ZoneOffset getZoneOffset() {
return zoneOffset;
}
/**
* Sets location timezone offset.
* @param zoneOffset timezone offset
*/
public void setZoneOffset(ZoneOffset zoneOffset) {
this.zoneOffset = zoneOffset;
}
/**
* Returns location coordinates.
* @return location coordinates.
*/
public Coordinates getCoordinates() {
return coordinates;
}
/**
* Sets location coordinates.
* @param coordinates location coordinates
*/
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}
/**
* Sets location population.
* @return location population
*/
public Long getPopulation() {
return population;
}
/**
* Sets location population.
* @param population location population
*/
public void setPopulation(Long population) {
this.population = population;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Location)) return false;
Location location = (Location) o;
return id == location.id &&
Objects.equals(name, location.name) &&
Objects.equals(countryCode, location.countryCode) &&
Objects.equals(zoneOffset, location.zoneOffset) &&
Objects.equals(coordinates, location.coordinates) &&
Objects.equals(population, location.population);
}
@Override
public int hashCode() {
return Objects.hash(id, name, countryCode, zoneOffset, coordinates, population);
}
@Override
public String toString() {
final StringBuilder stringBuilder = new StringBuilder();
if (coordinates != null) {
stringBuilder.append(coordinates);
stringBuilder.append(". ");
}
stringBuilder.append("ID: ");
stringBuilder.append(id);
stringBuilder.append(", Name: ");
stringBuilder.append(name);
if (countryCode != null) {
stringBuilder.append('(');
stringBuilder.append(countryCode);
stringBuilder.append(')');
}
if (population != null) {
stringBuilder.append(", Population: ");
stringBuilder.append(population);
}
return stringBuilder.toString();
}
}
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2022 Alexey Zinchenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.prominence.openweathermap.api.model.forecast.daily;
import java.util.Objects;
/**
* Represents rain information.
*/
public class Rain {
private static final String DEFAULT_UNIT = "mm";
private double level;
protected Rain(double level) {
this.level = level;
}
/**
* Creates {@link Rain} object with correctness check.
* @param level rain level value
* @return rain object.
*/
public static Rain withValue(double level) {
if (level < 0) {
throw new IllegalArgumentException("Rain level value cannot be negative.");
}
return new Rain(level);
}
/**
* Returns rain level value.
* @return rain level value
*/
public double getLevel() {
return level;
}
/**
* Sets rain level value with correctness check.
* @param level rain level value
*/
public void setLevel(double level) {
if (level < 0) {
throw new IllegalArgumentException("Rain level value cannot be negative.");
}
this.level = level;
}
/**
* Returns rain level unit of measure. Currently, is constant.
* @return rain level unit of measure
*/
public String getUnit() {
return DEFAULT_UNIT;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Rain rain = (Rain) o;
return Double.compare(rain.level, level) == 0;
}
@Override
public int hashCode() {
return Objects.hash(level);
}
@Override
public String toString() {
return "Rain precipitation volume, mm: " +
level + ' ' +
getUnit();
}
}

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