or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotations.mdbuilt-ins.mdcore-serialization.mddescriptors.mdencoding.mdindex.mdmodules.md

descriptors.mddocs/

0

# Descriptors

1

2

The descriptor system in kotlinx.serialization provides structural metadata about serializable types. Descriptors describe the shape, names, and characteristics of serialized data, enabling format implementations to understand how to encode and decode objects without needing to know the actual Kotlin types.

3

4

## Capabilities

5

6

### Core Descriptor Interface

7

8

The fundamental interface that describes the structure of any serializable type.

9

10

```kotlin { .api }

11

/**

12

* Describes the structure of a serializable type including its name, kind, and elements.

13

* Used by encoders and decoders to understand the shape of data they're processing.

14

*/

15

interface SerialDescriptor {

16

/** The serial name of the described type */

17

val serialName: String

18

19

/** The kind of serial data (primitive, structured, etc.) */

20

val kind: SerialKind

21

22

/** Number of elements in this descriptor */

23

val elementsCount: Int

24

25

/** Annotations present on the described type */

26

val annotations: List<Annotation>

27

28

/** Whether this descriptor represents an inline value class */

29

val isInline: Boolean

30

31

/** Whether this descriptor is nullable */

32

val isNullable: Boolean

33

34

/** Get the name of element at specified index */

35

fun getElementName(index: Int): String

36

37

/** Get the index of element with specified name */

38

fun getElementIndex(name: String): Int

39

40

/** Get annotations for element at specified index */

41

fun getElementAnnotations(index: Int): List<Annotation>

42

43

/** Get descriptor for element at specified index */

44

fun getElementDescriptor(index: Int): SerialDescriptor

45

46

/** Check if element at specified index is optional */

47

fun isElementOptional(index: Int): Boolean

48

}

49

```

50

51

**Usage Examples:**

52

53

```kotlin

54

import kotlinx.serialization.*

55

import kotlinx.serialization.descriptors.*

56

57

@Serializable

58

data class User(val name: String, val age: Int, val email: String? = null)

59

60

val descriptor = User.serializer().descriptor

61

62

println(descriptor.serialName) // "User"

63

println(descriptor.kind) // StructureKind.CLASS

64

println(descriptor.elementsCount) // 3

65

66

// Inspect elements

67

for (i in 0 until descriptor.elementsCount) {

68

println("${descriptor.getElementName(i)}: ${descriptor.isElementOptional(i)}")

69

}

70

// name: false

71

// age: false

72

// email: true

73

```

74

75

### Serial Kinds

76

77

Type hierarchy that categorizes different kinds of serializable data structures.

78

79

```kotlin { .api }

80

/**

81

* Base sealed class for all serial kinds that categorize serializable types.

82

*/

83

sealed class SerialKind

84

85

/**

86

* Kinds for primitive values that can be directly encoded/decoded.

87

*/

88

sealed class PrimitiveKind : SerialKind() {

89

object BOOLEAN : PrimitiveKind()

90

object BYTE : PrimitiveKind()

91

object CHAR : PrimitiveKind()

92

object SHORT : PrimitiveKind()

93

object INT : PrimitiveKind()

94

object LONG : PrimitiveKind()

95

object FLOAT : PrimitiveKind()

96

object DOUBLE : PrimitiveKind()

97

object STRING : PrimitiveKind()

98

}

99

100

/**

101

* Kinds for structured values that contain multiple elements.

102

*/

103

sealed class StructureKind : SerialKind() {

104

/** Regular class with named properties */

105

object CLASS : StructureKind()

106

107

/** Ordered collection of elements */

108

object LIST : StructureKind()

109

110

/** Key-value mapping */

111

object MAP : StructureKind()

112

113

/** Object instance (singleton) */

114

object OBJECT : StructureKind()

115

}

116

117

/**

118

* Kinds for polymorphic types that can have multiple runtime implementations.

119

*/

120

sealed class PolymorphicKind : SerialKind() {

121

/** Sealed class hierarchy with known subclasses */

122

object SEALED : PolymorphicKind()

123

124

/** Open class/interface with potentially unknown subclasses */

125

object OPEN : PolymorphicKind()

126

}

127

128

/**

129

* Special kinds for specific serialization scenarios.

130

*/

131

object SerialKind {

132

/** Type that requires contextual serializer lookup */

133

object CONTEXTUAL : SerialKind()

134

135

/** Enum type */

136

object ENUM : SerialKind()

137

}

138

```

139

140

### Descriptor Factory Functions

141

142

Factory functions for creating descriptors programmatically.

143

144

```kotlin { .api }

145

/**

146

* Creates a primitive descriptor for basic types.

147

* @param serialName The name of the described type

148

* @param kind The primitive kind

149

* @return SerialDescriptor for the primitive type

150

*/

151

fun PrimitiveSerialDescriptor(serialName: String, kind: PrimitiveKind): SerialDescriptor

152

153

/**

154

* DSL builder for creating class descriptors with elements.

155

* @param serialName The name of the described type

156

* @param builderAction Lambda to configure descriptor elements

157

* @return SerialDescriptor for the class

158

*/

159

fun buildClassSerialDescriptor(

160

serialName: String,

161

builderAction: ClassSerialDescriptorBuilder.() -> Unit = {}

162

): SerialDescriptor

163

164

/**

165

* Creates a descriptor identical to original but with different name.

166

* @param serialName The new name for the descriptor

167

* @param original The original descriptor to copy

168

* @return SerialDescriptor with new name

169

*/

170

fun SerialDescriptor(serialName: String, original: SerialDescriptor): SerialDescriptor

171

172

/**

173

* Builder class for constructing class descriptors.

174

*/

175

class ClassSerialDescriptorBuilder {

176

/** Add an element to the descriptor */

177

fun element(

178

elementName: String,

179

descriptor: SerialDescriptor,

180

annotations: List<Annotation> = emptyList(),

181

isOptional: Boolean = false

182

)

183

184

/** Add annotations to the descriptor itself */

185

fun annotations(annotations: List<Annotation>)

186

}

187

```

188

189

**Usage Examples:**

190

191

```kotlin

192

import kotlinx.serialization.descriptors.*

193

194

// Create primitive descriptor

195

val stringDescriptor = PrimitiveSerialDescriptor("MyString", PrimitiveKind.STRING)

196

197

// Create class descriptor with DSL

198

val personDescriptor = buildClassSerialDescriptor("Person") {

199

element("name", PrimitiveSerialDescriptor("kotlin.String", PrimitiveKind.STRING))

200

element("age", PrimitiveSerialDescriptor("kotlin.Int", PrimitiveKind.INT))

201

element("email", PrimitiveSerialDescriptor("kotlin.String", PrimitiveKind.STRING), isOptional = true)

202

}

203

204

// Copy descriptor with new name

205

val aliasDescriptor = SerialDescriptor("PersonAlias", personDescriptor)

206

```

207

208

### Collection Descriptor Functions

209

210

Specialized functions for creating descriptors for collection types.

211

212

```kotlin { .api }

213

/**

214

* Creates a descriptor for List<T> structures.

215

* @param elementDescriptor Descriptor for list elements

216

* @return SerialDescriptor for List type

217

*/

218

fun listSerialDescriptor(elementDescriptor: SerialDescriptor): SerialDescriptor

219

220

/**

221

* Creates a descriptor for Set<T> structures.

222

* @param elementDescriptor Descriptor for set elements

223

* @return SerialDescriptor for Set type

224

*/

225

fun setSerialDescriptor(elementDescriptor: SerialDescriptor): SerialDescriptor

226

227

/**

228

* Creates a descriptor for Map<K,V> structures.

229

* @param keyDescriptor Descriptor for map keys

230

* @param valueDescriptor Descriptor for map values

231

* @return SerialDescriptor for Map type

232

*/

233

fun mapSerialDescriptor(

234

keyDescriptor: SerialDescriptor,

235

valueDescriptor: SerialDescriptor

236

): SerialDescriptor

237

```

238

239

### Descriptor Lookup Functions

240

241

Functions for obtaining descriptors at runtime.

242

243

```kotlin { .api }

244

/**

245

* Retrieves a descriptor for the given reified type T.

246

* @return SerialDescriptor for type T

247

*/

248

inline fun <reified T> serialDescriptor(): SerialDescriptor

249

250

/**

251

* Retrieves a descriptor for the given KType.

252

* @param type The KType to get descriptor for

253

* @return SerialDescriptor for the specified type

254

*/

255

fun serialDescriptor(type: KType): SerialDescriptor

256

```

257

258

**Usage Examples:**

259

260

```kotlin

261

import kotlinx.serialization.*

262

import kotlinx.serialization.descriptors.*

263

import kotlin.reflect.typeOf

264

265

@Serializable

266

data class Product(val name: String, val price: Double)

267

268

// Get descriptor for known type

269

val productDescriptor = serialDescriptor<Product>()

270

271

// Get descriptor for collection types

272

val listDescriptor = serialDescriptor<List<Product>>()

273

val mapDescriptor = serialDescriptor<Map<String, Product>>()

274

275

// Runtime descriptor lookup

276

val typeDescriptor = serialDescriptor(typeOf<List<String>>())

277

278

// Create collection descriptors manually

279

val customListDesc = listSerialDescriptor(PrimitiveSerialDescriptor("kotlin.String", PrimitiveKind.STRING))

280

val customMapDesc = mapSerialDescriptor(

281

PrimitiveSerialDescriptor("kotlin.String", PrimitiveKind.STRING),

282

serialDescriptor<Product>()

283

)

284

```

285

286

### Descriptor Extension Properties

287

288

Additional properties available on descriptors for advanced use cases.

289

290

```kotlin { .api }

291

/**

292

* Extension property that returns the captured KClass for the descriptor.

293

* Useful for runtime type checking and reflection operations.

294

*/

295

val SerialDescriptor.capturedKClass: KClass<Any>?

296

```

297

298

## Usage Patterns

299

300

### Custom Serializer Descriptors

301

302

When implementing custom serializers, you typically need to provide appropriate descriptors:

303

304

```kotlin

305

import kotlinx.serialization.*

306

import kotlinx.serialization.descriptors.*

307

import kotlinx.serialization.encoding.*

308

309

object LocalDateSerializer : KSerializer<LocalDate> {

310

override val descriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)

311

312

override fun serialize(encoder: Encoder, value: LocalDate) {

313

encoder.encodeString(value.toString())

314

}

315

316

override fun deserialize(decoder: Decoder): LocalDate {

317

return LocalDate.parse(decoder.decodeString())

318

}

319

}

320

```

321

322

### Format Implementation Guidance

323

324

Descriptors help format implementations understand data structure:

325

326

```kotlin

327

fun encodeStructure(descriptor: SerialDescriptor, encoder: Encoder) {

328

when (descriptor.kind) {

329

StructureKind.CLASS -> encodeObject(descriptor, encoder)

330

StructureKind.LIST -> encodeArray(descriptor, encoder)

331

StructureKind.MAP -> encodeMap(descriptor, encoder)

332

is PrimitiveKind -> encodePrimitive(descriptor, encoder)

333

else -> throw SerializationException("Unsupported kind: ${descriptor.kind}")

334

}

335

}

336

```

337

338

## Error Handling

339

340

Descriptor-related errors typically indicate structural mismatches:

341

342

- **IndexOutOfBoundsException**: Invalid element index access

343

- **IllegalArgumentException**: Invalid descriptor configurations

344

- **SerializationException**: Descriptor/data structure mismatches during encoding/decoding