or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

frame-operations.mdindex.mdplugin-configuration.mdserialization-support.mdsession-management.mdwebsocket-connections.md

serialization-support.mddocs/

0

# Serialization Support

1

2

Content converter integration for automatic serialization/deserialization of objects to/from WebSocket frames, enabling seamless object-based communication over WebSocket connections.

3

4

## Capabilities

5

6

### Send Serialized Data

7

8

Serialize objects to WebSocket frames and send them through the connection.

9

10

```kotlin { .api }

11

/**

12

* Serialize data to WebSocket frame and send it

13

* May suspend if outgoing queue is full

14

* @param data Object to serialize and send

15

* @param typeInfo Type information for serialization

16

* @throws WebsocketConverterNotFoundException if no converter found

17

*/

18

suspend fun DefaultClientWebSocketSession.sendSerialized(data: Any?, typeInfo: TypeInfo)

19

20

/**

21

* Serialize data to WebSocket frame and send it (reified version)

22

* Type information is automatically inferred

23

* @param data Object to serialize and send

24

* @throws WebsocketConverterNotFoundException if no converter found

25

*/

26

suspend inline fun <reified T> DefaultClientWebSocketSession.sendSerialized(data: T)

27

```

28

29

**Usage Examples:**

30

31

```kotlin

32

data class Message(val text: String, val timestamp: Long)

33

data class UserAction(val type: String, val payload: Map<String, Any>)

34

35

client.webSocket("ws://api.example.com") {

36

// Send typed objects (type inferred)

37

sendSerialized(Message("Hello!", System.currentTimeMillis()))

38

sendSerialized(UserAction("login", mapOf("username" to "alice")))

39

40

// Send with explicit type info

41

val genericData: Any = listOf("item1", "item2", "item3")

42

sendSerialized(genericData, typeInfo<List<String>>())

43

44

// Send nullable data

45

val optionalMessage: Message? = null

46

sendSerialized(optionalMessage)

47

}

48

```

49

50

### Receive Deserialized Data

51

52

Receive WebSocket frames and deserialize them to typed objects.

53

54

```kotlin { .api }

55

/**

56

* Receive WebSocket frame and deserialize to specified type

57

* May throw WebsocketDeserializeException if frame cannot be deserialized

58

* @param typeInfo Type information for deserialization

59

* @return Deserialized object of type T

60

* @throws WebsocketConverterNotFoundException if no converter found

61

* @throws WebsocketDeserializeException if deserialization fails

62

* @throws ClosedReceiveChannelException if channel is closed

63

*/

64

suspend fun <T> DefaultClientWebSocketSession.receiveDeserialized(typeInfo: TypeInfo): T

65

66

/**

67

* Receive WebSocket frame and deserialize to specified type (reified version)

68

* Type information is automatically inferred

69

* @return Deserialized object of type T

70

* @throws WebsocketConverterNotFoundException if no converter found

71

* @throws WebsocketDeserializeException if deserialization fails

72

* @throws ClosedReceiveChannelException if channel is closed

73

*/

74

suspend inline fun <reified T> DefaultClientWebSocketSession.receiveDeserialized(): T

75

```

76

77

**Usage Examples:**

78

79

```kotlin

80

data class ServerResponse(val status: String, val data: Any?)

81

data class ChatMessage(val user: String, val message: String, val timestamp: Long)

82

83

client.webSocket("ws://chat.example.com") {

84

// Receive typed objects

85

while (true) {

86

try {

87

val response = receiveDeserialized<ServerResponse>()

88

println("Server status: ${response.status}")

89

90

// Handle different response types

91

when (response.status) {

92

"chat_message" -> {

93

val chatMsg = receiveDeserialized<ChatMessage>()

94

println("${chatMsg.user}: ${chatMsg.message}")

95

}

96

"user_list" -> {

97

val users = receiveDeserialized<List<String>>()

98

println("Online users: ${users.joinToString()}")

99

}

100

}

101

102

} catch (e: WebsocketDeserializeException) {

103

println("Failed to deserialize: ${e.message}")

104

// Handle malformed frame

105

val frame = e.frame

106

if (frame is Frame.Text) {

107

println("Raw content: ${frame.readText()}")

108

}

109

}

110

}

111

}

112

```

113

114

### Content Converter Access

115

116

Get the configured content converter for manual serialization operations.

117

118

```kotlin { .api }

119

/**

120

* Get content converter from WebSocket plugin configuration

121

* Returns null if no converter is configured

122

*/

123

val DefaultClientWebSocketSession.converter: WebsocketContentConverter?

124

```

125

126

**Usage Examples:**

127

128

```kotlin

129

client.webSocket("ws://api.example.com") {

130

val converter = converter

131

if (converter != null) {

132

println("Using converter: ${converter::class.simpleName}")

133

134

// Manual serialization

135

val data = MyData("value")

136

val frame = converter.serialize(

137

Charsets.UTF_8,

138

typeInfo<MyData>(),

139

data

140

)

141

outgoing.send(frame)

142

143

} else {

144

println("No content converter configured")

145

// Fall back to manual JSON or string serialization

146

}

147

}

148

```

149

150

### Content Converter Interface

151

152

Interface for implementing custom serialization converters.

153

154

```kotlin { .api }

155

/**

156

* Interface for WebSocket content converters

157

* Handles serialization/deserialization between objects and WebSocket frames

158

*/

159

interface WebsocketContentConverter {

160

/**

161

* Serialize object to WebSocket frame

162

* @param charset Character encoding to use

163

* @param typeInfo Type information for serialization

164

* @param value Object to serialize

165

* @return WebSocket frame containing serialized data

166

*/

167

suspend fun serialize(

168

charset: Charset,

169

typeInfo: TypeInfo,

170

value: Any?

171

): Frame

172

173

/**

174

* Deserialize WebSocket frame to object

175

* @param charset Character encoding to use

176

* @param typeInfo Type information for deserialization

177

* @param content WebSocket frame to deserialize

178

* @return Deserialized object

179

*/

180

suspend fun deserialize(

181

charset: Charset,

182

typeInfo: TypeInfo,

183

content: Frame

184

): Any?

185

}

186

```

187

188

### Exception Types

189

190

Exceptions specific to WebSocket serialization operations.

191

192

```kotlin { .api }

193

/**

194

* Thrown when no content converter is available for serialization

195

* @param message Error description

196

*/

197

class WebsocketConverterNotFoundException(message: String) : Exception

198

199

/**

200

* Thrown when frame deserialization fails

201

* Contains the original frame for inspection

202

* @param message Error description

203

* @param frame Original frame that failed to deserialize

204

*/

205

class WebsocketDeserializeException(

206

message: String,

207

val frame: Frame

208

) : Exception

209

```

210

211

## Serialization Examples

212

213

### JSON Communication

214

215

```kotlin

216

// Configure client with JSON converter

217

val client = HttpClient {

218

install(WebSockets) {

219

contentConverter = GsonWebsocketContentConverter()

220

}

221

}

222

223

data class ApiRequest(val action: String, val params: Map<String, Any>)

224

data class ApiResponse(val success: Boolean, val result: Any?, val error: String?)

225

226

client.webSocket("ws://api.example.com/json") {

227

// Send JSON request

228

sendSerialized(ApiRequest(

229

action = "get_user",

230

params = mapOf("id" to 123)

231

))

232

233

// Receive JSON response

234

val response = receiveDeserialized<ApiResponse>()

235

if (response.success) {

236

println("Result: ${response.result}")

237

} else {

238

println("Error: ${response.error}")

239

}

240

}

241

```

242

243

### Trading Data Stream

244

245

```kotlin

246

data class Trade(

247

val symbol: String,

248

val price: Double,

249

val quantity: Double,

250

val timestamp: Long

251

)

252

253

data class OrderBook(

254

val symbol: String,

255

val bids: List<Pair<Double, Double>>,

256

val asks: List<Pair<Double, Double>>

257

)

258

259

client.webSocket("ws://trading.example.com") {

260

// Subscribe to data streams

261

sendSerialized(mapOf(

262

"action" to "subscribe",

263

"channels" to listOf("trades", "orderbook"),

264

"symbols" to listOf("BTCUSD", "ETHUSD")

265

))

266

267

while (true) {

268

try {

269

// Receive different message types

270

val messageType = receiveDeserialized<Map<String, Any>>()

271

272

when (messageType["type"]) {

273

"trade" -> {

274

val trade = receiveDeserialized<Trade>()

275

handleTrade(trade)

276

}

277

278

"orderbook" -> {

279

val orderBook = receiveDeserialized<OrderBook>()

280

handleOrderBook(orderBook)

281

}

282

283

"error" -> {

284

val error = receiveDeserialized<Map<String, String>>()

285

println("Server error: ${error["message"]}")

286

}

287

}

288

289

} catch (e: WebsocketDeserializeException) {

290

println("Failed to parse message: ${e.message}")

291

292

// Log raw frame content for debugging

293

when (val frame = e.frame) {

294

is Frame.Text -> println("Raw text: ${frame.readText()}")

295

is Frame.Binary -> println("Raw binary: ${frame.data.size} bytes")

296

}

297

}

298

}

299

}

300

```

301

302

### Custom Protocol with Kotlinx Serialization

303

304

```kotlin

305

@Serializable

306

data class GameState(

307

val players: List<Player>,

308

val board: Array<Array<Int>>,

309

val currentPlayer: String,

310

val gameOver: Boolean

311

)

312

313

@Serializable

314

data class GameAction(

315

val player: String,

316

val action: String,

317

val coordinates: Pair<Int, Int>?

318

)

319

320

// Configure client with Kotlinx Serialization

321

val client = HttpClient {

322

install(WebSockets) {

323

contentConverter = KotlinxSerializationWebsocketContentConverter(Json)

324

}

325

}

326

327

client.webSocket("ws://game.example.com") {

328

// Send game action

329

sendSerialized(GameAction(

330

player = "alice",

331

action = "move",

332

coordinates = Pair(2, 3)

333

))

334

335

// Receive updated game state

336

val newState = receiveDeserialized<GameState>()

337

updateGameUI(newState)

338

}

339

```

340

341

### Mixed Text and Binary Serialization

342

343

```kotlin

344

client.webSocket("ws://multimedia.example.com") {

345

// Text-based metadata

346

sendSerialized(mapOf(

347

"type" to "image_upload",

348

"filename" to "photo.jpg",

349

"size" to 1024000

350

))

351

352

// Binary image data (using custom converter that produces binary frames)

353

val imageBytes = File("photo.jpg").readBytes()

354

val converter = converter as? CustomBinaryConverter

355

356

if (converter != null) {

357

val binaryFrame = converter.serialize(

358

Charsets.UTF_8,

359

typeInfo<ByteArray>(),

360

imageBytes

361

) as Frame.Binary

362

363

outgoing.send(binaryFrame)

364

}

365

366

// Receive processing result

367

val result = receiveDeserialized<Map<String, Any>>()

368

println("Upload result: ${result["status"]}")

369

}

370

```

371

372

### Error Handling and Fallbacks

373

374

```kotlin

375

client.webSocket("ws://api.example.com") {

376

try {

377

// Attempt to send typed object

378

sendSerialized(MyComplexType(data))

379

380

} catch (e: WebsocketConverterNotFoundException) {

381

// Fallback to manual JSON serialization

382

val json = Json.encodeToString(data)

383

send(json)

384

}

385

386

// Receive with error handling

387

while (true) {

388

try {

389

val response = receiveDeserialized<ApiResponse>()

390

handleResponse(response)

391

392

} catch (e: WebsocketDeserializeException) {

393

// Try to handle as plain text

394

val frame = e.frame

395

if (frame is Frame.Text) {

396

val plainText = frame.readText()

397

println("Received plain text: $plainText")

398

399

// Attempt manual parsing

400

try {

401

val json = Json.parseToJsonElement(plainText)

402

handleJsonElement(json)

403

} catch (e: Exception) {

404

println("Could not parse as JSON: $plainText")

405

}

406

}

407

408

} catch (e: ClosedReceiveChannelException) {

409

println("Connection closed")

410

break

411

}

412

}

413

}

414

```

415

416

### Batch Operations

417

418

```kotlin

419

client.webSocket("ws://batch.example.com") {

420

// Send multiple objects in sequence

421

val messages = listOf(

422

ChatMessage("alice", "Hello everyone!"),

423

ChatMessage("bob", "Hi Alice!"),

424

ChatMessage("charlie", "Good morning!")

425

)

426

427

for (message in messages) {

428

sendSerialized(message)

429

}

430

431

// Receive batch response

432

val batchResult = receiveDeserialized<List<MessageStatus>>()

433

batchResult.forEach { status ->

434

println("Message ${status.id}: ${status.delivered}")

435

}

436

}

437

```

438

439

### Type-Safe Protocol Definition

440

441

```kotlin

442

sealed class ServerMessage {

443

@Serializable

444

data class UserJoined(val username: String) : ServerMessage()

445

446

@Serializable

447

data class UserLeft(val username: String) : ServerMessage()

448

449

@Serializable

450

data class ChatMessage(val user: String, val message: String) : ServerMessage()

451

452

@Serializable

453

data class SystemNotification(val level: String, val text: String) : ServerMessage()

454

}

455

456

client.webSocket("ws://chat.example.com") {

457

// Type-safe message handling

458

while (true) {

459

val message = receiveDeserialized<ServerMessage>()

460

461

when (message) {

462

is ServerMessage.UserJoined ->

463

println("${message.username} joined the chat")

464

465

is ServerMessage.UserLeft ->

466

println("${message.username} left the chat")

467

468

is ServerMessage.ChatMessage ->

469

println("${message.user}: ${message.message}")

470

471

is ServerMessage.SystemNotification ->

472

println("[${message.level}] ${message.text}")

473

}

474

}

475

}

476

```