0
# DSL Builders
1
2
Kotlin DSL for building JSON structures programmatically with type-safe, fluent APIs. The builder DSL provides an intuitive way to construct JsonObject and JsonArray instances without manually managing collections.
3
4
## Capabilities
5
6
### JsonObject Builder
7
8
Create JsonObject instances using a type-safe builder DSL.
9
10
```kotlin { .api }
11
/**
12
* Build a JsonObject using a type-safe DSL
13
* @param builderAction Lambda with receiver for JsonObjectBuilder
14
* @return Constructed JsonObject
15
*/
16
fun buildJsonObject(builderAction: JsonObjectBuilder.() -> Unit): JsonObject
17
18
/**
19
* Builder for constructing JsonObject instances
20
*/
21
class JsonObjectBuilder {
22
/**
23
* Put a JsonElement value for the given key
24
* @param key Property name
25
* @param element JsonElement value to store
26
* @return Previous value associated with key, or null
27
*/
28
fun put(key: String, element: JsonElement): JsonElement?
29
30
/**
31
* Put a Boolean value for the given key
32
* @param key Property name
33
* @param value Boolean value to store (null creates JsonNull)
34
* @return Previous value associated with key, or null
35
*/
36
fun put(key: String, value: Boolean?): JsonElement?
37
38
/**
39
* Put a Number value for the given key
40
* @param key Property name
41
* @param value Number value to store (null creates JsonNull)
42
* @return Previous value associated with key, or null
43
*/
44
fun put(key: String, value: Number?): JsonElement?
45
46
/**
47
* Put a String value for the given key
48
* @param key Property name
49
* @param value String value to store (null creates JsonNull)
50
* @return Previous value associated with key, or null
51
*/
52
fun put(key: String, value: String?): JsonElement?
53
54
/**
55
* Put a null value for the given key
56
* @param key Property name
57
* @param value Must be null
58
* @return Previous value associated with key, or null
59
*/
60
@ExperimentalSerializationApi
61
fun put(key: String, value: Nothing?): JsonElement?
62
63
/**
64
* Put a nested JsonObject for the given key using builder DSL
65
* @param key Property name
66
* @param builderAction Lambda to build nested JsonObject
67
* @return Previous value associated with key, or null
68
*/
69
fun putJsonObject(key: String, builderAction: JsonObjectBuilder.() -> Unit): JsonElement?
70
71
/**
72
* Put a nested JsonArray for the given key using builder DSL
73
* @param key Property name
74
* @param builderAction Lambda to build nested JsonArray
75
* @return Previous value associated with key, or null
76
*/
77
fun putJsonArray(key: String, builderAction: JsonArrayBuilder.() -> Unit): JsonElement?
78
}
79
```
80
81
**Usage Examples:**
82
83
```kotlin
84
import kotlinx.serialization.json.*
85
86
// Basic object construction
87
val userJson = buildJsonObject {
88
put("id", 1)
89
put("name", "Alice")
90
put("email", "alice@example.com")
91
put("active", true)
92
put("lastLogin", null as String?) // Creates JsonNull
93
}
94
95
// Nested objects and arrays
96
val productJson = buildJsonObject {
97
put("id", 12345)
98
put("name", "Laptop")
99
put("price", 999.99)
100
101
putJsonObject("specifications") {
102
put("cpu", "Intel i7")
103
put("ram", "16GB")
104
put("storage", "512GB SSD")
105
}
106
107
putJsonArray("tags") {
108
add("electronics")
109
add("computers")
110
add("portable")
111
}
112
113
putJsonArray("reviews") {
114
addJsonObject {
115
put("author", "John")
116
put("rating", 5)
117
put("comment", "Great laptop!")
118
}
119
addJsonObject {
120
put("author", "Jane")
121
put("rating", 4)
122
put("comment", "Good value")
123
}
124
}
125
}
126
127
// Result:
128
// {
129
// "id": 12345,
130
// "name": "Laptop",
131
// "price": 999.99,
132
// "specifications": {
133
// "cpu": "Intel i7",
134
// "ram": "16GB",
135
// "storage": "512GB SSD"
136
// },
137
// "tags": ["electronics", "computers", "portable"],
138
// "reviews": [
139
// {"author": "John", "rating": 5, "comment": "Great laptop!"},
140
// {"author": "Jane", "rating": 4, "comment": "Good value"}
141
// ]
142
// }
143
```
144
145
### JsonArray Builder
146
147
Create JsonArray instances using a type-safe builder DSL.
148
149
```kotlin { .api }
150
/**
151
* Build a JsonArray using a type-safe DSL
152
* @param builderAction Lambda with receiver for JsonArrayBuilder
153
* @return Constructed JsonArray
154
*/
155
fun buildJsonArray(builderAction: JsonArrayBuilder.() -> Unit): JsonArray
156
157
/**
158
* Builder for constructing JsonArray instances
159
*/
160
class JsonArrayBuilder {
161
/**
162
* Add a JsonElement to the array
163
* @param element JsonElement to add
164
* @return Always true (consistent with MutableList.add)
165
*/
166
fun add(element: JsonElement): Boolean
167
168
/**
169
* Add a Boolean value to the array
170
* @param value Boolean value to add (null creates JsonNull)
171
* @return Always true
172
*/
173
fun add(value: Boolean?): Boolean
174
175
/**
176
* Add a Number value to the array
177
* @param value Number value to add (null creates JsonNull)
178
* @return Always true
179
*/
180
fun add(value: Number?): Boolean
181
182
/**
183
* Add a String value to the array
184
* @param value String value to add (null creates JsonNull)
185
* @return Always true
186
*/
187
fun add(value: String?): Boolean
188
189
/**
190
* Add a null value to the array
191
* @param value Must be null
192
* @return Always true
193
*/
194
@ExperimentalSerializationApi
195
fun add(value: Nothing?): Boolean
196
197
/**
198
* Add all JsonElements from a collection to the array
199
* @param elements Collection of JsonElements to add
200
* @return True if array was modified
201
*/
202
@ExperimentalSerializationApi
203
fun addAll(elements: Collection<JsonElement>): Boolean
204
205
/**
206
* Add all String values from a collection to the array
207
* @param values Collection of String values to add
208
* @return True if array was modified
209
*/
210
@ExperimentalSerializationApi
211
fun addAll(values: Collection<String?>): Boolean
212
213
/**
214
* Add all Boolean values from a collection to the array
215
* @param values Collection of Boolean values to add
216
* @return True if array was modified
217
*/
218
@ExperimentalSerializationApi
219
fun addAll(values: Collection<Boolean?>): Boolean
220
221
/**
222
* Add all Number values from a collection to the array
223
* @param values Collection of Number values to add
224
* @return True if array was modified
225
*/
226
@ExperimentalSerializationApi
227
fun addAll(values: Collection<Number?>): Boolean
228
229
/**
230
* Add a nested JsonObject to the array using builder DSL
231
* @param builderAction Lambda to build nested JsonObject
232
* @return Always true
233
*/
234
fun addJsonObject(builderAction: JsonObjectBuilder.() -> Unit): Boolean
235
236
/**
237
* Add a nested JsonArray to the array using builder DSL
238
* @param builderAction Lambda to build nested JsonArray
239
* @return Always true
240
*/
241
fun addJsonArray(builderAction: JsonArrayBuilder.() -> Unit): Boolean
242
}
243
```
244
245
**Usage Examples:**
246
247
```kotlin
248
import kotlinx.serialization.json.*
249
250
// Basic array construction
251
val numbersJson = buildJsonArray {
252
add(1)
253
add(2.5)
254
add(3)
255
add(null as Number?) // Creates JsonNull
256
}
257
258
// Mixed type array
259
val mixedJson = buildJsonArray {
260
add("hello")
261
add(42)
262
add(true)
263
add(null as String?)
264
265
addJsonObject {
266
put("type", "embedded")
267
put("value", 100)
268
}
269
270
addJsonArray {
271
add("nested")
272
add("array")
273
}
274
}
275
276
// Bulk operations (experimental)
277
val bulkJson = buildJsonArray {
278
addAll(listOf("apple", "banana", "cherry"))
279
addAll(listOf(1, 2, 3, 4, 5))
280
addAll(listOf(true, false, null))
281
}
282
283
// Complex nested structure
284
val dataJson = buildJsonArray {
285
addJsonObject {
286
put("id", 1)
287
put("name", "Alice")
288
putJsonArray("hobbies") {
289
add("reading")
290
add("gaming")
291
}
292
}
293
294
addJsonObject {
295
put("id", 2)
296
put("name", "Bob")
297
putJsonArray("hobbies") {
298
add("sports")
299
add("music")
300
}
301
}
302
}
303
304
// Result:
305
// [
306
// {
307
// "id": 1,
308
// "name": "Alice",
309
// "hobbies": ["reading", "gaming"]
310
// },
311
// {
312
// "id": 2,
313
// "name": "Bob",
314
// "hobbies": ["sports", "music"]
315
// }
316
// ]
317
```
318
319
### Advanced Builder Patterns
320
321
Complex JSON structures using nested builders and conditional logic.
322
323
```kotlin
324
import kotlinx.serialization.json.*
325
326
fun buildUserProfile(
327
user: User,
328
includePrivateInfo: Boolean = false,
329
includePreferences: Boolean = true
330
): JsonObject = buildJsonObject {
331
put("id", user.id)
332
put("username", user.username)
333
put("displayName", user.displayName)
334
335
if (includePrivateInfo) {
336
put("email", user.email)
337
put("phone", user.phone)
338
}
339
340
putJsonObject("profile") {
341
put("bio", user.bio)
342
put("avatar", user.avatarUrl)
343
put("joinDate", user.joinDate.toString())
344
345
putJsonArray("badges") {
346
user.badges.forEach { badge ->
347
addJsonObject {
348
put("id", badge.id)
349
put("name", badge.name)
350
put("earned", badge.earnedDate.toString())
351
}
352
}
353
}
354
}
355
356
if (includePreferences && user.preferences.isNotEmpty()) {
357
putJsonObject("preferences") {
358
user.preferences.forEach { (key, value) ->
359
when (value) {
360
is String -> put(key, value)
361
is Number -> put(key, value)
362
is Boolean -> put(key, value)
363
else -> put(key, value.toString())
364
}
365
}
366
}
367
}
368
369
putJsonArray("recentActivity") {
370
user.recentActivities.take(10).forEach { activity ->
371
addJsonObject {
372
put("type", activity.type)
373
put("timestamp", activity.timestamp.toString())
374
put("data", Json.encodeToJsonElement(activity.data))
375
}
376
}
377
}
378
}
379
```
380
381
### Builder Integration with Serialization
382
383
Combining DSL builders with kotlinx.serialization for hybrid approaches.
384
385
```kotlin
386
import kotlinx.serialization.*
387
import kotlinx.serialization.json.*
388
389
@Serializable
390
data class ApiResponse<T>(
391
val success: Boolean,
392
val data: T?,
393
val error: String?
394
)
395
396
fun <T> buildApiResponse(
397
data: T? = null,
398
error: String? = null,
399
metadata: Map<String, Any> = emptyMap()
400
): JsonObject = buildJsonObject {
401
put("success", data != null)
402
put("timestamp", System.currentTimeMillis())
403
404
if (data != null) {
405
put("data", Json.encodeToJsonElement(data))
406
}
407
408
if (error != null) {
409
put("error", error)
410
}
411
412
if (metadata.isNotEmpty()) {
413
putJsonObject("metadata") {
414
metadata.forEach { (key, value) ->
415
when (value) {
416
is JsonElement -> put(key, value)
417
is String -> put(key, value)
418
is Number -> put(key, value)
419
is Boolean -> put(key, value)
420
else -> put(key, Json.encodeToJsonElement(value))
421
}
422
}
423
}
424
}
425
}
426
427
// Usage
428
val response = buildApiResponse(
429
data = listOf("item1", "item2", "item3"),
430
metadata = mapOf(
431
"requestId" to "req-123",
432
"processingTime" to 150,
433
"cached" to false
434
)
435
)
436
```
437
438
## Common Patterns
439
440
### Dynamic JSON Construction
441
442
```kotlin
443
import kotlinx.serialization.json.*
444
445
fun buildDynamicJson(properties: Map<String, Any?>): JsonObject = buildJsonObject {
446
properties.forEach { (key, value) ->
447
when (value) {
448
null -> put(key, null as String?)
449
is String -> put(key, value)
450
is Number -> put(key, value)
451
is Boolean -> put(key, value)
452
is List<*> -> putJsonArray(key) {
453
value.forEach { item ->
454
when (item) {
455
is String -> add(item)
456
is Number -> add(item)
457
is Boolean -> add(item)
458
else -> add(item.toString())
459
}
460
}
461
}
462
is Map<*, *> -> putJsonObject(key) {
463
value.forEach { (nestedKey, nestedValue) ->
464
put(nestedKey.toString(), nestedValue.toString())
465
}
466
}
467
else -> put(key, value.toString())
468
}
469
}
470
}
471
```
472
473
### Conditional Builder Logic
474
475
```kotlin
476
import kotlinx.serialization.json.*
477
478
fun buildConditionalJson(
479
baseData: Map<String, String>,
480
includeTimestamp: Boolean = true,
481
includeDebug: Boolean = false,
482
userRole: String? = null
483
): JsonObject = buildJsonObject {
484
// Always include base data
485
baseData.forEach { (key, value) ->
486
put(key, value)
487
}
488
489
// Conditional timestamp
490
if (includeTimestamp) {
491
put("timestamp", System.currentTimeMillis())
492
}
493
494
// Debug information
495
if (includeDebug) {
496
putJsonObject("debug") {
497
put("buildTime", System.currentTimeMillis())
498
put("jvmVersion", System.getProperty("java.version"))
499
put("kotlinVersion", KotlinVersion.CURRENT.toString())
500
}
501
}
502
503
// Role-based data
504
when (userRole) {
505
"admin" -> {
506
put("adminLevel", true)
507
putJsonArray("permissions") {
508
add("read")
509
add("write")
510
add("delete")
511
add("admin")
512
}
513
}
514
"user" -> {
515
put("adminLevel", false)
516
putJsonArray("permissions") {
517
add("read")
518
add("write")
519
}
520
}
521
"guest" -> {
522
put("adminLevel", false)
523
putJsonArray("permissions") {
524
add("read")
525
}
526
}
527
null -> {
528
// No role-specific data
529
}
530
}
531
}
532
```