How to handle JSON with polymorphic types using GSON in Kotlin Android
How to handle JSON with polymorphic types using GSON in Kotlin Android.
In this tutorial, we will learn how to handle JSON with polymorphic types using the GSON library in Kotlin for Android development. Polymorphic types refer to a scenario where a JSON object can have multiple different types based on a certain condition or property.
Step 1: Add GSON dependency to your project
First, you need to add the GSON dependency to your build.gradle
file:
dependencies {
implementation 'com.google.code.gson:gson:2.8.7'
}
Sync your project to make sure the dependency is downloaded and available for use.
Step 2: Define your JSON data classes
Next, you need to define your data classes that represent the JSON structure. Let's consider an example where we have a Shape
class hierarchy with Circle
, Rectangle
, and Triangle
subclasses.
sealed class Shape
data class Circle(val radius: Double) : Shape()
data class Rectangle(val width: Double, val height: Double) : Shape()
data class Triangle(val base: Double, val height: Double) : Shape()
In this example, Shape
is declared as a sealed class, which means all its subclasses must be declared within the same file. Each subclass represents a specific shape with its corresponding properties.
Step 3: Create a custom GSON TypeAdapter
To handle polymorphic types, we need to create a custom TypeAdapter
for GSON. A TypeAdapter
is responsible for serializing and deserializing JSON objects to and from Java/Kotlin objects.
import com.google.gson.Gson
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
class ShapeTypeAdapterFactory : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (!Shape::class.java.isAssignableFrom(type.rawType)) {
return null
}
return ShapeTypeAdapter(gson) as TypeAdapter<T>
}
}
class ShapeTypeAdapter(private val gson: Gson) : TypeAdapter<Shape>() {
override fun write(out: JsonWriter?, value: Shape?) {
// Implement serialization if needed
}
override fun read(reader: JsonReader?): Shape? {
if (reader == null) {
return null
}
if (reader.peek() == JsonToken.NULL) {
reader.nextNull()
return null
}
reader.beginObject()
reader.nextName() // Assuming the shape type is specified as a property
val shapeType = reader.nextString()
val shape = when (shapeType) {
"Circle" -> gson.fromJson(reader, Circle::class.java)
"Rectangle" -> gson.fromJson(reader, Rectangle::class.java)
"Triangle" -> gson.fromJson(reader, Triangle::class.java)
else -> null
}
reader.endObject()
return shape
}
}
In this example, we create a custom ShapeTypeAdapterFactory
that implements the TypeAdapterFactory
interface. It checks if the given type is assignable to Shape
and returns a ShapeTypeAdapter
instance if true.
The ShapeTypeAdapter
is responsible for deserializing JSON objects into the corresponding Shape
subclasses. It reads the shape type from the JSON object and uses gson.fromJson
to deserialize the remaining properties based on the shape type.
Step 4: Register the custom TypeAdapterFactory
To make GSON aware of our custom TypeAdapterFactory
, we need to register it when creating a GSON instance.
val gson = GsonBuilder()
.registerTypeAdapterFactory(ShapeTypeAdapterFactory())
.create()
In this example, we create a new GsonBuilder
and register our ShapeTypeAdapterFactory
using the registerTypeAdapterFactory
method. Finally, we call create
to build the GSON instance.
Step 5: Serialize and deserialize JSON with polymorphic types
Now that we have set up the GSON configuration, we can use it to serialize and deserialize JSON objects that contain polymorphic types.
// Serializing a Shape object to JSON
val circle = Circle(5.0)
val json = gson.toJson(circle)
println(json) // Output: {"radius":5.0}
// Deserializing JSON to a Shape object
val json = "{\"radius\":5.0}"
val shape = gson.fromJson(json, Shape::class.java)
println(shape) // Output: Circle(radius=5.0)
In this example, we serialize a Circle
object to JSON using gson.toJson
, and then deserialize it back to a Shape
object using gson.fromJson
.
Conclusion
In this tutorial, we learned how to handle JSON with polymorphic types using the GSON library in Kotlin for Android development. We created a custom TypeAdapter
and TypeAdapterFactory
to handle the serialization and deserialization of polymorphic types. By following these steps, you can easily handle complex JSON structures with polymorphic types in your Android applications.