Skip to content

Commit de189af

Browse files
authored
fix(models)!: deserialize model objects reflectively with gson (#473)
1 parent 8dc27f7 commit de189af

192 files changed

Lines changed: 391 additions & 6628 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎AGENTS.md‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ This file provides context for AI coding agents working in this repository.
88

99
- **Group ID:** `se.michaelthelin.spotify`
1010
- **Artifact ID:** `spotify-web-api-java`
11-
- **Current Version:** `10.0.0-RC1`
1211
- **Build Tool:** Maven (`pom.xml`)
13-
- **Java Version:** 17+
12+
- **Java Version:** compiled with `--release 9`; CI builds on JDK 17 and 25
1413

1514
## Repository Structure
1615

@@ -49,7 +48,6 @@ Create `src/main/java/se/michaelthelin/spotify/requests/data/<category>/<Endpoin
4948

5049
Key patterns:
5150
- Extend `AbstractDataRequest<ReturnType>` (or `AbstractDataPagingRequest` for paginated results).
52-
- Annotate with `@JsonDeserialize(builder = <ClassName>.Builder.class)`.
5351
- Implement `execute()` which calls `getJson()`, `postJson()`, `putJson()`, or `deleteJson()` as appropriate.
5452
- Add a `static final class Builder` with:
5553
- Path parameters set via `setPathParameter("key", value)`
@@ -86,6 +84,19 @@ Extend `AbstractDataTest<ReturnType>`. Tests should:
8684

8785
Common test constants are in `ITest.java` (e.g., `ITest.NAME`, `ITest.ID_PLAYLIST`, `ITest.PUBLIC`).
8886

87+
### 5. Add an example and index it
88+
89+
Create `examples/.../<EndpointName>Example.java` and link it from the example index in `README.md`.
90+
Mark the link with ⚠️ if the request class carries `@Deprecated`.
91+
92+
`./ci/check-docs.py` enforces all of this and runs in CI.
93+
It checks that every `SpotifyApi` method has an example, that example file names match their request class, that the README index is complete and its ⚠️ markers match the code, that each request's verb and path exist in `spec/openapi.yaml` with matching deprecation, and that every current-API name written in `MIGRATION.md` still resolves.
94+
95+
### Renaming or removing public API
96+
97+
Record it in `MIGRATION.md` under the relevant `#### ` heading.
98+
Names that no longer exist have to sit in a table column whose header contains "v9", or inside a code fence under a `// v9` marker, otherwise the docs check reports them as stale.
99+
89100
## Building and Testing
90101

91102
```bash
@@ -104,6 +115,10 @@ mvn test -Dtest="*Playlist*"
104115

105116
## Key Conventions
106117

118+
- **Model objects are deserialized reflectively** by the shared Gson in
119+
`model_objects/ModelObjectGson.java`, so a new field needs no parsing code.
120+
Add `@SerializedName` only when the wire name is not the snake_case form of the field,
121+
and add a type adapter only for a shape reflection cannot express.
107122
- **Trailing underscores** on Java-reserved words: e.g., `public_` for the `public` field.
108123
- **Assertions** in tests are imported from both JUnit 5 (`org.junit.jupiter.api.Assertions`) and the project's own `se.michaelthelin.spotify.Assertions`.
109124
- **Nullable fields** from the API should be tested with `assertNull(...)` when the fixture returns `null`.

‎MIGRATION.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,31 @@ There is no replacement.
151151
| `Track` | `getAvailableMarkets()`, `getLinkedFrom()`, `getPopularity()` |
152152
| `TrackSimplified` | `getAvailableMarkets()`, `getLinkedFrom()` |
153153

154+
#### Removed classes
155+
156+
Nothing in the library referred to these any more, in most cases because 10.0.0 dropped the getter that used them.
157+
158+
| v9 type | Why it went |
159+
|---|---|
160+
| `AlbumGroup` | backed `AlbumSimplified.getAlbumGroup()`, which the specification deprecated |
161+
| `ProductType` | backed the user product getter, which the specification deprecated |
162+
| `PlaylistTrackPosition` | never referenced by any request or model object |
163+
| `Paging.JsonUtil`, `PagingCursorbased.JsonUtil` | resolved their type argument to a parameterized type rather than a class, so instantiating either always threw |
164+
165+
A `Paging` object is built through the JsonUtil of the type it contains, which is how every request already built one.
166+
The `IModelObject` array helper that took an explicit element class is gone as well, having had no callers.
167+
154168
#### New getters and model objects
155169

156170
`Album` and `AlbumSimplified` gained `getTotalTracks()`, `AlbumSimplified` also `getIsPlayable()`, `Episode` and `EpisodeSimplified` `getHtmlDescription()`, `User` `getAccountId()` and `getExplicitContent()`, and `SearchResult` `getAudiobooks()`.
157171

158172
Audiobooks and chapters are new: `Audiobook`, `AudiobookSimplified`, `Chapter`, `ChapterSimplified`, `ChapterRestriction`, `Author` and `Narrator`.
159173
`ExplicitContentSettings` backs the new `User.getExplicitContent()`.
160174

175+
Three getters that always returned `null` in 9.4.0 now return a value, because the parser was reading a key the API does not send.
176+
`AudioAnalysisTrack` fixes `getWindowSeconds()` and `getEndOfFadeIn()`, and `AudioAnalysisSection` fixes `getMode()`.
177+
Code that null-checked them will now take the other branch.
178+
161179
Seven interfaces were extracted so that full and simplified objects can be handled through one type: `IAlbum`, `IArtist`, `IEpisode`, `IPlaylist`, `IShow`, `ITrack` and `IHasTotal`.
162180

163181
### New in 10.0.0
@@ -204,6 +222,15 @@ Playlist items on the `/items` path, replacing the `/tracks` path:
204222

205223
And `getAvailableMarkets` ⚠️ for `GET /markets`.
206224

225+
### Deserialization
226+
227+
Model objects are deserialized reflectively by Gson.
228+
The Jackson annotations every model carried are gone, along with the Jackson dependency itself, because nothing in the library ever constructed an ObjectMapper.
229+
230+
This only affects you if you fed these model classes into your own ObjectMapper.
231+
The `@JsonDeserialize` annotations gave you builder-based deserialization for free, and you now have to configure that yourself.
232+
Nothing changes for code that goes through the library.
233+
207234
### Deprecations
208235

209236
49 of the 114 request builders carry `@Deprecated`, up from 1 in 9.4.0.

‎pom.xml‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,6 @@
6262
<version>6.1.3</version>
6363
<scope>test</scope>
6464
</dependency>
65-
<dependency>
66-
<groupId>com.fasterxml.jackson.core</groupId>
67-
<artifactId>jackson-databind</artifactId>
68-
<version>2.22.2</version>
69-
</dependency>
7065
<dependency>
7166
<groupId>com.google.code.gson</groupId>
7267
<artifactId>gson</artifactId>
@@ -200,6 +195,11 @@
200195
<groupId>org.apache.maven.plugins</groupId>
201196
<artifactId>maven-javadoc-plugin</artifactId>
202197
<version>3.12.0</version>
198+
<configuration>
199+
<!-- accessors and builder setters in model_objects carry no prose of their own,
200+
so only broken syntax and dead references should be reported -->
201+
<doclint>all,-missing</doclint>
202+
</configuration>
203203
</plugin>
204204
</plugins>
205205
</build>
@@ -261,6 +261,7 @@
261261
</execution>
262262
</executions>
263263
<configuration>
264+
<doclint>all,-missing</doclint>
264265
<outputDirectory>${project.basedir}/</outputDirectory>
265266
</configuration>
266267
</plugin>

‎src/main/java/se/michaelthelin/spotify/enums/AlbumGroup.java‎

Lines changed: 0 additions & 54 deletions
This file was deleted.

‎src/main/java/se/michaelthelin/spotify/enums/ProductType.java‎

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)