Json Enum deserialization breakes kotlin null-safety

I use Kotlin data classes and GSON to deserialize JSON schemas, and implement default values to protect against null-objects in JSON. Also- JSON int enums map to Kotlin enum values using the @SerializedName annotation:

data class Person(@SerializedName("name")
           val name: String = ",
           @SerializedName("age")
           val age: Int = 0,
           @SerializedName("hairColor")
           val hairColor: Color = Color.NONE)

enum class Color{
    @SerializedName("1")
    BROWN,
    @SerializedName("2")
    BLONDE,
    NONE
}

Focusing on enum deserialization- this works well for situations when a field matches a known enum or if the field is totally absent from the JSON, in which case the default enum will be implemented.

BUT - if the received enum in JSON doesn’t map to a known enum value in my kotlin enum - the resulting deserialized enum will be null!!

{"name":"Joe","age":10,"hairColor":1} ->
Person(name=Joe, age=10, hairColor=BROWN)

{"name":"Jim"} ->
Person(name=Jim, age=0, hairColor=NONE)

{"name":"Jeff", "age":8,"hairColor":3) ->
Person(name=Jane, age=8, hairColor=null)

Gson fools the null safety mechanism of Kotlin by assigning null to a non-null type.

P.S. - I know I could just parse JSON enums as Ints, and deserialize them later, or use backing fields and custom getters, but the null-safety guaranty of kotlin is being broken here.

As described in this issue, when it comes to enums, GSON deserializes invalid strings (and apparently also numbers) as null. For missing values, however, GSON by default just skips them, leaving the default initialized value as it is.

As for breaking Kotlins null safety, GSON uses reflection to assign directly to the fields of the returned object, rather than calling a setter. Kotlin has no way of ensuring null safety against libraries that do that.

1 Like

I realize this is a GSON issue, not Kotlin. But it may be valuable to supply a Lint check for such cases for future naive users.
Me think that if Kotlin guaraneets null-safety, it should at least warn us where it can’t.