Skip to content

Misleading IndexOutOfBoundsException when decoding JsonElement as primitive #1766

Open
@rgmz

Description

@rgmz

Description

I encountered a confusing exception when writing JsonElement-related tests. I don't know how likely someone would be to stumble across this in the wild.

While it isn't a bug per se, the exception message could be clarified to point out the actual failure cause.

java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 0
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.remove(ArrayList.java:536)
	at kotlinx.serialization.internal.TaggedDecoder.popTag(Tagged.kt:321)
	at kotlinx.serialization.internal.TaggedDecoder.decodeBoolean(Tagged.kt:223)
	at kotlinx.serialization.internal.BooleanSerializer.deserialize(Primitives.kt:86)
	at kotlinx.serialization.internal.BooleanSerializer.deserialize(Primitives.kt:82)
	at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:59)
	at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeSerializableValue(TreeJsonDecoder.kt:51)
	at kotlinx.serialization.json.internal.TreeJsonDecoderKt.readJson(TreeJsonDecoder.kt:24)
	at kotlinx.serialization.json.Json.decodeFromJsonElement(Json.kt:119)

To Reproduce

Consider the following (contrived) code:

fun main() {
    val jsonString = JsonPrimitive("bar")
    val jsonObject = JsonObject(mapOf("foo" to jsonString))
    val jsonArray = JsonArray(listOf(jsonObject))

    listOf(jsonString, jsonObject, jsonArray).forEach { element ->
      runCatching { Json.decodeFromJsonElement<String>(element) }
         .fold(
            onSuccess = {  println("Value is: $value") },
            onFailure = {  println("Could not decode element: ${it.message}")  }
        )
    }
}

Attempting to decode JsonObject or JsonArray as a primitive (String, Boolean, Long, etc.) will yield the confusing error mentioned above.

protected fun popTag(): Tag {
val r = tagStack.removeAt(tagStack.lastIndex)
flag = true
return r
}

Expected behavior

Provide a meaningful exception, if possible. For example, attempting to decode a JsonObject or JsonArray as a JsonPrimitive yields a more friendly error:

kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON element, expected JsonPrimitive, had class kotlinx.serialization.json.JsonObject
JSON input: {}
	at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:24)
	at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:32)
	at kotlinx.serialization.json.JsonPrimitiveSerializer.deserialize(JsonElementSerializers.kt:76)
	at kotlinx.serialization.json.JsonPrimitiveSerializer.deserialize(JsonElementSerializers.kt:59)
	at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:59)
	at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeSerializableValue(TreeJsonDecoder.kt:51)
	at kotlinx.serialization.json.internal.TreeJsonDecoderKt.readJson(TreeJsonDecoder.kt:24)
	at kotlinx.serialization.json.Json.decodeFromJsonElement(Json.kt:119)

Environment

  • Kotlin version: 1.5.31
  • Library version: 1.3.0
  • Kotlin platforms: Jvm

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions