Explain Codes LogoExplain Codes Logo

Kotlin Data Class from Json using GSON

kotlin
gson
data-class
json-parsing
Alex KataevbyAlex Kataev·Sep 18, 2024
TLDR

Here's how to transform a JSON into a Kotlin data class using GSON:

  1. Use @SerializedName to adjust data class properties per JSON keys.
  2. Build an instance of Gson.
  3. Utilize fromJson, sending your JSON string and a class reference .java.

Please observe the provided example:

// Smell the Java in Kotlin through Gson! import com.google.gson.annotations.SerializedName import com.google.gson.Gson data class UserProfile( @SerializedName("firstName") val name: String, @SerializedName("careerYears") val years: Int ) // Who needs caffeine? Not Gson, it's on fire! val gson = Gson() val jsonInput = """{"firstName": "Java", "careerYears": 25}""" val profile: UserProfile = gson.fromJson(jsonInput, UserProfile::class.java)

Make sure to have GSON on the list of your project's dependencies.

dependencies { implementation 'com.google.code.gson:gson:2.8.8' }

Default parameter values and Nullability

Kotlin is known for its null safety, when working with JSON, fields might be missing or null. Add default values to your data classes and use nullable properties when needed:

data class UserProfile( @SerializedName("firstName") val name: String = "John Doe", // Default value? Check! @SerializedName("careerYears") val years: Int? = null // Nullable age property )

Nested JSON objects

Sometimes JSON isn't flat like a pancake but more like a layered cake, that's when we need to handle nested JSON objects.

// Define Address class data class Address( @SerializedName("street") val street: String, @SerializedName("city") val city: String ) //Stuffing an address inside User data class UserProfile( @SerializedName("firstName") val name: String, @SerializedName("careerYears") val years: Int, @SerializedName("address") val address: Address )

Controlling Serialization with @Expose

With @Expose and @SerializedName together, you can customize the serialization and deserialization process:

// Exposing the concealed import com.google.gson.annotations.Expose data class UserProfile( @Expose @SerializedName("firstName") val name: String, // This age is shy, @Expose without serialize = false will control its exposure @Expose(serialize = false) @SerializedName("careerYears") val years: Int ) // @Expose without serialize = false, hides 'age' during serialization val userProfile = UserProfile("Java", 25) val jsonOutput = gson.toJson(userProfile) // {"firstName": "Java"} Pfft... Age hiding in action!

Transforming a Kotlin data class back to JSON is as simple as using Gson.toJson.

val profileJson = gson.toJson(userProfile)

Generics and TypeToken in JSON

Working with Generics in GSON? TypeToken to the rescue.

import com.google.gson.reflect.TypeToken import java.lang.reflect.Type data class ApiResponse<T>( @SerializedName("data") val data: T ) val jsonString = """{"data": [{"firstName": "Java", "careerYears": 25}, ...]}""" val type: Type = object : TypeToken<ApiResponse<List<UserProfile>>>() {}.type val response: ApiResponse<List<UserProfile>> = gson.fromJson(jsonString, type)

Fun with Kotlin Features

Kotlin's extension functions and inline functions with reified types can make JSON parsing a fun ride!

inline fun <reified T> Gson.fromJson(json: String): T = this.fromJson(json, T::class.java) // Use the inline function for the cool kids' code style val userProfile: UserProfile = gson.fromJson(jsonInput)

Mind the Naming

Just as a nicely named variable can be a lifesaver, clear and consistent naming in your data classes aligns with Kotlin's design philosophies, making your JSON parsing code both airy and sturdy.

Matching Versions Tiger Style

Beware of the version dragons, compatible versions of Gson library, Android Studio, and Kotlin will slay them instantly.