0
# Configuration and Customization
1
2
Comprehensive configuration system for customizing JSON encoding/decoding behavior, naming strategies, and polymorphism handling. The JsonBuilder class provides extensive options to control how JSON serialization behaves.
3
4
## Capabilities
5
6
### JsonBuilder Configuration
7
8
Configure Json instances through the JsonBuilder class with extensive customization options.
9
10
```kotlin { .api }
11
/**
12
* Builder class for configuring Json instances
13
*/
14
class JsonBuilder {
15
/**
16
* Encode default property values (default: false)
17
*/
18
var encodeDefaults: Boolean
19
20
/**
21
* Explicitly encode/require null values (default: true)
22
*/
23
var explicitNulls: Boolean
24
25
/**
26
* Ignore unknown JSON properties during decoding (default: false)
27
*/
28
var ignoreUnknownKeys: Boolean
29
30
/**
31
* Coerce invalid input values to defaults (default: false)
32
*/
33
var coerceInputValues: Boolean
34
35
/**
36
* Enable pretty-printed JSON output (default: false)
37
*/
38
var prettyPrint: Boolean
39
40
/**
41
* Indentation string for pretty printing (default: " ")
42
*/
43
var prettyPrintIndent: String
44
45
/**
46
* Allow malformed JSON (unquoted keys/values) (default: false)
47
*/
48
var isLenient: Boolean
49
50
/**
51
* Allow NaN, Infinity values (default: false)
52
*/
53
var allowSpecialFloatingPointValues: Boolean
54
55
/**
56
* Allow complex objects as map keys (default: false)
57
*/
58
var allowStructuredMapKeys: Boolean
59
60
/**
61
* Allow trailing commas in objects/arrays (default: false)
62
*/
63
var allowTrailingComma: Boolean
64
65
/**
66
* Allow C-style comments in JSON (default: false)
67
*/
68
var allowComments: Boolean
69
70
/**
71
* Use @JsonNames alternative names (default: true)
72
*/
73
var useAlternativeNames: Boolean
74
75
/**
76
* Global property name transformation (default: null)
77
*/
78
var namingStrategy: JsonNamingStrategy?
79
80
/**
81
* Case-insensitive enum parsing (default: false)
82
*/
83
var decodeEnumsCaseInsensitive: Boolean
84
85
/**
86
* Property name for type discriminator (default: "type")
87
*/
88
var classDiscriminator: String
89
90
/**
91
* When to add discriminators (default: POLYMORPHIC)
92
*/
93
var classDiscriminatorMode: ClassDiscriminatorMode
94
95
/**
96
* Use legacy array-based polymorphism (default: false)
97
*/
98
var useArrayPolymorphism: Boolean
99
}
100
```
101
102
### Encoding/Decoding Behavior
103
104
Control how objects are serialized and deserialized.
105
106
**Usage Examples:**
107
108
```kotlin
109
@Serializable
110
data class User(
111
val name: String,
112
val age: Int = 25, // Default value
113
val email: String? = null,
114
val isActive: Boolean = true
115
)
116
117
// Default behavior
118
val defaultJson = Json.Default
119
val user = User("Alice")
120
val defaultResult = defaultJson.encodeToString(user)
121
// Result: {"name":"Alice"}
122
// Note: Default values and nulls are omitted
123
124
// Include default values
125
val includeDefaultsJson = Json {
126
encodeDefaults = true
127
}
128
val withDefaults = includeDefaultsJson.encodeToString(user)
129
// Result: {"name":"Alice","age":25,"email":null,"isActive":true}
130
131
// Handle null values explicitly
132
val explicitNullsJson = Json {
133
encodeDefaults = true
134
explicitNulls = true
135
}
136
val userWithEmail = User("Bob", email = "bob@example.com")
137
val withExplicitNulls = explicitNullsJson.encodeToString(userWithEmail)
138
// Result: {"name":"Bob","age":25,"email":"bob@example.com","isActive":true}
139
140
val noExplicitNullsJson = Json {
141
encodeDefaults = true
142
explicitNulls = false
143
}
144
val withoutExplicitNulls = noExplicitNullsJson.encodeToString(userWithEmail)
145
// Result: {"name":"Bob","age":25,"email":"bob@example.com","isActive":true}
146
// Note: Non-null email is still included
147
```
148
149
### Lenient Parsing
150
151
Handle malformed or non-standard JSON input.
152
153
```kotlin { .api }
154
/**
155
* Configuration modes for handling malformed JSON
156
*/
157
enum class ClassDiscriminatorMode {
158
NONE, // Never add class discriminators
159
POLYMORPHIC, // Add discriminators for polymorphic classes only
160
ALL_JSON_OBJECTS // Add discriminators for all JSON objects
161
}
162
```
163
164
**Usage Examples:**
165
166
```kotlin
167
// Strict JSON parsing (default)
168
val strictJson = Json.Default
169
170
// Lenient JSON parsing
171
val lenientJson = Json {
172
isLenient = true
173
ignoreUnknownKeys = true
174
coerceInputValues = true
175
allowSpecialFloatingPointValues = true
176
allowTrailingComma = true
177
allowComments = true
178
}
179
180
// Malformed JSON examples that work with lenient parsing
181
val malformedJson = """
182
{
183
// This is a comment
184
unquoted_key: "value",
185
"number": NaN,
186
"infinity": Infinity,
187
"trailing": "comma",
188
}
189
"""
190
191
try {
192
val parsed = lenientJson.decodeFromString<JsonElement>(malformedJson)
193
println("Lenient parsing succeeded")
194
} catch (e: JsonDecodingException) {
195
println("Lenient parsing failed: ${e.message}")
196
}
197
198
// Coercing invalid values
199
@Serializable
200
data class NumberData(val value: Int, val flag: Boolean)
201
202
val invalidDataJson = """{"value": "not_a_number", "flag": "yes"}"""
203
204
val coercingJson = Json {
205
coerceInputValues = true
206
}
207
208
val coercedData = coercingJson.decodeFromString<NumberData>(invalidDataJson)
209
// Result: NumberData(value = 0, flag = false) - invalid values coerced to defaults
210
```
211
212
### Pretty Printing
213
214
Format JSON output for human readability.
215
216
**Usage Examples:**
217
218
```kotlin
219
@Serializable
220
data class Product(
221
val id: String,
222
val name: String,
223
val categories: List<String>,
224
val metadata: Map<String, String>
225
)
226
227
val product = Product(
228
id = "PROD-001",
229
name = "Super Widget",
230
categories = listOf("electronics", "gadgets"),
231
metadata = mapOf("color" to "blue", "weight" to "1.5kg")
232
)
233
234
// Compact output (default)
235
val compactJson = Json.Default
236
val compact = compactJson.encodeToString(product)
237
// Result: {"id":"PROD-001","name":"Super Widget","categories":["electronics","gadgets"],"metadata":{"color":"blue","weight":"1.5kg"}}
238
239
// Pretty printed output
240
val prettyJson = Json {
241
prettyPrint = true
242
}
243
val pretty = prettyJson.encodeToString(product)
244
// Result:
245
// {
246
// "id": "PROD-001",
247
// "name": "Super Widget",
248
// "categories": [
249
// "electronics",
250
// "gadgets"
251
// ],
252
// "metadata": {
253
// "color": "blue",
254
// "weight": "1.5kg"
255
// }
256
// }
257
258
// Custom indentation
259
val customIndentJson = Json {
260
prettyPrint = true
261
prettyPrintIndent = " " // 2 spaces instead of 4
262
}
263
val customIndent = customIndentJson.encodeToString(product)
264
```
265
266
### Naming Strategies
267
268
Transform property names during serialization/deserialization.
269
270
```kotlin { .api }
271
/**
272
* Strategy for transforming property names
273
*/
274
interface JsonNamingStrategy {
275
/**
276
* Transform a serial name for JSON serialization
277
* @param descriptor Serial descriptor of the class
278
* @param elementIndex Index of the property in the class
279
* @param serialName Original property name
280
* @return Transformed property name for JSON
281
*/
282
fun serialNameForJson(descriptor: SerialDescriptor, elementIndex: Int, serialName: String): String
283
284
companion object {
285
/**
286
* Convert camelCase to snake_case
287
*/
288
val SnakeCase: JsonNamingStrategy
289
290
/**
291
* Convert camelCase to kebab-case
292
*/
293
val KebabCase: JsonNamingStrategy
294
}
295
}
296
```
297
298
**Usage Examples:**
299
300
```kotlin
301
@Serializable
302
data class ApiResponse(
303
val userId: Int,
304
val firstName: String,
305
val lastName: String,
306
val emailAddress: String,
307
val isActiveUser: Boolean
308
)
309
310
val response = ApiResponse(
311
userId = 123,
312
firstName = "Alice",
313
lastName = "Smith",
314
emailAddress = "alice@example.com",
315
isActiveUser = true
316
)
317
318
// Default naming (camelCase)
319
val defaultNaming = Json.Default
320
val camelCase = defaultNaming.encodeToString(response)
321
// Result: {"userId":123,"firstName":"Alice","lastName":"Smith","emailAddress":"alice@example.com","isActiveUser":true}
322
323
// Snake case naming
324
val snakeCaseJson = Json {
325
namingStrategy = JsonNamingStrategy.SnakeCase
326
}
327
val snakeCase = snakeCaseJson.encodeToString(response)
328
// Result: {"user_id":123,"first_name":"Alice","last_name":"Smith","email_address":"alice@example.com","is_active_user":true}
329
330
// Kebab case naming
331
val kebabCaseJson = Json {
332
namingStrategy = JsonNamingStrategy.KebabCase
333
}
334
val kebabCase = kebabCaseJson.encodeToString(response)
335
// Result: {"user-id":123,"first-name":"Alice","last-name":"Smith","email-address":"alice@example.com","is-active-user":true}
336
337
// Custom naming strategy
338
val customNamingJson = Json {
339
namingStrategy = object : JsonNamingStrategy {
340
override fun serialNameForJson(descriptor: SerialDescriptor, elementIndex: Int, serialName: String): String {
341
return serialName.uppercase() // Convert all property names to uppercase
342
}
343
}
344
}
345
val uppercase = customNamingJson.encodeToString(response)
346
// Result: {"USERID":123,"FIRSTNAME":"Alice","LASTNAME":"Smith","EMAILADDRESS":"alice@example.com","ISACTIVEUSER":true}
347
```
348
349
### Alternative Names
350
351
Support multiple property names during deserialization.
352
353
**Usage Examples:**
354
355
```kotlin
356
@Serializable
357
data class User(
358
@JsonNames("user_id", "id")
359
val userId: Int,
360
361
@JsonNames("user_name", "username", "login")
362
val name: String,
363
364
@JsonNames("email_address", "mail")
365
val email: String
366
)
367
368
val flexibleJson = Json {
369
useAlternativeNames = true // Default is true
370
}
371
372
// All these JSON variations can be deserialized to the same User object
373
val json1 = """{"userId":1,"name":"Alice","email":"alice@example.com"}"""
374
val json2 = """{"user_id":1,"user_name":"Alice","email_address":"alice@example.com"}"""
375
val json3 = """{"id":1,"username":"Alice","mail":"alice@example.com"}"""
376
val json4 = """{"user_id":1,"login":"Alice","email":"alice@example.com"}"""
377
378
val user1 = flexibleJson.decodeFromString<User>(json1)
379
val user2 = flexibleJson.decodeFromString<User>(json2)
380
val user3 = flexibleJson.decodeFromString<User>(json3)
381
val user4 = flexibleJson.decodeFromString<User>(json4)
382
383
// All result in the same User object
384
assert(user1 == user2)
385
assert(user2 == user3)
386
assert(user3 == user4)
387
```
388
389
### Enum Handling
390
391
Configure enum serialization and deserialization behavior.
392
393
**Usage Examples:**
394
395
```kotlin
396
@Serializable
397
enum class Status { ACTIVE, INACTIVE, PENDING }
398
399
@Serializable
400
data class Record(val id: Int, val status: Status)
401
402
// Case-sensitive enum parsing (default)
403
val strictEnumJson = Json.Default
404
405
// Case-insensitive enum parsing
406
val lenientEnumJson = Json {
407
decodeEnumsCaseInsensitive = true
408
}
409
410
// These will work with case-insensitive parsing
411
val variations = listOf(
412
"""{"id":1,"status":"ACTIVE"}""",
413
"""{"id":1,"status":"active"}""",
414
"""{"id":1,"status":"Active"}""",
415
"""{"id":1,"status":"AcTiVe"}"""
416
)
417
418
variations.forEach { json ->
419
try {
420
val record = lenientEnumJson.decodeFromString<Record>(json)
421
println("Parsed: $record")
422
} catch (e: JsonDecodingException) {
423
println("Failed to parse: $json")
424
}
425
}
426
```
427
428
### Polymorphism Configuration
429
430
Control polymorphic serialization behavior.
431
432
**Usage Examples:**
433
434
```kotlin
435
@Serializable
436
abstract class Animal {
437
abstract val name: String
438
}
439
440
@Serializable
441
@SerialName("dog")
442
data class Dog(override val name: String, val breed: String) : Animal()
443
444
@Serializable
445
@SerialName("cat")
446
data class Cat(override val name: String, val lives: Int) : Animal()
447
448
// Default polymorphic configuration
449
val defaultPolymorphicJson = Json {
450
classDiscriminator = "type" // Default
451
classDiscriminatorMode = ClassDiscriminatorMode.POLYMORPHIC // Default
452
}
453
454
val dog = Dog("Buddy", "Golden Retriever")
455
val polymorphicResult = defaultPolymorphicJson.encodeToString<Animal>(dog)
456
// Result: {"type":"dog","name":"Buddy","breed":"Golden Retriever"}
457
458
// Custom discriminator property name
459
val customDiscriminatorJson = Json {
460
classDiscriminator = "objectType"
461
}
462
463
val customResult = customDiscriminatorJson.encodeToString<Animal>(dog)
464
// Result: {"objectType":"dog","name":"Buddy","breed":"Golden Retriever"}
465
466
// Array-based polymorphism (legacy)
467
val arrayPolymorphicJson = Json {
468
useArrayPolymorphism = true
469
}
470
471
val arrayResult = arrayPolymorphicJson.encodeToString<Animal>(dog)
472
// Result: ["dog",{"name":"Buddy","breed":"Golden Retriever"}]
473
474
// Discriminator modes
475
val allObjectsJson = Json {
476
classDiscriminatorMode = ClassDiscriminatorMode.ALL_JSON_OBJECTS
477
classDiscriminator = "className"
478
}
479
480
@Serializable
481
data class SimpleData(val value: String)
482
483
val simpleData = SimpleData("test")
484
val withDiscriminator = allObjectsJson.encodeToString(simpleData)
485
// Result: {"className":"SimpleData","value":"test"}
486
```