Kotlin Serialization Shenanigans
It’s been a while since I did some serialization implementation on Android. I forgot how painful this was to implement. This is for my future self, in case I reencounter this stupid shenanigans again.
Gradle Imports
First, import Retrofit, Kotlinx Serialization and Jake Wharton’s Retrofit Kotlinx Serialization Converter.
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
On the build.gradle
project level file, don’t forget to also add the dependency inside the plugin section.
plugins {
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.22" apply false
}
Back to your app level build.gradle
file, also add the dependency inside the plugin section.
plugins {
id("kotlinx-serialization")
}
Retrofit Helper Class
Your Retrofit helper class should be like below. Take note of the import statements.
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType
import retrofit2.Retrofit
object ApiHelper {
val baseApi = "https://api.somewebsite.com/"
private val contentType = MediaType.get("application/json")
fun getInstance(): Retrofit {
return Retrofit.Builder()
.baseUrl(baseApi)
.addConverterFactory(Json.asConverterFactory(contentType))
.build()
}
}
Proguard rules
Don’t forget about the proguard rules.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
static <1>$Companion Companion;
}
# Keep `serializer()` on companion objects (both default and named) of serializable classes.
-if @kotlinx.serialization.Serializable class ** {
static **$* *;
}
-keepclassmembers class <2>$<3> {
kotlinx.serialization.KSerializer serializer(...);
}
# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
public static ** INSTANCE;
}
-keepclassmembers class <1> {
public static <1> INSTANCE;
kotlinx.serialization.KSerializer serializer(...);
}
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
kotlinx.serialization.MissingFieldException
In your data class, it might seem that adding a nullable type to your variable is enough.
@Serializable
data class User(
@SerialName("user_id")
val userId: Int?
)
It’s not. You need to add a default null value.
@Serializable
data class User(
@SerialName("user_id")
val userId: Int? = null
)
Shoutout to Jere Schneider and tyczj for the helpful answers that can’t be found anywhere on Android’s documentation.