0
# JSON Annotations
1
2
JSON-specific annotations for controlling serialization behavior, providing alternative names, class discriminators, and selective ignoring of unknown properties.
3
4
## Capabilities
5
6
### JsonNames Annotation
7
8
Allows multiple alternative names for a single property during JSON deserialization.
9
10
```kotlin { .api }
11
/**
12
* Indicates that the field can be represented in JSON with multiple possible alternative names
13
* Unlike SerialName annotation, does not affect JSON encoding in any way
14
* @param names Alternative names for the property
15
*/
16
@SerialInfo
17
@Target(AnnotationTarget.PROPERTY)
18
@ExperimentalSerializationApi
19
annotation class JsonNames(vararg val names: String)
20
```
21
22
**Usage Examples:**
23
24
```kotlin
25
@Serializable
26
data class Project(
27
@JsonNames("title", "project_name")
28
val name: String,
29
@JsonNames("desc", "description")
30
val summary: String
31
)
32
33
val json = Json { useAlternativeNames = true }
34
35
// All of these work for deserialization
36
val project1 = json.decodeFromString<Project>("""{"name":"kotlinx.serialization","summary":"Kotlin serialization"}""")
37
val project2 = json.decodeFromString<Project>("""{"title":"kotlinx.coroutines","desc":"Kotlin coroutines"}""")
38
val project3 = json.decodeFromString<Project>("""{"project_name":"kotlinx.datetime","description":"Kotlin datetime"}""")
39
40
// But encoding always uses the primary name
41
val encoded = json.encodeToString(project1)
42
// Result: {"name":"kotlinx.serialization","summary":"Kotlin serialization"}
43
```
44
45
### JsonClassDiscriminator Annotation
46
47
Specifies a custom key for class discriminator values in polymorphic serialization.
48
49
```kotlin { .api }
50
/**
51
* Specifies key for class discriminator value used during polymorphic serialization
52
* This annotation is inheritable, so it should be sufficient to place it on a base class of hierarchy
53
* @param discriminator The key name to use for the class discriminator
54
*/
55
@InheritableSerialInfo
56
@Target(AnnotationTarget.CLASS)
57
@ExperimentalSerializationApi
58
annotation class JsonClassDiscriminator(val discriminator: String)
59
```
60
61
**Usage Examples:**
62
63
```kotlin
64
@Serializable
65
@JsonClassDiscriminator("message_type")
66
abstract class BaseMessage
67
68
@Serializable
69
class TextMessage(val text: String) : BaseMessage()
70
71
@Serializable
72
class ImageMessage(val imageUrl: String, val caption: String?) : BaseMessage()
73
74
@Serializable
75
class ChatData(val messages: List<BaseMessage>)
76
77
val json = Json.Default
78
val chat = ChatData(listOf(
79
TextMessage("Hello world"),
80
ImageMessage("https://example.com/image.jpg", "A beautiful sunset")
81
))
82
83
val encoded = json.encodeToString(chat)
84
// Result uses "message_type" instead of default "type":
85
// {
86
// "messages": [
87
// {"message_type":"TextMessage","text":"Hello world"},
88
// {"message_type":"ImageMessage","imageUrl":"https://example.com/image.jpg","caption":"A beautiful sunset"}
89
// ]
90
// }
91
```
92
93
### JsonIgnoreUnknownKeys Annotation
94
95
Allows specific classes to ignore unknown properties during deserialization while maintaining strict checking for other classes.
96
97
```kotlin { .api }
98
/**
99
* Specifies whether encounters of unknown properties should be ignored for this class
100
* Provides per-class control over unknown key handling
101
*/
102
@SerialInfo
103
@Target(AnnotationTarget.CLASS)
104
@ExperimentalSerializationApi
105
annotation class JsonIgnoreUnknownKeys
106
```
107
108
**Usage Examples:**
109
110
```kotlin
111
@Serializable
112
@JsonIgnoreUnknownKeys
113
class FlexibleConfig(
114
val host: String,
115
val port: Int
116
)
117
118
@Serializable
119
class StrictConfig(
120
val apiKey: String,
121
val timeout: Int
122
)
123
124
@Serializable
125
class AppConfig(
126
val flexible: FlexibleConfig,
127
val strict: StrictConfig
128
)
129
130
val json = Json.Default // ignoreUnknownKeys = false globally
131
132
// This works - FlexibleConfig ignores unknown "ssl" property
133
val config1 = json.decodeFromString<FlexibleConfig>("""
134
{"host":"localhost","port":8080,"ssl":true,"region":"us-east-1"}
135
""")
136
137
// This fails - StrictConfig doesn't ignore unknown "retries" property
138
try {
139
val config2 = json.decodeFromString<StrictConfig>("""
140
{"apiKey":"secret","timeout":5000,"retries":3}
141
""")
142
} catch (e: SerializationException) {
143
println("Failed: ${e.message}") // Unknown key 'retries'
144
}
145
146
// Mixed usage in nested structures
147
val appConfig = json.decodeFromString<AppConfig>("""
148
{
149
"flexible": {"host":"api.example.com","port":443,"ssl":true},
150
"strict": {"apiKey":"abc123","timeout":10000}
151
}
152
""")
153
// Works because FlexibleConfig ignores "ssl" but StrictConfig is still strict
154
```
155
156
## Configuration Integration
157
158
These annotations work in conjunction with global Json configuration settings:
159
160
```kotlin
161
val json = Json {
162
useAlternativeNames = true // Required for @JsonNames to work
163
ignoreUnknownKeys = false // @JsonIgnoreUnknownKeys provides per-class override
164
classDiscriminator = "type" // @JsonClassDiscriminator provides per-hierarchy override
165
}
166
```
167
168
## Annotation Priority Rules
169
170
1. **JsonNames vs SerialName**: `@SerialName` has higher priority. If property A has `@SerialName("foo")` and property B has `@JsonNames("foo")`, the key "foo" will deserialize to property A.
171
172
2. **Class-level vs Global**: `@JsonIgnoreUnknownKeys` on a class overrides the global `ignoreUnknownKeys` setting.
173
174
3. **Hierarchy Inheritance**: `@JsonClassDiscriminator` is inherited by subclasses automatically.
175
176
## Common Patterns
177
178
### API Evolution Support
179
180
```kotlin
181
@Serializable
182
data class UserProfile(
183
@JsonNames("user_name", "username", "login")
184
val name: String,
185
@JsonNames("user_id", "id")
186
val userId: Long,
187
val email: String
188
)
189
190
// Supports multiple API versions
191
val v1Response = """{"user_name":"alice","user_id":123,"email":"alice@example.com"}"""
192
val v2Response = """{"username":"bob","id":456,"email":"bob@example.com"}"""
193
val v3Response = """{"name":"charlie","userId":789,"email":"charlie@example.com"}"""
194
195
// All parse successfully to the same data class
196
```
197
198
### Flexible Data Models
199
200
```kotlin
201
@Serializable
202
@JsonIgnoreUnknownKeys
203
data class PartialUser(
204
val name: String,
205
val email: String?
206
)
207
208
// Can extract just the needed fields from complex API responses
209
val complexApiResponse = """
210
{
211
"name": "Alice",
212
"email": "alice@example.com",
213
"address": {"street": "123 Main St", "city": "Anytown"},
214
"preferences": {"theme": "dark", "notifications": true},
215
"metadata": {"created": "2023-01-01", "lastLogin": "2023-12-01"}
216
}
217
"""
218
219
val user = json.decodeFromString<PartialUser>(complexApiResponse)
220
// Successfully extracts just name and email, ignoring all other fields
221
```