Why use Moshi?
- https://www.reddit.com/r/androiddev/comments/684flw/why_use_moshi_over_gson/.
- https://stackoverflow.com/questions/43577623/moshi-vs-gson-in-android
- https://medium.com/@dannydamsky99/heres-why-you-probably-shouldn-t-be-using-the-gson-library-in-2018-4bed5698b78b
- https://www.youtube.com/watch?v=WvyScM_S88c
- https://github.com/square/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
- https://github.com/square/moshi/blob/master/moshi/src/main/resources/META-INF/proguard/moshi.pro
- https://github.com/square/moshi/blob/master/kotlin/reflect/src/main/resources/META-INF/proguard/moshi-kotlin.pro
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 adapterval 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)}