Pasha Shkaran
Pasha Shkaran

Reputation: 1481

How use Kotlin enum with Retrofit?

How can I parse JSON to model with enum?

Here is my enum class:

enum class VehicleEnumEntity(val value: String) {
   CAR("vehicle"),
   MOTORCYCLE("motorcycle"),
   VAN("van"),
   MOTORHOME("motorhome"),
   OTHER("other")
}

and I need to parse type into an enum

"vehicle": { "data": { "type": "vehicle", "id": "F9dubDYLYN" } }

EDIT

I have tried standard way, just pass my enum to POJO and it always null

Upvotes: 39

Views: 25422

Answers (4)

MrArtyD
MrArtyD

Reputation: 190

If you are using kotlinx.serialization, then you simply need to mark your enum class as @Serializable and use @SerialName with it's values:

@Serializable
enum class VehicleEnumEntity(val value: String) {
   @SerialName("vehicle")
   CAR("vehicle"),

   @SerialName("motorcycle")
   MOTORCYCLE("motorcycle"),

   @SerialName("van")
   VAN("van"),

   @SerialName("motorhome")
   MOTORHOME("motorhome"),

   @SerialName("other")
   OTHER("other")
}

Upvotes: 2

In case the backend service responses integers for example. You can you change the constructor parameter as Int.

enum class Day(val rawValue: Int) {
    @SerializedName("1")
    SUNDAY(1),
    @SerializedName("2")
    MONDAY(2),
    @SerializedName("3")
    TUESDAY(3),
    @SerializedName("4")
    WEDNESDAY(4),
    @SerializedName("5")
    THURSDAY(5),
    @SerializedName("6")
    FRIDAY(6),
    @SerializedName("7")
    SATURDAY(7),
    @SerializedName("-1")
    UNSUPPORTED(-1);

    companion object {
        fun from(findValue: Int): Day = values().firstOrNull { it.rawValue == findValue } ?: UNSUPPORTED
    }
}

Nitpick: The from function helps you to find an enum value easily by a given Int.

Upvotes: 3

ephemient
ephemient

Reputation: 204778

Another option: use a custom (de)serializer that uses the value of the enum, instead of the name (default). This means you don't need to annotate every enum value, but instead you can annotate the enum class (or add the adapter to GsonBuilder).

interface HasValue {
    val value: String
}

@JsonAdapter(EnumByValueAdapter::class)
enum class VehicleEnumEntity(override val value: String): HasValue {
   CAR("vehicle"),
   MOTORCYCLE("motorcycle"),
   VAN("van"),
   MOTORHOME("motorhome"),
   OTHER("other")
}

class EnumByValueAdapter<T> : JsonDeserializer<T>, JsonSerializer<T>
    where T : Enum<T>, T : HasValue {
    private var values: Map<String, T>? = null

    override fun deserialize(
        json: JsonElement, type: Type, context: JsonDeserializationContext
    ): T? =
        (values ?: @Suppress("UNCHECKED_CAST") (type as Class<T>).enumConstants
            .associateBy { it.value }.also { values = it })[json.asString]

    override fun serialize(
        src: T, type: Type, context: JsonSerializationContext
    ): JsonElement = JsonPrimitive(src.value)
}

The same adapter class is reusable on other enum classes.

Upvotes: 16

LordRaydenMK
LordRaydenMK

Reputation: 13321

enum class VehicleEnumEntity(val value: String) {
   @SerializedName("vehicle")
   CAR("vehicle"),

   @SerializedName("motorcycle")
   MOTORCYCLE("motorcycle"),

   @SerializedName("van")
   VAN("van"),

   @SerializedName("motorhome")
   MOTORHOME("motorhome"),

   @SerializedName("other")
   OTHER("other")
}

Source

Upvotes: 97

Related Questions