Kotlin / kotlinx.serialization

Kotlin multiplatform / multi-format serialization
Apache License 2.0
5.33k stars 618 forks source link

The built-in String type (JsonPrimitive/JsonLiteral) puts double quotes around the string value #2752

Closed Yuanuo closed 1 month ago

Yuanuo commented 1 month ago

Describe the bug

The string result obtained with the default base type of Json is incorrect.

This code:

val type = kotlinx.serialization.json.Json.parseToJsonElement("""{"type":"test","v":0}""").jsonObject["type"].toString()
println(type)
println(type == "test")

The result of the output is:

"test"
false

, which normally should be test, but it has its own double quotes.

To Reproduce

fun main() {
val type = kotlinx.serialization.json.Json.parseToJsonElement("""{"type":"test","v":0}""").jsonObject["type"].toString()
println(type)
println(type == "test")
}

Expected behavior What you expect is a real String, without double quotes

Environment

Yuanuo commented 1 month ago

Probably a fix from here?

https://github.com/Kotlin/kotlinx.serialization/blob/5e341923571ff477f781e63995c31ebef1747736/formats/json/commonMain/src/kotlinx/serialization/json/JsonElement.kt#L153-L156

lukellmann commented 1 month ago

You can use JsonPrimitive.content to get the unqoted string. Also not that all subtypes of JsonElement implement toString in such a way, that the resulting string is valid JSON. So I think this behavior is intended.

Yuanuo commented 1 month ago

(Json.parseToJsonElement("""{"type":"test","v":0}""").jsonObject["type"] as JsonPrimitive).content

That would look too unsightly, so I just used org.json.JSON

JSONObject("""{"type":"test","v":0}""")["type"]

lukellmann commented 1 month ago

(Json.parseToJsonElement("""{"type":"test","v":0}""").jsonObject["type"] as JsonPrimitive).content

That would look too unsightly, so I just used org.json.JSON

Like JsonElement.jsonObject, there is also JsonElement.jsonPrimitive.

sandwwraith commented 1 month ago

all subtypes of JsonElement implement toString in such a way, that the resulting string is valid JSON. So I think this behavior is intended.

This is correct. If you want to get string without quotes, use .jsonPrimitive.content

Yuanuo commented 1 month ago

It still doesn't look good in code image

Yuanuo commented 1 month ago

I think the value of a Json property should be the value itself.

A string is double-quoted just to keep it as it is inside the text, and should not have double-quoted marks at runtime.

However, when converting the original runtime values to text, this should be done by a third-party operator (often called a Builder or Convertor). Now toString() is only limited to one purpose for converting to text, which may not be right.

sandwwraith commented 1 month ago

But using toString() instead of a .content wouldn't change much: it is still .jsonObject["type"].jsonPrimitive.toString() or .jsonObject["type"].jsonPrimitive.content. This wordy approach was chosen because it gives you type safety in contrary with e.g. org.json.

I think the value of a Json property should be the value itself.

It is, .content gives you a value of this json primitive. This method could have been named .value.

Now toString() is only limited to one purpose for converting to text

What other purpose method that converts to a string can have? The idea is, that you do not need to perform complex operations to get Json out of JsonElement: Json.parseToJsonElement("""{"type":"test","a":42}""").toString() == """{"type":"test","a":42}"""