or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

builder-dsl.mdconfiguration.mdcore-operations.mdcustom-serializers.mddynamic-conversion.mdindex.mdjson-annotations.mdjson-element.md

json-annotations.mddocs/

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

```