Skip to content

Commit b994572

Browse files
authored
Make empty objects and arrays collapsed in pretty print mode (#2506)
because it is a widespread convention. Fixes #2502
1 parent 7c62a79 commit b994572

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.json
6+
7+
import kotlinx.serialization.*
8+
import kotlin.test.*
9+
10+
class JsonPrettyPrintTest : JsonTestBase() {
11+
val fmt = Json(default) { prettyPrint = true; encodeDefaults = true }
12+
13+
@Serializable
14+
class Empty
15+
16+
@Serializable
17+
class A(val empty: Empty = Empty())
18+
19+
@Serializable
20+
class B(val prefix: String = "a", val empty: Empty = Empty(), val postfix: String = "b")
21+
22+
@Serializable
23+
class Recursive(val rec: Recursive?, val empty: Empty = Empty())
24+
25+
@Serializable
26+
class WithListRec(val rec: WithListRec?, val l: List<Int> = listOf())
27+
28+
@Serializable
29+
class WithDefaults(val x: String = "x", val y: Int = 0)
30+
31+
@Test
32+
fun testTopLevel() = parametrizedTest { mode ->
33+
assertEquals("{}", fmt.encodeToString(Empty(), mode))
34+
}
35+
36+
@Test
37+
fun testWithDefaults() = parametrizedTest { mode ->
38+
val dropDefaults = Json(fmt) { encodeDefaults = false }
39+
val s = "{\n \"boxed\": {}\n}"
40+
assertEquals(s, dropDefaults.encodeToString(Box(WithDefaults()), mode))
41+
}
42+
43+
@Test
44+
fun testPlain() = parametrizedTest { mode ->
45+
val s = """{
46+
| "empty": {}
47+
|}""".trimMargin()
48+
assertEquals(s, fmt.encodeToString(A(), mode))
49+
}
50+
51+
@Test
52+
fun testInside() = parametrizedTest { mode ->
53+
val s = """{
54+
| "prefix": "a",
55+
| "empty": {},
56+
| "postfix": "b"
57+
|}""".trimMargin()
58+
assertEquals(s, fmt.encodeToString(B(), mode))
59+
}
60+
61+
@Test
62+
fun testRecursive() = parametrizedTest { mode ->
63+
val obj = Recursive(Recursive(null))
64+
val s = "{\n \"rec\": {\n \"rec\": null,\n \"empty\": {}\n },\n \"empty\": {}\n}"
65+
assertEquals(s, fmt.encodeToString(obj, mode))
66+
}
67+
68+
@Test
69+
fun test() = parametrizedTest { mode ->
70+
val obj = WithListRec(WithListRec(null), listOf(1, 2, 3))
71+
val s =
72+
"{\n \"rec\": {\n \"rec\": null,\n \"l\": []\n },\n \"l\": [\n 1,\n 2,\n 3\n ]\n}"
73+
assertEquals(s, fmt.encodeToString(obj, mode))
74+
}
75+
}

formats/json/commonMain/src/kotlinx/serialization/json/internal/Composers.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ internal open class Composer(@JvmField internal val writer: InternalJsonWriter)
2727
writingFirst = false
2828
}
2929

30+
open fun nextItemIfNotFirst() {
31+
writingFirst = false
32+
}
33+
3034
open fun space() = Unit
3135

3236
fun print(v: Char) = writer.writeChar(v)
@@ -88,6 +92,11 @@ internal class ComposerWithPrettyPrint(
8892
repeat(level) { print(json.configuration.prettyPrintIndent) }
8993
}
9094

95+
override fun nextItemIfNotFirst() {
96+
if (writingFirst) writingFirst = false
97+
else nextItem()
98+
}
99+
91100
override fun space() {
92101
print(' ')
93102
}

formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ internal class StreamingJsonEncoder(
9696
override fun endStructure(descriptor: SerialDescriptor) {
9797
if (mode.end != INVALID) {
9898
composer.unIndent()
99-
composer.nextItem()
99+
composer.nextItemIfNotFirst()
100100
composer.print(mode.end)
101101
}
102102
}

0 commit comments

Comments
 (0)