1 /*
2 * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4 @file:OptIn(ExperimentalContracts::class)
5
6 package kotlinx.serialization.json
7
8 import kotlinx.serialization.ExperimentalSerializationApi
9 import kotlin.contracts.*
10 import kotlin.jvm.JvmName
11
12 /**
13 * Builds [JsonObject] with the given [builderAction] builder.
14 * Example of usage:
15 * ```
16 * val json = buildJsonObject {
17 * put("booleanKey", true)
18 * putJsonArray("arrayKey") {
19 * for (i in 1..10) add(i)
20 * }
21 * putJsonObject("objectKey") {
22 * put("stringKey", "stringValue")
23 * }
24 * }
25 * ```
26 */
buildJsonObjectnull27 public inline fun buildJsonObject(builderAction: JsonObjectBuilder.() -> Unit): JsonObject {
28 contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
29 val builder = JsonObjectBuilder()
30 builder.builderAction()
31 return builder.build()
32 }
33
34
35 /**
36 * Builds [JsonArray] with the given [builderAction] builder.
37 * Example of usage:
38 * ```
39 * val json = buildJsonArray {
40 * add(true)
41 * addJsonArray {
42 * for (i in 1..10) add(i)
43 * }
44 * addJsonObject {
45 * put("stringKey", "stringValue")
46 * }
47 * }
48 * ```
49 */
buildJsonArraynull50 public inline fun buildJsonArray(builderAction: JsonArrayBuilder.() -> Unit): JsonArray {
51 contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
52 val builder = JsonArrayBuilder()
53 builder.builderAction()
54 return builder.build()
55 }
56
57 /**
58 * DSL builder for a [JsonObject]. To create an instance of builder, use [buildJsonObject] build function.
59 */
60 @JsonDslMarker
61 public class JsonObjectBuilder @PublishedApi internal constructor() {
62
63 private val content: MutableMap<String, JsonElement> = linkedMapOf()
64
65 /**
66 * Add the given JSON [element] to a resulting JSON object using the given [key].
67 *
68 * Returns the previous value associated with [key], or `null` if the key was not present.
69 */
putnull70 public fun put(key: String, element: JsonElement): JsonElement? = content.put(key, element)
71
72 @PublishedApi
73 internal fun build(): JsonObject = JsonObject(content)
74 }
75
76 /**
77 * Add the [JSON object][JsonObject] produced by the [builderAction] function to a resulting JSON object using the given [key].
78 *
79 * Returns the previous value associated with [key], or `null` if the key was not present.
80 */
81 public fun JsonObjectBuilder.putJsonObject(key: String, builderAction: JsonObjectBuilder.() -> Unit): JsonElement? =
82 put(key, buildJsonObject(builderAction))
83
84 /**
85 * Add the [JSON array][JsonArray] produced by the [builderAction] function to a resulting JSON object using the given [key].
86 *
87 * Returns the previous value associated with [key], or `null` if the key was not present.
88 */
89 public fun JsonObjectBuilder.putJsonArray(key: String, builderAction: JsonArrayBuilder.() -> Unit): JsonElement? =
90 put(key, buildJsonArray(builderAction))
91
92 /**
93 * Add the given boolean [value] to a resulting JSON object using the given [key].
94 *
95 * Returns the previous value associated with [key], or `null` if the key was not present.
96 */
97 public fun JsonObjectBuilder.put(key: String, value: Boolean?): JsonElement? = put(key, JsonPrimitive(value))
98
99 /**
100 * Add the given numeric [value] to a resulting JSON object using the given [key].
101 *
102 * Returns the previous value associated with [key], or `null` if the key was not present.
103 */
104 public fun JsonObjectBuilder.put(key: String, value: Number?): JsonElement? = put(key, JsonPrimitive(value))
105
106 /**
107 * Add the given string [value] to a resulting JSON object using the given [key].
108 *
109 * Returns the previous value associated with [key], or `null` if the key was not present.
110 */
111 public fun JsonObjectBuilder.put(key: String, value: String?): JsonElement? = put(key, JsonPrimitive(value))
112
113 /**
114 * Add `null` to a resulting JSON object using the given [key].
115 *
116 * Returns the previous value associated with [key], or `null` if the key was not present.
117 */
118 @ExperimentalSerializationApi
119 @Suppress("UNUSED_PARAMETER") // allows to call `put("key", null)`
120 public fun JsonObjectBuilder.put(key: String, value: Nothing?): JsonElement? = put(key, JsonNull)
121
122 /**
123 * DSL builder for a [JsonArray]. To create an instance of builder, use [buildJsonArray] build function.
124 */
125 @JsonDslMarker
126 public class JsonArrayBuilder @PublishedApi internal constructor() {
127
128 private val content: MutableList<JsonElement> = mutableListOf()
129
130 /**
131 * Adds the given JSON [element] to a resulting JSON array.
132 *
133 * Always returns `true` similarly to [ArrayList] specification.
134 */
135 public fun add(element: JsonElement): Boolean {
136 content += element
137 return true
138 }
139
140 /**
141 * Adds the given JSON [elements] to a resulting JSON array.
142 *
143 * @return `true` if the list was changed as the result of the operation.
144 */
145 @ExperimentalSerializationApi
146 public fun addAll(elements: Collection<JsonElement>): Boolean =
147 content.addAll(elements)
148
149 @PublishedApi
150 internal fun build(): JsonArray = JsonArray(content)
151 }
152
153 /**
154 * Adds the given boolean [value] to a resulting JSON array.
155 *
156 * Always returns `true` similarly to [ArrayList] specification.
157 */
addnull158 public fun JsonArrayBuilder.add(value: Boolean?): Boolean = add(JsonPrimitive(value))
159
160 /**
161 * Adds the given numeric [value] to a resulting JSON array.
162 *
163 * Always returns `true` similarly to [ArrayList] specification.
164 */
165 public fun JsonArrayBuilder.add(value: Number?): Boolean = add(JsonPrimitive(value))
166
167 /**
168 * Adds the given string [value] to a resulting JSON array.
169 *
170 * Always returns `true` similarly to [ArrayList] specification.
171 */
172 public fun JsonArrayBuilder.add(value: String?): Boolean = add(JsonPrimitive(value))
173
174 /**
175 * Adds `null` to a resulting JSON array.
176 *
177 * Always returns `true` similarly to [ArrayList] specification.
178 */
179 @ExperimentalSerializationApi
180 @Suppress("UNUSED_PARAMETER") // allows to call `add(null)`
181 public fun JsonArrayBuilder.add(value: Nothing?): Boolean = add(JsonNull)
182
183 /**
184 * Adds the [JSON object][JsonObject] produced by the [builderAction] function to a resulting JSON array.
185 *
186 * Always returns `true` similarly to [ArrayList] specification.
187 */
188 public fun JsonArrayBuilder.addJsonObject(builderAction: JsonObjectBuilder.() -> Unit): Boolean =
189 add(buildJsonObject(builderAction))
190
191 /**
192 * Adds the [JSON array][JsonArray] produced by the [builderAction] function to a resulting JSON array.
193 *
194 * Always returns `true` similarly to [ArrayList] specification.
195 */
196 public fun JsonArrayBuilder.addJsonArray(builderAction: JsonArrayBuilder.() -> Unit): Boolean =
197 add(buildJsonArray(builderAction))
198
199 /**
200 * Adds the given string [values] to a resulting JSON array.
201 *
202 * @return `true` if the list was changed as the result of the operation.
203 */
204 @JvmName("addAllStrings")
205 @ExperimentalSerializationApi
206 public fun JsonArrayBuilder.addAll(values: Collection<String?>): Boolean =
207 addAll(values.map(::JsonPrimitive))
208
209 /**
210 * Adds the given boolean [values] to a resulting JSON array.
211 *
212 * @return `true` if the list was changed as the result of the operation.
213 */
214 @JvmName("addAllBooleans")
215 @ExperimentalSerializationApi
216 public fun JsonArrayBuilder.addAll(values: Collection<Boolean?>): Boolean =
217 addAll(values.map(::JsonPrimitive))
218
219 /**
220 * Adds the given numeric [values] to a resulting JSON array.
221 *
222 * @return `true` if the list was changed as the result of the operation.
223 */
224 @JvmName("addAllNumbers")
225 @ExperimentalSerializationApi
226 public fun JsonArrayBuilder.addAll(values: Collection<Number?>): Boolean =
227 addAll(values.map(::JsonPrimitive))
228
229 @DslMarker
230 internal annotation class JsonDslMarker
231