Skip to content

JSON: Decode nullable enum property from JsonElement with non-explicit nulls throws NoSuchElementException #2931

Closed
@damianw

Description

@damianw

When decoding a nullable enum property from a JsonElement, using explicitNulls = false, the absence of the field results in deserialization throwing a NoSuchElementException with message Key ... is missing in the map..

This behavior appears specific to 1) decoding from a JsonElement and 2) the property being an enum. The same problem doesn't occur either when decoding from string, or when the property is any other kind of type.

To Reproduce

The below sample can be ran directly on the Kotlin Playground here.

package sample

import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.put
import kotlinx.serialization.json.Json
import kotlinx.serialization.Serializable

@Serializable
data class Thing(
    val required: String,
    val nullable: Type?,
)

@Serializable
enum class Type {
    FOO,
    BAR,
}

fun main() {
    val json = Json {
        coerceInputValues = true
        ignoreUnknownKeys = true
        encodeDefaults = true
        explicitNulls = false
    }
    val element = buildJsonObject {
        put("required", "blah")
    }
    val result = json.decodeFromJsonElement<Thing>(element)
    println(result)
}

Exception:

Exception in thread "main" java.util.NoSuchElementException: Key nullable is missing in the map.
 at kotlin.collections.MapsKt__MapWithDefaultKt.getOrImplicitDefaultNullable (MapWithDefault.kt:24) 
 at kotlin.collections.MapsKt__MapsKt.getValue (Maps.kt:369) 
 at kotlinx.serialization.json.internal.JsonTreeDecoder.currentElement (TreeJsonDecoder.kt:255) 

Expected behavior

Decoding the JsonObject should not throw an exception; instead it should default the value of nullable to null. This works correctly when using decodeFromString: if the val result = ... line in the reproduction sample is changed to val result = json.decodeFromString<Thing>("""{"required": "blah"}"""), the test passes successfully.

Environment

  • Kotlin version: 2.0.20 in local reproduction project, 2.1.10 in Kotlin Playground
  • Library version: 1.7.3 in local reproduction project, unknown in Kotlin Playground (probably 1.8.0)
  • Kotlin platforms: JVM, JS
  • Gradle version: N/A

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions