Serialize enum field into JSON in Kotlin

Viewed 7342

I've got a stupid question that stunned me a bit. I have an enum and a data class like this:

enum class MyEventType(val typeName: String) {
    FIRST("firstEventReceived")
}

data class MyEvent(
    val id: String,
    val event: MyEventType
)

I need to send this as a json string, but common desearilizer makes such a json

{ 
    "id": "identifier",
    "event": "FIRST"
}

but i need

{ 
    "id": "identifier",
    "event": "firstEventReceived"
}

As far as i understand, kotlin allows to override getter in data class, but i didn't succeed in it... Trying to make

data class MyEvent(
    val id: String
) {
    val event: MyEventType get() event.typeName
}

but i've missed something, i guess...

3 Answers

The simplest way is probably to annotate the property with @JsonValue:

enum class MyEventType(@JsonValue val typeName: String) {
    FIRST("firstEventReceived")
}

data class MyEvent(
    val id: String,
    val event: MyEventType
)


fun main() {
    MyEvent(id = "foo", event = MyEventType.FIRST)
        .let { jacksonObjectMapper().writeValueAsString(it) }
        .let { println(it) }
}

Prints:

{"id":"foo","event":"firstEventReceived"}

The easiest way is to annotate the typeName with @JsonValue. This will serialise and deserialise the enum field as you want.

enum class MyEventType(@JsonValue val typeName: String) {
    FIRST("firstEventReceived");
}

An alternative is to use @JsonFormat (if you are using jackson version < 2.9);


enum class MyEventType(@JsonFormat(shape = JsonFormat.Shape.OBJECT) val typeName: String) {
    FIRST("firstEventReceived");
}

Herer's an example;

  @JvmStatic
    fun main(args: Array<String>) {
        val mapper = jacksonObjectMapper()
        val json = mapper.writeValueAsString(MyEvent("1", MyEventType.FIRST))
        println(json)

        val event = mapper.readValue<MyEvent>(json)
        println(event)
    }

You get the output;

{"id":"1","event":"firstEventReceived"}
MyEvent(id=1, event=FIRST)

I used Jackson version 2.12.0. Here's a good read on enum manipulation with Jackson - https://www.baeldung.com/jackson-serialize-enums

Also you can have enum with 2+ fields which you want to be serialized

enum class MyEventType(
        val firstField: String,
        val secondField: String,
        val thirdField: String
) {
        MY_ENUM("firstFieldValue", "secondFieldValue", "thirdFieldValue")
}

You can chose one of the following two options:

  1. Put @JsonValue over a method(lets call it getter) that will return the required value(if you need only part of the fields):

    @JsonValue
    fun getSerializedObject(): String {
            return "{firstField: $firstField, thirdField: $thirdField}"
    }
    

    Result will be "{firstField: firstFieldValue, thirdField: thirdFieldValue}"

  2. Put @JsonFormat(shape = JsonFormat.Shape.OBJECT) over your enum class(for serialization class as common class):

     @JsonFormat(shape = JsonFormat.Shape.OBJECT)
     enum class MyEventType(
             val firstField: String,
             val secondField: String,
             val thirdField: String
     ) {
             MY_ENUM("firstField", "secondField", "thirdField")
     }
    

    Result will be "{"firstField": "firstFieldValue", "secondField": "secondFieldValue", "thirdField": "thirdFieldValue"}"

Related