Skip to content

Commit af86639

Browse files
committed
replace klaxon with moshi for speed-
1 parent 4d6bc38 commit af86639

File tree

22 files changed

+491
-571
lines changed

22 files changed

+491
-571
lines changed

build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ repositories {
3434

3535
dependencies {
3636
// Actual library dependencies
37-
compile 'com.beust:klaxon:5.0.5'
3837
compile 'com.neovisionaries:nv-i18n:1.25'
3938

39+
compile "com.squareup.moshi:moshi:1.8.0"
40+
compile "com.squareup.moshi:moshi-kotlin:1.8.0"
41+
4042
compile group: 'com.google.http-client', name: 'google-http-client', version: '1.23.0'
4143

4244
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

src/main/kotlin/com/adamratzman/spotify/SpotifyAPI.kt

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,9 @@ import com.adamratzman.spotify.http.byteEncode
2424
import com.adamratzman.spotify.models.AuthenticationError
2525
import com.adamratzman.spotify.models.BadRequestException
2626
import com.adamratzman.spotify.models.Token
27-
import com.adamratzman.spotify.models.serialization.getAlbumConverter
28-
import com.adamratzman.spotify.models.serialization.getFeaturedPlaylistsConverter
29-
import com.adamratzman.spotify.models.serialization.getPlaylistConverter
30-
import com.adamratzman.spotify.models.serialization.getPublicUserConverter
31-
import com.adamratzman.spotify.models.serialization.getSavedTrackConverter
3227
import com.adamratzman.spotify.models.serialization.toObject
33-
import com.beust.klaxon.Klaxon
28+
import com.squareup.moshi.Moshi
29+
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
3430
import java.util.concurrent.Executors
3531
import java.util.concurrent.ScheduledExecutorService
3632

@@ -95,8 +91,6 @@ abstract class SpotifyAPI internal constructor(
9591

9692
val logger = SpotifyLogger(enableLogger)
9793

98-
internal abstract val klaxon: Klaxon
99-
10094
/**
10195
* If the method used to create the [token] supports token refresh and
10296
* the information in [token] is accurate, attempt to refresh the token
@@ -126,6 +120,11 @@ abstract class SpotifyAPI internal constructor(
126120
*/
127121
abstract fun getApiBuilderDsl(): SpotifyApiBuilderDsl
128122

123+
internal val moshi = Moshi.Builder()
124+
.add(KotlinJsonAdapterFactory())
125+
.build()
126+
127+
129128
private fun clearCaches(vararg endpoints: SpotifyEndpoint) {
130129
endpoints.forEach { it.cache.clear() }
131130
}
@@ -189,8 +188,6 @@ class SpotifyAppAPI internal constructor(
189188
*/
190189
override val following: FollowingAPI = FollowingAPI(this)
191190

192-
override val klaxon: Klaxon = getKlaxon(this)
193-
194191
override fun refreshToken(): Token {
195192
if (clientId != "not-set" && clientSecret != "not-set") {
196193
val currentToken = this.token
@@ -292,8 +289,6 @@ class SpotifyClientAPI internal constructor(
292289
*/
293290
val player: ClientPlayerAPI = ClientPlayerAPI(this)
294291

295-
override val klaxon: Klaxon = getKlaxon(this)
296-
297292
/**
298293
* The Spotify user id to which the api instance is connected
299294
*/
@@ -395,12 +390,6 @@ fun getCredentialedToken(clientId: String, clientSecret: String, api: SpotifyAPI
395390
throw BadRequestException(response.body.toObject<AuthenticationError>(null))
396391
}
397392

398-
private fun getKlaxon(api: SpotifyAPI) = Klaxon()
399-
.converter(getFeaturedPlaylistsConverter(api))
400-
.converter(getPlaylistConverter(api))
401-
.converter(getAlbumConverter(api))
402-
.converter(getSavedTrackConverter(api))
403-
.converter(getPublicUserConverter(api))
404393

405394
internal fun executeTokenRequest(httpConnection: HttpConnection, clientId: String, clientSecret: String): HttpResponse {
406395
return httpConnection.execute(listOf(HttpHeader("Authorization", "Basic ${"$clientId:$clientSecret".byteEncode()}")))

src/main/kotlin/com/adamratzman/spotify/endpoints/client/ClientPlayerAPI.kt

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ import com.adamratzman.spotify.models.PlaylistURI
2020
import com.adamratzman.spotify.models.TrackURI
2121
import com.adamratzman.spotify.models.serialization.toCursorBasedPagingObject
2222
import com.adamratzman.spotify.models.serialization.toInnerObject
23+
import com.adamratzman.spotify.models.serialization.toJson
2324
import com.adamratzman.spotify.models.serialization.toObject
2425
import com.adamratzman.spotify.utils.catch
25-
import com.beust.klaxon.JsonObject
26+
import com.adamratzman.spotify.utils.jsonMap
2627
import java.util.function.Supplier
2728

2829
/**
@@ -69,9 +70,9 @@ class ClientPlayerAPI(api: SpotifyAPI) : SpotifyEndpoint(api) {
6970
*
7071
*/
7172
fun getRecentlyPlayed(
72-
limit: Int? = null,
73-
before: String? = null,
74-
after: String? = null
73+
limit: Int? = null,
74+
before: String? = null,
75+
after: String? = null
7576
): SpotifyRestActionPaging<PlayHistory, CursorBasedPagingObject<PlayHistory>> {
7677
return toActionPaging(Supplier {
7778
get(
@@ -231,28 +232,28 @@ class ClientPlayerAPI(api: SpotifyAPI) : SpotifyEndpoint(api) {
231232
* @throws BadRequestException if more than one type of play type is specified or the offset is illegal.
232233
*/
233234
fun startPlayback(
234-
album: String? = null,
235-
artist: String? = null,
236-
playlist: PlaylistURI? = null,
237-
offsetNum: Int? = null,
238-
offsetTrackId: String? = null,
239-
deviceId: String? = null,
240-
vararg tracksToPlay: String
235+
album: String? = null,
236+
artist: String? = null,
237+
playlist: PlaylistURI? = null,
238+
offsetNum: Int? = null,
239+
offsetTrackId: String? = null,
240+
deviceId: String? = null,
241+
vararg tracksToPlay: String
241242
): SpotifyRestAction<Unit> {
242243
return toAction(Supplier {
243244
val url = EndpointBuilder("/me/player/play").with("device_id", deviceId).toString()
244-
val body = JsonObject()
245+
val body = jsonMap()
245246
when {
246247
album != null -> body["context_uri"] = AlbumURI(album).uri
247248
artist != null -> body["context_uri"] = ArtistURI(artist).uri
248249
playlist != null -> body["context_uri"] = playlist.uri
249250
tracksToPlay.isNotEmpty() -> body["uris"] = tracksToPlay.map { TrackURI(it).uri }
250251
}
251252
if (body.keys.isNotEmpty()) {
252-
if (offsetNum != null) body["offset"] = JsonObject().apply { this["position"] = offsetNum }
253+
if (offsetNum != null) body["offset"] = jsonMap().apply { this["position"] = offsetNum }
253254
else if (offsetTrackId != null) body["offset"] =
254-
JsonObject().apply { this["uri"] = TrackURI(offsetTrackId).uri }
255-
put(url, body.toJsonString())
255+
jsonMap().apply { this["uri"] = TrackURI(offsetTrackId).uri }
256+
put(url, body.toJson())
256257
} else put(url)
257258
Unit
258259
})

src/main/kotlin/com/adamratzman/spotify/endpoints/client/ClientPlaylistAPI.kt

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ import com.adamratzman.spotify.models.PlaylistURI
1717
import com.adamratzman.spotify.models.SimplePlaylist
1818
import com.adamratzman.spotify.models.TrackURI
1919
import com.adamratzman.spotify.models.UserURI
20+
import com.adamratzman.spotify.models.serialization.toJson
2021
import com.adamratzman.spotify.models.serialization.toObject
2122
import com.adamratzman.spotify.models.serialization.toPagingObject
22-
import com.beust.klaxon.Json
23-
import com.beust.klaxon.JsonArray
24-
import com.beust.klaxon.JsonObject
23+
import com.adamratzman.spotify.utils.jsonMap
24+
import com.squareup.moshi.Json
2525
import java.awt.image.BufferedImage
2626
import java.io.ByteArrayOutputStream
2727
import java.io.File
@@ -54,22 +54,22 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
5454
* @return The created [Playlist] object with no tracks
5555
*/
5656
fun createPlaylist(
57-
name: String,
58-
description: String? = null,
59-
public: Boolean? = null,
60-
collaborative: Boolean? = null,
61-
user: String = (api as SpotifyClientAPI).userId
57+
name: String,
58+
description: String? = null,
59+
public: Boolean? = null,
60+
collaborative: Boolean? = null,
61+
user: String = (api as SpotifyClientAPI).userId
6262
): SpotifyRestAction<Playlist> {
6363
if (name.isEmpty()) throw BadRequestException(ErrorObject(400, "Name cannot be empty"))
6464
return toAction(Supplier {
65-
val json = JsonObject()
65+
val json = jsonMap()
6666
json["name"] = name
6767
if (description != null) json["description"] = description
6868
if (public != null) json["public"] = public
6969
if (collaborative != null) json["collaborative"] = collaborative
7070
post(
7171
EndpointBuilder("/users/${UserURI(user).id.encode()}/playlists").toString(),
72-
json.toJsonString()
72+
json.toJson()
7373
).toObject<Playlist>(api)
7474
})
7575
}
@@ -107,12 +107,12 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
107107
* @throws BadRequestException if any invalid track ids is provided or the playlist is not found
108108
*/
109109
fun addTracksToPlaylist(playlist: String, vararg tracks: String, position: Int? = null): SpotifyRestAction<Unit> {
110-
val json = JsonObject().apply { this["uris"] = tracks.map { TrackURI(TrackURI(it).id.encode()).uri } }
110+
val json = mutableMapOf<String, Any>("uris" to tracks.map { TrackURI(TrackURI(it).id.encode()).uri })
111111
if (position != null) json["position"] = position
112112
return toAction(Supplier {
113113
post(
114114
EndpointBuilder("/playlists/${PlaylistURI(playlist).id.encode()}/tracks").toString(),
115-
json.toJsonString()
115+
json.toJson()
116116
)
117117
Unit
118118
})
@@ -133,20 +133,20 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
133133
* @throws BadRequestException if the playlist is not found or parameters exceed the max length
134134
*/
135135
fun changePlaylistDetails(
136-
playlist: String,
137-
name: String? = null,
138-
public: Boolean? = null,
139-
collaborative: Boolean? = null,
140-
description: String? = null
136+
playlist: String,
137+
name: String? = null,
138+
public: Boolean? = null,
139+
collaborative: Boolean? = null,
140+
description: String? = null
141141
): SpotifyRestAction<Unit> {
142-
val json = JsonObject()
142+
val json = jsonMap()
143143
if (name != null) json["name"] = name
144144
if (public != null) json["public"] = public
145145
if (collaborative != null) json["collaborative"] = collaborative
146146
if (description != null) json["description"] = description
147147
if (json.isEmpty()) throw IllegalArgumentException("At least one option must not be null")
148148
return toAction(Supplier {
149-
put(EndpointBuilder("/playlists/${PlaylistURI(playlist).id.encode()}").toString(), json.toJsonString())
149+
put(EndpointBuilder("/playlists/${PlaylistURI(playlist).id.encode()}").toString(), json.toJson())
150150
Unit
151151
})
152152
}
@@ -166,8 +166,8 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
166166
* @throws BadRequestException if the filters provided are illegal
167167
*/
168168
fun getPlaylists(
169-
limit: Int? = null,
170-
offset: Int? = null
169+
limit: Int? = null,
170+
offset: Int? = null
171171
): SpotifyRestActionPaging<SimplePlaylist, PagingObject<SimplePlaylist>> {
172172
if (limit != null && limit !in 1..50) throw IllegalArgumentException("Limit must be between 1 and 50. Provided $limit")
173173
if (offset != null && offset !in 0..100000) throw IllegalArgumentException("Offset must be between 0 and 100,000. Provided $limit")
@@ -229,21 +229,21 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
229229
* @throws BadRequestException if the playlist is not found or illegal filters are applied
230230
*/
231231
fun reorderPlaylistTracks(
232-
playlist: String,
233-
reorderRangeStart: Int,
234-
reorderRangeLength: Int? = null,
235-
insertionPoint: Int,
236-
snapshotId: String? = null
232+
playlist: String,
233+
reorderRangeStart: Int,
234+
reorderRangeLength: Int? = null,
235+
insertionPoint: Int,
236+
snapshotId: String? = null
237237
): SpotifyRestAction<Snapshot> {
238238
return toAction(Supplier {
239-
val json = JsonObject()
239+
val json = jsonMap()
240240
json["range_start"] = reorderRangeStart
241241
json["insert_before"] = insertionPoint
242242
if (reorderRangeLength != null) json["range_length"] = reorderRangeLength
243243
if (snapshotId != null) json["snapshot_id"] = snapshotId
244244
put(
245245
EndpointBuilder("/playlists/${PlaylistURI(playlist).id.encode()}/tracks").toString(),
246-
json.toJsonString()
246+
json.toJson()
247247
).toObject<Snapshot>(api)
248248
})
249249
}
@@ -262,11 +262,11 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
262262
*/
263263
fun setPlaylistTracks(playlist: String, vararg tracks: String): SpotifyRestAction<Unit> {
264264
return toAction(Supplier {
265-
val json = JsonObject()
265+
val json = jsonMap()
266266
json["uris"] = tracks.map { TrackURI(TrackURI(it).id.encode()).uri }
267267
put(
268268
EndpointBuilder("/playlists/${PlaylistURI(playlist).id.encode()}/tracks").toString(),
269-
json.toJsonString()
269+
json.toJson()
270270
)
271271
Unit
272272
})
@@ -316,12 +316,12 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
316316
* @throws BadRequestException if invalid data is provided
317317
*/
318318
fun uploadPlaylistCover(
319-
playlist: String,
320-
imagePath: String? = null,
321-
imageFile: File? = null,
322-
image: BufferedImage? = null,
323-
imageData: String? = null,
324-
imageUrl: String? = null
319+
playlist: String,
320+
imagePath: String? = null,
321+
imageFile: File? = null,
322+
image: BufferedImage? = null,
323+
imageData: String? = null,
324+
imageUrl: String? = null
325325
): SpotifyRestAction<Unit> {
326326
return toAction(Supplier {
327327
val data = imageData ?: when {
@@ -351,10 +351,10 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
351351
* @param snapshotId The playlist snapshot against which to apply this action. **recommended to have**
352352
*/
353353
fun removeTrackFromPlaylist(
354-
playlist: String,
355-
track: String,
356-
positions: SpotifyTrackPositions,
357-
snapshotId: String? = null
354+
playlist: String,
355+
track: String,
356+
positions: SpotifyTrackPositions,
357+
snapshotId: String? = null
358358
) = removeTracksFromPlaylist(playlist, track to positions, snapshotId = snapshotId)
359359

360360
/**
@@ -368,9 +368,9 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
368368
* @param snapshotId The playlist snapshot against which to apply this action. **recommended to have**
369369
*/
370370
fun removeTrackFromPlaylist(
371-
playlist: String,
372-
track: String,
373-
snapshotId: String? = null
371+
playlist: String,
372+
track: String,
373+
snapshotId: String? = null
374374
) = removeTracksFromPlaylist(playlist, track, snapshotId = snapshotId)
375375

376376
/**
@@ -384,9 +384,9 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
384384
* @param snapshotId The playlist snapshot against which to apply this action. **recommended to have**
385385
*/
386386
fun removeTracksFromPlaylist(
387-
playlist: String,
388-
vararg tracks: String,
389-
snapshotId: String? = null
387+
playlist: String,
388+
vararg tracks: String,
389+
snapshotId: String? = null
390390
) = removePlaylistTracksImpl(playlist, tracks.map { it to null }.toTypedArray(), snapshotId)
391391

392392
/**
@@ -400,29 +400,29 @@ class ClientPlaylistAPI(api: SpotifyAPI) : PlaylistAPI(api) {
400400
* @param snapshotId The playlist snapshot against which to apply this action. **recommended to have**
401401
*/
402402
fun removeTracksFromPlaylist(
403-
playlist: String,
404-
vararg tracks: Pair<String, SpotifyTrackPositions>,
405-
snapshotId: String? = null
403+
playlist: String,
404+
vararg tracks: Pair<String, SpotifyTrackPositions>,
405+
snapshotId: String? = null
406406
) = removePlaylistTracksImpl(playlist, tracks.toList().toTypedArray(), snapshotId)
407407

408408
private fun removePlaylistTracksImpl(
409-
playlist: String,
410-
tracks: Array<Pair<String, SpotifyTrackPositions?>>,
411-
snapshotId: String?
409+
playlist: String,
410+
tracks: Array<Pair<String, SpotifyTrackPositions?>>,
411+
snapshotId: String?
412412
): SpotifyRestAction<Snapshot> {
413413
return toAction(Supplier {
414414
if (tracks.isEmpty()) throw IllegalArgumentException("You need to provide at least one track to remove")
415415

416-
val json = JsonObject().apply { if (snapshotId != null) this["snapshot_id"] = snapshotId }
416+
val json = jsonMap().apply { if (snapshotId != null) this["snapshot_id"] = snapshotId }
417417

418418
tracks.map { (track, positions) ->
419-
JsonObject().apply {
419+
jsonMap().apply {
420420
this["uri"] = TrackURI(track).uri
421421
if (positions?.positions?.isNotEmpty() == true) this["positions"] = positions.positions
422422
}.also { if (positions?.positions?.isNotEmpty() == true) it["positions"] = positions }
423-
}.let { json.put("tracks", JsonArray(it)) }
423+
}.let { json.put("tracks", it) }
424424
delete(
425-
EndpointBuilder("/playlists/${PlaylistURI(playlist).id}/tracks").toString(), body = json.toJsonString()
425+
EndpointBuilder("/playlists/${PlaylistURI(playlist).id}/tracks").toString(), body = json.toJson()
426426
).toObject<Snapshot>(api)
427427
})
428428
}

src/main/kotlin/com/adamratzman/spotify/http/Endpoints.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ abstract class SpotifyEndpoint(val api: SpotifyAPI) {
100100
val message = try {
101101
document.body.toObject<ErrorResponse>(api).error
102102
} catch (e: Exception) {
103+
e.printStackTrace()
103104
ErrorObject(400, "malformed request sent")
104105
}
105106
throw BadRequestException(message)

0 commit comments

Comments
 (0)