Skip to content

Value class cannot be used as JSON map key #1459

@brianguertin

Description

@brianguertin

Describe the bug
kotlinx.serialization.json.internal.JsonEncodingException: Value of type 'MyId' can't be used in JSON as a key in the map. It should have either primitive or enum kind, but its kind is 'CLASS'. Use 'allowStructuredMapKeys = true' in 'Json {}' builder to convert such maps to [key1, value1, key2, value2,...] arrays.

To Reproduce

@JvmInline
@Serializable
value class MyId(val id: String)

@Serializable
data class MyObject {
   val myMap: Map<MyId, Double>? = null
}

Json().decodeFromString(MyObject.serializer(), """{"myMap":{"hello", 1.0}}""")

Expected behavior
Since value classes are supposed to be (de)serialized by kotlinx.serialization as their underlying value, I would expect MyId to be usable anywhere that String is normally usable, such as the keys in a map.

Workaround is to use a serializer that mimics what kotlinx.serialization already does for value classes, but explicitly makes it a "primitive", such as:

object MyIdSerializer: KSerializer<MyId> {
    override val descriptor = PrimitiveSerialDescriptor("MyId", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: MyId) {
        encoder.encodeString(value.id)
    }
    override fun deserialize(decoder: Decoder): MyId {
        return MyId(decoder.decodeString())
    }
}

Environment

  • Kotlin version: [e.g. 1.5.0]
  • Library version: [e.g. 1.2.0]
  • Kotlin platforms: JVM, JS, Native
  • Gradle version: 4.7

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions