Home > Back-end >  Kotlin Serialisation with Enum (kotlinx.serialisation library)
Kotlin Serialisation with Enum (kotlinx.serialisation library)

Time:01-17

I am using kotlinx.serialisation and had a question.

I have JSON like this:

{ 
    "state": "bad"
}

state can return bad|good|near_good

My State data class looks like this:

@Serializable
internal enum class State {
    @SerialName("good") GOOD,
    @SerialName("bad") BAD,
    @SerialName("near_good") NEAR_GOOD
}

Is it possible to have the enum names remain all caps like this, while parsing the json value that is returned? Right now when I test this, the parsed json data returns as GOOD|BAD|NEAR_GOOD, because the enum name is uppercase. Hopefully the question makes sense. Appreciate any answers.

EDIT (Updated for clarity)

Right now I have a test that checks: assert(state.name == "bad") This fails because with the way I mentioned it above (@SerialName("bad") BAD), the state.name is equal to 'BAD'. I want the enum name to be uppercase, as per enum naming convention, but I want the value to be lowercase as per the JSON. I can fix the failing test by changing it to be

@SerialName("bad") bad

I'm not sure if it is possible or maybe I am doing something in the wrong way, but I hope this clarifies.

Thanks!

CodePudding user response:

I guess the problem is your test. It's not very robust to check for string equality. You have powerful compile-time guarantees with enums, so I would suggest to just compare enum values, not strings:

assert(state == State.BAD)

If you're trying to test the serial name of the enum value, then... don't? That's the job of Kotlinx Serialization's tests to verify that the annotations work correctly.

CodePudding user response:

name is the wrong property to use for this purpose. It is documented as:

Returns the name of this enum constant, exactly as declared in its enum declaration.

What you could possibly do instead is to define a property (and, if you like, toString) for your enum class as follows:

val serialName =
    declaringJavaClass.getField(name)
        .getAnnotation(SerialName::class.java)
        .value

// optionally set toString
override fun toString() = serialName

And then you can print it like this: println(state.serialName)

Or like this: println(state)

But the real question is:

Why do you want to do that?

The whole point of the SerialName name annotation is to parse the serialized value to your enum variable, and to encode your enum variable to the serialized value. The value of your enum variable itself is independent from the serialized value and remains an object (State.BAD etc) rather than a string.

  • Related