Side-by-side comparison of five Java HTTP clients (HttpURLConnection, java.net.http.HttpClient, Apache HttpClient 5, OkHttp, Retrofit) and four JSON-parsing approaches (tree model, simple data binding, full-schema data binding, path queries) — two independent demonstration tracks. Each HTTP client issues the same GET /api/article_users?page=2 request and parses it into a shared model, so client trade-offs (ergonomics, dependency footprint, async support) are directly comparable; each JSON-parsing demo processes the same bundled NASA Near-Earth Objects (NEO) feed snapshot, so parsing trade-offs (schema handling, query ergonomics) are directly comparable. It doubles as a build-tooling reference: a JUnit 6 + WireMock test pyramid, google-java-format / gitleaks / Trivy / OWASP dependency-check quality + security gates, JaCoCo 70% coverage enforcement, and a GitHub Actions CI pipeline (locally replayable via act) on a mise-pinned toolchain with Renovate-managed dependencies.
flowchart LR
App["Example main() classes"]
subgraph HTTPC["HTTP Clients — fetch + parse into a shared Page/User model"]
direction TB
HC1["HttpURLConnection (JDK)"]
HC2["java.net.http.HttpClient (JDK)"]
HC3["Apache HttpClient 5"]
HC4["OkHttp"]
HC5["Retrofit (+ Gson converter)"]
end
API[("Article-users API<br/>jsonmock.hackerrank.com")]
subgraph JSONP["JSON Parsing — four approaches over a bundled NEO feed"]
direction TB
JP1["Tree model<br/>Jackson JsonNode + Gson JsonElement"]
JP2["Simple data binding<br/>Jackson + Gson POJOs"]
JP3["Complex data binding<br/>generated full-schema POJOs"]
JP4["Path queries<br/>JsonPath + Jackson JsonPointer"]
end
NEO["Bundled source.json<br/>(NASA NEO feed snapshot)"]
App --> HTTPC
HTTPC -->|"GET /api/article_users?page=2"| API
App --> JSONP
JSONP -->|"reads classpath resource"| NEO
The two areas are independent. Each main() class under http/client/{java,apache,okhttp,retrofit} (over a shared http/client/model) issues GET /api/article_users?page=2 against a public article-users API and parses the JSON into Page/User. Separately, each main() under jsonparse/{treemodels,databinding/simple,databinding/complex,pathqueries} parses the bundled src/main/resources/source.json (a NASA NEO feed snapshot) — no network call. Library versions live in the Tech Stack table below — the diagram intentionally omits them so it never drifts from the build.
| Component | Technology |
|---|---|
| Language | Java 25 LTS (Temurin via mise) |
| Build | Maven 3.9.16 (pinned via .mise.toml; enforcer allows 3.6.3+) |
| Tests | JUnit Jupiter 6.1.1 (unit) + WireMock 3.13.2 (integration via Failsafe *IT.java) |
| Coverage | JaCoCo (70% instruction + branch) |
| HTTP clients | java.net.HttpURLConnection, java.net.http.HttpClient, Apache HttpClient 5 5.6.1, OkHttp 5.4.0, Retrofit 3.0.0 |
| JSON | Jackson 3.2.0 (tools.jackson.core), Gson 2.14.0, JsonPath 3.0.0 |
| Formatting | google-java-format |
| Security | gitleaks, Trivy, OWASP dependency-check |
| CI | GitHub Actions; local replay via act |
| Automation | Renovate (automerge via its own re-validated run) |
make deps # auto-install mise + Java/Maven pinned in .mise.toml
make build # build the project
make test # run all tests
make ci # or run the full CI pipeline (static-check, test, coverage-check, build)| Tool | Version | Purpose |
|---|---|---|
| GNU Make | 3.81+ | Build orchestration |
| Git | 2.0+ | Version control, releases |
| JDK | 25+ | Java runtime and compiler (source: .java-version) |
| Maven | 3.6.3+ | Build and dependency management (3.9.16 pinned in .mise.toml) |
| mise | latest | Java/Maven version manager (auto-installed by make deps) |
| Docker | latest | Required by act for local CI |
| act | 0.2.89+ | Local CI runner for make ci-run (installed via make deps-act) |
Install everything:
make depsTwo independent module areas under src/main/java/:
| Implementation | Package | Notes |
|---|---|---|
| HttpURLConnection | java.net |
Core JDK, low-level |
| java.net.http.HttpClient | java.net.http |
Modern JDK (Java 11+), async-capable |
| Apache HttpClient 5 | org.apache.httpcomponents.client5 |
Long-standing library, fluent API |
| OkHttp | com.squareup.okhttp3 |
Square's HTTP stack |
| Retrofit | com.squareup.retrofit2 |
Type-safe REST over OkHttp, Gson converter |
Shared models live under http/client/model/.
| Approach | Package | Library |
|---|---|---|
| Tree model | jsonparse/treemodels/ |
Jackson JsonNode, Gson JsonElement |
| Data binding — simple | jsonparse/databinding/simple/ |
Jackson + Gson POJO mapping |
| Data binding — complex | jsonparse/databinding/complex/ |
Generated model classes (jackson/generated/, gson/generated/) |
| Path queries | jsonparse/pathqueries/ |
JsonPath + Jackson JsonPointer |
Each HTTP client and JSON-parsing approach has a matching *Test.java (Surefire, unit) and — where applicable — an *IT.java (Failsafe, WireMock-stubbed):
# run a single unit test
mvn -B test -Dtest=OkHttpDemoTest -Ddependency-check.skip=true
# run all WireMock-stubbed integration tests
make integration-testmake cve-check scans dependencies for known vulnerabilities using two data sources:
- NVD — NIST National Vulnerability Database. Without an API key, requests are rate-limited and the scan may fail with a 429 error.
- OSS Index — Sonatype's vulnerability database; provides additional coverage beyond NVD. Authentication is required — without credentials the analyzer is skipped.
export NVD_API_KEY=<nvd-api-key>
export OSS_INDEX_USER=<ossindex-account-email>
export OSS_INDEX_TOKEN=<ossindex-api-token>
make cve-checkBoth the NVD API key and OSS Index credentials are written to ~/.m2/settings.xml by the maven-settings-ossindex prerequisite of cve-check, then referenced by id (-DnvdApiServerId=nvd) — secret values never enter Maven's argv (visible to local users via ps -ef).
Listed below; make help prints the same list.
| Target | Description |
|---|---|
make build |
Build project (skips tests and OWASP dependency-check) |
make clean |
Cleanup |
| Target | Description |
|---|---|
make test |
Run project tests (unit, fast) |
make integration-test |
Run integration tests (WireMock-stubbed HTTP clients; *IT.java) |
make coverage-generate |
Generate JaCoCo coverage report |
make coverage-check |
Verify code coverage meets 70% threshold |
make coverage-open |
Open code coverage report |
| Target | Description |
|---|---|
make lint |
Validate project configuration and check compiler warnings |
make format |
Format Java sources with google-java-format |
make format-check |
Verify Java sources are formatted |
make secrets |
Scan repository for hardcoded secrets (gitleaks) |
make trivy-fs |
Filesystem vulnerability/secret/misconfig scan |
make mermaid-lint |
Validate Mermaid diagrams in Markdown (requires Docker) |
make check-toolchain-alignment |
Fail if the Java major disagrees across .java-version, .mise.toml, pom.xml |
make static-check |
Composite fast quality gate (check-toolchain-alignment + format-check + lint + secrets + trivy-fs + mermaid-lint + deps-prune-check) |
make cve-check |
Run OWASP dependency vulnerability scan |
make vulncheck |
Alias for cve-check |
| Target | Description |
|---|---|
make ci |
Run full CI pipeline (static-check, integration-test, coverage-check, build) |
make ci-run |
Run GitHub Actions workflow locally using act |
| Target | Description |
|---|---|
make deps |
Check tools; auto-install mise (no root) and mise-pinned Java/Maven |
make deps-install |
Install Java and Maven via mise (reads .mise.toml) |
make deps-maven |
Install Maven into ~/.local (CI fallback) |
make deps-act |
Install act into ~/.local/bin |
make deps-gitleaks |
Install gitleaks into ~/.local/bin |
make deps-trivy |
Install trivy into ~/.local/bin |
make deps-docker |
Verify Docker is available (internal helper for mermaid-lint; skipped under act) |
make deps-check |
Show required tools and installation status |
make deps-prune |
Analyze declared-but-unused / used-but-undeclared dependencies |
make deps-prune-check |
Fail build on declared-but-unused dependencies |
| Target | Description |
|---|---|
make release VERSION=x.y.z |
Tag and push a release |
make maven-settings-ossindex |
Create Maven settings for OSS Index credentials |
make renovate-bootstrap |
Install mise + Node for Renovate |
make renovate-validate |
Validate Renovate configuration |
make help |
List available tasks |
GitHub Actions runs on every push to main, tags v*, pull requests, a weekly schedule (Monday 06:00 UTC for cve-check), and manual dispatch. The workflow also exposes workflow_call for reuse.
| Job | Triggers | Runs |
|---|---|---|
changes |
every event | dorny/paths-filter detector — gates heavy jobs so doc-only changes skip CI without deadlocking the ci-pass required check |
static-check |
after changes (when code changes) |
make static-check (format-check + lint + gitleaks + Trivy filesystem scan + mermaid-lint + deps-prune-check) |
test |
after changes + static-check |
make coverage-generate (tests + jacoco:report) then make coverage-check (70% threshold); uploads coverage-report artifact |
integration-test |
after changes + static-check |
make integration-test (WireMock-stubbed HTTP client tests) |
build |
after changes + static-check |
make build |
cve-check |
tags v*, weekly schedule, manual dispatch |
make cve-check with cached NVD database (uploads cve-report artifact) |
ci-pass |
after all of the above | Single gate for branch protection |
Pipeline: changes → static-check → test + integration-test + build (parallel); cve-check runs on release tags, the weekly schedule, and manual dispatch. ci-pass aggregates every required job so branch protection needs only one check, and treats skipped jobs (doc-only PRs) as success.
| Secret | Type | Required by | Purpose |
|---|---|---|---|
NVD_API_KEY |
Secret | cve-check |
Avoid NVD rate limits — request one |
OSS_INDEX_USER |
Secret | cve-check |
OSS Index account email — register |
OSS_INDEX_TOKEN |
Secret | cve-check |
OSS Index API token from account settings |
Set secrets via Settings > Secrets and variables > Actions > New repository secret.
Renovate keeps dependencies up to date, automerging on green CI via its own re-validated run.
Contributions welcome — open a PR. Review routing is configured via CODEOWNERS.
Released under the MIT License.