Use Moshi as Android Json Library (Kotlin)

January 22, 2019
Include Retrofit integration

Why use Moshi?

NOTE: Faster than Gson, more lightweight than Jackson, “modern”, uses Okio library for optimization (used by OkHttp and Retrofit as well).

Dependencies

// https://mvnrepository.com/artifact/com.squareup.moshi/moshi-kotlin
def moshi_version = '1.8.0'

implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"

// Optional: generate small and fast adapter for each of your Kotlin classes 
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"

Proguard

Refer to Moshi R8 / ProGuard

Usage

Create Moshi object.

val moshi = Moshi.Builder()
      .add(KotlinJsonAdapterFactory())
      .add(LocalDateTimeAdapter())
      .add(MultipleFormatsDateAdapter())
      .build()

NOTE: Refer to Moshi DateTime Adapter With Multiple Format Support for LocalDateTimeAdapter and MultipleFormatsDateAdapter().

Create Moshi adapter to parse Json to object and vice versa.

var jsonString = "..."

// create adapter
val adapter = moshi.adapter<RateAppReminder>(RateAppReminder::class.java)
val item = adapter.fromJson(jsonString)
jsonString = adapter.toJson(item)

Json Class

@JsonClass(generateAdapter = true)
class RateAppReminder {
    class Reminder(val date: LocalDateTime, val sessionCount: Long)

    @Json(name = "last_reminder")
    var lastReminder: Reminder? = null

    @Json(name = "reminder_count")
    var reminderCount: Int = 0

    // isRated
    @Json(name = "is_done")
    var isDone: Boolean = false
}

NOTE: @JsonClass is optional, but do use it with moshi-kotlin-codegen for faster adapter generation.

NOTE: @Json is optional, but I like things to be more verbose and perfer snake_case as opposed to camelCase for json.

Integration with Retrofit

fun provideApiService(moshi: Moshi): ApiService {

    val okHttpClientBuilder = OkHttpClient.Builder()
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)

    if (BuildConfig.DEBUG) {
        val logging = HttpLoggingInterceptor()
        logging.level = HttpLoggingInterceptor.Level.BODY
        okHttpClientBuilder.addInterceptor(logging)
    }

    val retrofit = Retrofit.Builder()
            .baseUrl("https://api.mydomain.com")
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            // .addCallAdapterFactory(CoroutineCallAdapterFactory())
            .client(okHttpClientBuilder.build())
            .build()

    return retrofit.create(ApiService::class.java)
}
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.