GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — ci: add an API compatibility gate; refactor: replace JsonUtil with ModelObjects by dargmuesli · Pull Request #485 · spotify-web-api-java/spotify-web-api-java

Conversation

@dargmuesli

@dargmuesli dargmuesli commented Nov 3, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Steps 1 and 2 of the alternative plan discussed in #461. The commits are separate and each one builds and passes on its own.

1. ci: API compatibility gate

  • Adds japicmp-maven-plugin to pom.xml. It isn't bound to any build phase, so a plain local build doesn't need network access.
  • Adds a Check API compatibility step to CI. It compares the built jar against the newest non-RC tag before HEAD^.
    • On a release-tag build, that is the release before it, which is already on Maven Central.
  • The step fails on any change that breaks callers at compile time or at runtime. The exception is a version in pom.xml with a higher major number than the baseline, as on beta; there the report is for information only.
  • The report goes to the job summary.
  • japicmp's own semantic-versioning mode can't be used here. Between releases pom.xml still carries the last released version, and in that state the mode rejects even additive changes.
  • Documented in CONTRIBUTING.md and AGENTS.md.

2. Internal boilerplate, without changing the public API

  • Response parsing. Requests no longer create a model's JsonUtil just to reach the shared Gson. They call ModelObjectJson in a new se.michaelthelin.spotify.internal package.
    • The package isn't exported from the module and doesn't appear in the published Javadoc. It is excluded from the API gate.
    • ModelObjectGson moved there too. The parsing steps are the same, so empty or malformed bodies fail exactly as before.
  • Custom readers. The hand-written readers for Disallows, ExternalId, ExternalUrl and PlaybackQueue are now Gson adapters.
    • Their JsonUtil.createModelObject overrides now only call super.
    • They stay because their erased return type differs from the inherited one, so removing them would break callers that are already compiled.
  • Assertions. The 92 inline assert (x != null); assert (!x.isEmpty()); pairs in request builders are replaced by Preconditions.assertNotEmpty(x).
    • It is still a Java assertion: a no-op by default, and an AssertionError under -ea, as before (checked both ways).
  • Public replacement for JsonUtil. New class se.michaelthelin.spotify.model_objects.ModelObjects, for callers who read JSON they got outside a request, such as cached responses. It has four methods: fromJson, arrayFromJson, pagingFromJson and pagingCursorbasedFromJson.
    • It parses exactly the way the requests do, including enum and date formats and the mixed track/episode playlist items.
    • The signatures take a String rather than Gson types, so they won't be affected if Gson later stops being part of the public API.
    • There are deliberately no key overloads: adding them later is compatible, removing them wouldn't be.
  • Deprecation. All JsonUtil classes and IModelObject.IJsonUtil are marked deprecated, point to ModelObjects, and are to be removed in the next major version.
    • It's plain @Deprecated rather than forRemoval. Removal warnings aren't suppressed inside deprecated code, so every model JsonUtil extending the deprecated base class would add a warning to the build.
    • ModelObjectMappingTest now uses ModelObjects.

Verification (local)

  • mvn install: 420 tests, all passing, including 6 new ones for ModelObjects.
  • japicmp against 10.1.0: only additions, no incompatible change.
  • The gate itself was tested in both directions:
    • A public method made package-private fails it.
    • The same break inside an excluded package passes.
  • Javadoc (javadoc-check profile), the examples module compile, and ci/check-docs.py: all pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KSXwvJcGsHkEQQs7VNmYpR

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@claude
ci: fail on incompatible API changes against the last stable release
a512c55
Runs japicmp after the build against the newest non-RC tag before HEAD and
fails on binary or source incompatible changes, unless the major version went
up, as on beta. The report is written to the job summary.

Refs #461

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KSXwvJcGsHkEQQs7VNmYpR
@codecov

codecov Bot commented Nov 3, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.39344% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.23%. Comparing base (64986e1) to head (c5165d6).

Files with missing lines Patch % Lines
...ichaelthelin/spotify/internal/ModelObjectJson.java 76.00% 3 Missing and 3 partials ⚠️
...ichaelthelin/spotify/internal/ModelObjectGson.java 87.50% 0 Missing and 4 partials ⚠️
.../michaelthelin/spotify/internal/Preconditions.java 42.85% 0 Missing and 4 partials ⚠️
...n/spotify/model_objects/special/PlaybackQueue.java 0.00% 1 Missing ⚠️
...spotify/model_objects/specification/Disallows.java 0.00% 1 Missing ⚠️
...potify/model_objects/specification/ExternalId.java 0.00% 1 Missing ⚠️
...otify/model_objects/specification/ExternalUrl.java 0.00% 1 Missing ⚠️
...otify/model_objects/utils/PlaylistItemFactory.java 66.66% 0 Missing and 1 partial ⚠️
...uthorization_code/AuthorizationCodeUriRequest.java 75.00% 1 Missing ⚠️
...data/users/GetUsersTopArtistsAndTracksRequest.java 66.66% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #485      +/-   ##
============================================
+ Coverage     46.70%   47.23%   +0.52%     
- Complexity      692      721      +29     
============================================
  Files           209      212       +3     
  Lines          6276     6195      -81     
  Branches        759      574     -185     
============================================
- Hits           2931     2926       -5     
- Misses         2783     2890     +107     
+ Partials        562      379     -183     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

claude added 3 commits November 3, 2026 15:24
@claude
refactor(requests): read responses without going through model JsonUt…
c8af03d
…il classes

Requests now call a shared helper in a new, unexported internal package
instead of instantiating a model's JsonUtil only to reach the shared Gson.
The custom readers for Disallows, ExternalId, ExternalUrl and PlaybackQueue
move into Gson adapters, so those JsonUtil overrides only delegate and are
kept solely for binary compatibility.

The parsing steps are unchanged, all tests pass, and japicmp reports no API
change against 10.1.0. The internal package is excluded from the API gate.

Refs #461

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KSXwvJcGsHkEQQs7VNmYpR
@claude
refactor(requests): share the not-null-and-not-empty argument assertion
db33a78
Replaces 92 inline "assert (x != null); assert (!x.isEmpty());" pairs in the
request builders with Preconditions.assertNotEmpty in the internal package.
It is still a Java assertion, so it is a no-op unless assertions are enabled,
exactly like the statements it replaces.

Refs #461

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KSXwvJcGsHkEQQs7VNmYpR
@claude
refactor(models): deprecate the JsonUtil classes
d1871bc
Nothing in the library calls them any more, since responses are read through
the shared Gson instance. They are deprecated for removal in the next major
version. Plain @deprecated rather than forRemoval, because removal warnings
are not suppressed inside deprecated code and every model JsonUtil extends
the deprecated base class.

Refs #461

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KSXwvJcGsHkEQQs7VNmYpR
@dargmuesli dargmuesli changed the title ci: fail on incompatible API changes against the last stable release ci: add an API compatibility gate; refactor: drop internal JsonUtil use Nov 3, 2026
@claude
feat(models): add ModelObjects for reading model objects from JSON
c5165d6
Gives callers who parse JSON they obtained outside a request (cached or
stored responses) a public replacement for the deprecated JsonUtil classes:
fromJson, arrayFromJson, pagingFromJson and pagingCursorbasedFromJson. The
signatures take a String, not Gson types, so they survive Gson leaving the
public API. The JsonUtil deprecation notes now point here.

Refs #461

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KSXwvJcGsHkEQQs7VNmYpR
@dargmuesli dargmuesli changed the title ci: add an API compatibility gate; refactor: drop internal JsonUtil use ci: add an API compatibility gate; refactor: replace JsonUtil with ModelObjects Nov 3, 2026
This was referenced Nov 3, 2026
feat(codegen): prototype generating request classes from the OpenAPI spec #486
Closed
feat(codegen)!: generate the data requests and their SpotifyApi methods from the spec #487
Merged
@dargmuesli

dargmuesli commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

Superseded by #488 and #489

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@dargmuesli dargmuesli closed this Nov 4, 2026
@dargmuesli
dargmuesli deleted the dargmuesli/intelligent-allen-glwbik branch November 4, 2026 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@dargmuesli @claude
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.