adamint / spotify-web-api-kotlin

Spotify Web API wrapper for Kotlin, Java, JS, and Native - Targets JVM, Android, JS (browser), Native (Desktop), and Apple tvOS/iOS. Includes a Spotify Web Playback SDK wrapper for Kotlin/JS, and a spotify-auth wrapper for Kotlin/Android.
https://adamint.github.io/spotify-web-api-kotlin-docs/
MIT License
194 stars 21 forks source link

Json Parsing Exception when TrackApi.getTrack() #335

Closed osa030 closed 5 months ago

osa030 commented 6 months ago

Describe the bug

I had been using 4.0.1, but the album image size type in the response JSON from Spotify in TrackApi's getTrack had changed from integer to number, which caused a parse error. So I changed to the latest version, 4.1.0, and the album image size was resolved because it changed the type of the SpotifyImage variable to Double, but now a similar parse error occurred elsewhere.

From the exception msg, it looks like "track_number", "disc_number", "duration_ms", and "total_tracks" are changed from integer to number.

I know you are busy, but it would be helpful if you could address this.

Here is the exception msg: com.adamratzman.spotify.SpotifyException$ParseException: Unable to parse {"album":{"album_type":"album","artists":[{"external_urls":{"spotify":"https://open.spotify.com/artist/29kkCKKGXheHuoO829FxWK"},"href":"https://api.spotify.com/v1/artists/29kkCKKGXheHuoO829FxWK","id":"29kkCKKGXheHuoO829FxWK","name":"Boston","type":"artist","uri":"spotify:artist:29kkCKKGXheHuoO829FxWK"}],"external_urls":{"spotify":"https://open.spotify.com/album/2QLp07RO6anZHmtcKTEvSC"},"href":"https://api.spotify.com/v1/albums/2QLp07RO6anZHmtcKTEvSC","id":"2QLp07RO6anZHmtcKTEvSC","images":[{"url":"https://i.scdn.co/image/ab67616d0000b2738c1fadcc997a65384f34d694","width":640.0,"height":640.0},{"url":"https://i.scdn.co/image/ab67616d00001e028c1fadcc997a65384f34d694","width":300.0,"height":300.0},{"url":"https://i.scdn.co/image/ab67616d000048518c1fadcc997a65384f34d694","width":64.0,"height":64.0}],"is_playable":true,"name":"Boston","release_date":"1976","release_date_precision":"year","total_tracks":8.0,"type":"album","uri":"spotify:album:2QLp07RO6anZHmtcKTEvSC"},"artists":[{"external_urls":{"spotify":"https://open.spotify.com/artist/29kkCKKGXheHuoO829FxWK"},"href":"https://api.spotify.com/v1/artists/29kkCKKGXheHuoO829FxWK","id":"29kkCKKGXheHuoO829FxWK","name":"Boston","type":"artist","uri":"spotify:artist:29kkCKKGXheHuoO829FxWK"}],"disc_number":1.0,"duration_ms":303586.0,"explicit":false,"external_ids":{"isrc":"USSM17600644"},"external_urls":{"spotify":"https://open.spotify.com/track/1GqlvSEtMx5xbGptxOTTyk"},"href":"https://api.spotify.com/v1/tracks/1GqlvSEtMx5xbGptxOTTyk","id":"1GqlvSEtMx5xbGptxOTTyk","is_local":false,"is_playable":true,"name":"Peace of Mind","popularity":70.0,"preview_url":"https://p.scdn.co/mp3-preview/3968a8001698e00fed591f0112f6603a56f2cef1?cid=533ce266539e41cb99642548c29f023c","track_number":2.0,"type":"track","uri":"spotify:track:1GqlvSEtMx5xbGptxOTTyk"} (Unexpected JSON token at offset 910: Unexpected symbol '.' in numeric literal at path: $.album.total_tracks

Nielssg commented 6 months ago

I'm experiencing the same issue, from what I could tell Spotify changed the SimpleAlbum class so the totalTracks is no longer an integer, but rather a float. I cannot seem to understand why the amount of tracks in an album would ever be in the decimals, but it's not ideal.

It seems other people are also noticing this issue, which not only happens to the totalTracks property but also various others. https://community.spotify.com/t5/Spotify-for-Developers/duration-ms-suddenly-returning-float-instead-of-int/td-p/5911044

adamint commented 6 months ago

Thank you for reporting, and thank you so much @Nielssg for the link to that thread. It looks like

  1. In the future, we can’t really expect more ints to change
  2. Spotify developers don’t care, which is unfortunate

This will likely require running all requests through a transformation phase before the serialization phase, where expected types are compared to actual types, and casted if necessary

Nielssg commented 6 months ago

Yep very unfortunate 🙁

I am currently working on a serializer which indeed casts the value to an int if its a float. Our Android app is experiencing issues with some calls so I am trying to create a patch asap for our app. I cannot seem to get a global serializer module working (perhaps because an Int is a primitive), so I'll be appending @Serializable(with=) to every data class property which uses an Int. I would not recommend to do anything with the code down below, as it is a quick fix, but I wanted to let you know it will solve patch the problem Spotify created.

// SerializationUtils.kt
public object SpotifyFloatFixSerializer : KSerializer<Int> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("SpotifyFloatFixSerializer", PrimitiveKind.FLOAT)

    override fun serialize(encoder: Encoder, value: Int) {
        encoder.encodeInt(value)
    }

    override fun deserialize(decoder: Decoder): Int {
        return try {
            decoder.decodeFloat().toInt()
        } catch (e: Throwable) {
            decoder.decodeInt()
        }
    }
}

// Albums.kt, but applicable for various other classes (e.g. Track.kt)
data class SimpleAlbum(
    @Serializable(with = SpotifyFloatFixSerializer::class)
    @SerialName("total_tracks") val totalTracks: Int? = null,
    ... other properties
)
adamint commented 6 months ago

A similar approach is currently taken with a couple endpoints.

Using a transforming serializer is also possible

osa030 commented 6 months ago

@adamint @Nielssg Thanks for considering how to address this issue.

I looked at the Spotify community that you mentioned before, and it appears to be an API issue that has been resolved.

https://community.spotify.com/t5/Spotify-for-Developers/duration-ms-suddenly-returning-float-instead-of-int/m-p/5926879#M13032

I checked the operation, still on 4.1.0, and the various values have reverted from number to integer, and the parsing error no longer occurs. (The image size of album images has also reverted to integer.)

{ "album":{ "album_type":"album", "artists":[ { "external_urls":{ "spotify":"https://open.spotify.com/artist/11wRdbnoYqRddKBrpHt4Ue" }, "href":"https://api.spotify.com/v1/artists/11wRdbnoYqRddKBrpHt4Ue", "id":"11wRdbnoYqRddKBrpHt4Ue", "name":"Kasabian", "type":"artist", "uri":"spotify:artist:11wRdbnoYqRddKBrpHt4Ue" } ], "external_urls":{ "spotify":"https://open.spotify.com/album/2DHGeuRTttjurZDb0pSjx6" }, "href":"https://api.spotify.com/v1/albums/2DHGeuRTttjurZDb0pSjx6", "id":"2DHGeuRTttjurZDb0pSjx6", "images":[ { "url":"https://i.scdn.co/image/ab67616d0000b273358f726999166b87f00e7066", "width":640, "height":640 }, { "url":"https://i.scdn.co/image/ab67616d00001e02358f726999166b87f00e7066", "width":300, "height":300 }, { "url":"https://i.scdn.co/image/ab67616d00004851358f726999166b87f00e7066", "width":64, "height":64 } ], "is_playable":true, "name":"West Ryder Pauper Lunatic Asylum", "release_date":"2009", "release_date_precision":"year", "total_tracks":12, "type":"album", "uri":"spotify:album:2DHGeuRTttjurZDb0pSjx6" }, "artists":[ { "external_urls":{ "spotify":"https://open.spotify.com/artist/11wRdbnoYqRddKBrpHt4Ue" }, "href":"https://api.spotify.com/v1/artists/11wRdbnoYqRddKBrpHt4Ue", "id":"11wRdbnoYqRddKBrpHt4Ue", "name":"Kasabian", "type":"artist", "uri":"spotify:artist:11wRdbnoYqRddKBrpHt4Ue" } ], "disc_number":1, "duration_ms":277466, "explicit":false, "external_ids":{ "isrc":"GBARL0801796" }, "external_urls":{ "spotify":"https://open.spotify.com/track/3PbsDnKdrZY0ttX7VE9s5R" }, "href":"https://api.spotify.com/v1/tracks/3PbsDnKdrZY0ttX7VE9s5R", "id":"3PbsDnKdrZY0ttX7VE9s5R", "is_local":false, "is_playable":true, "name":"Underdog", "popularity":63, "preview_url":"https://p.scdn.co/mp3-preview/5e0eefd1c6fd79caa07b4392c156dc4b78c72dd5?cid=533ce266539e41cb99642548c29f023c", "track_number":1, "type":"track", "uri":"spotify:track:3PbsDnKdrZY0ttX7VE9s5R" }

I think there is no need for the library to take action on this issue and it should be fine as a solution.