0
# Message Serialization
1
2
Content conversion support for serializing and deserializing objects to/from WebSocket frames with type safety.
3
4
## Required Imports
5
6
```kotlin
7
import io.ktor.client.plugins.websocket.*
8
import io.ktor.util.reflect.*
9
import io.ktor.serialization.*
10
import kotlinx.serialization.*
11
```
12
13
## Capabilities
14
15
### Serialization Functions
16
17
Type-safe functions for sending serialized data through WebSocket connections.
18
19
```kotlin { .api }
20
/**
21
* Serializes data to a frame and enqueues it using reified type information
22
* @param data The data object to serialize and send
23
* @throws WebsocketConverterNotFoundException if no contentConverter is configured
24
*/
25
suspend inline fun <reified T> DefaultClientWebSocketSession.sendSerialized(data: T)
26
27
/**
28
* Serializes data to a frame and enqueues it using explicit type information
29
* @param data The data object to serialize and send
30
* @param typeInfo Type information for the data object
31
* @throws WebsocketConverterNotFoundException if no contentConverter is configured
32
*/
33
suspend fun DefaultClientWebSocketSession.sendSerialized(data: Any?, typeInfo: TypeInfo)
34
```
35
36
**Usage Examples:**
37
38
```kotlin
39
// Configure client with content converter
40
val client = HttpClient {
41
install(WebSockets) {
42
contentConverter = KotlinxWebsocketSerializationConverter(Json)
43
}
44
}
45
46
@Serializable
47
data class Message(val text: String, val timestamp: Long)
48
49
client.webSocket("ws://example.com") {
50
// Send serialized object using reified type
51
val message = Message("Hello!", System.currentTimeMillis())
52
sendSerialized(message)
53
54
// Send serialized object using explicit type info
55
sendSerialized(message, typeInfo<Message>())
56
57
// Send different types
58
sendSerialized(42)
59
sendSerialized(listOf("a", "b", "c"))
60
sendSerialized(mapOf("key" to "value"))
61
}
62
```
63
64
### Deserialization Functions
65
66
Type-safe functions for receiving and deserializing data from WebSocket frames.
67
68
```kotlin { .api }
69
/**
70
* Dequeues a frame and deserializes it using reified type information
71
* @return Deserialized object of type T
72
* @throws WebsocketConverterNotFoundException if no contentConverter is configured
73
* @throws WebsocketDeserializeException if deserialization fails
74
*/
75
suspend inline fun <reified T> DefaultClientWebSocketSession.receiveDeserialized(): T
76
77
/**
78
* Dequeues a frame and deserializes it using explicit type information
79
* @param typeInfo Type information for deserialization target
80
* @return Deserialized object of type T
81
* @throws WebsocketConverterNotFoundException if no contentConverter is configured
82
* @throws WebsocketDeserializeException if deserialization fails
83
*/
84
suspend fun <T> DefaultClientWebSocketSession.receiveDeserialized(typeInfo: TypeInfo): T
85
```
86
87
**Usage Examples:**
88
89
```kotlin
90
@Serializable
91
data class Response(val status: String, val data: String)
92
93
client.webSocket("ws://example.com") {
94
// Send a request
95
sendSerialized(Message("ping", System.currentTimeMillis()))
96
97
// Receive and deserialize response
98
val response = receiveDeserialized<Response>()
99
println("Status: ${response.status}, Data: ${response.data}")
100
101
// Receive different types
102
val number = receiveDeserialized<Int>()
103
val list = receiveDeserialized<List<String>>()
104
val map = receiveDeserialized<Map<String, Any>>()
105
106
// Using explicit type info
107
val explicitResponse = receiveDeserialized<Response>(typeInfo<Response>())
108
}
109
```
110
111
### Content Converter Access
112
113
Access to the configured content converter for advanced usage.
114
115
```kotlin { .api }
116
/**
117
* Gets the WebSocket content converter from the client plugin configuration
118
* @return The configured WebsocketContentConverter or null if none configured
119
*/
120
val DefaultClientWebSocketSession.converter: WebsocketContentConverter?
121
```
122
123
**Usage Examples:**
124
125
```kotlin
126
client.webSocket("ws://example.com") {
127
val converter = converter
128
if (converter != null) {
129
println("Content converter available: ${converter::class.simpleName}")
130
131
// Can perform serialization/deserialization operations
132
sendSerialized("Hello World!")
133
} else {
134
println("No content converter configured")
135
136
// Must use raw frame sending
137
send("Hello World!")
138
}
139
}
140
```
141
142
## Content Converter Types
143
144
### WebSocket Content Converter Interface
145
146
Base interface for implementing custom content converters.
147
148
```kotlin { .api }
149
/**
150
* Interface for WebSocket content serialization/deserialization
151
*/
152
interface WebsocketContentConverter {
153
// Implementation details vary by concrete converter
154
}
155
```
156
157
### Exception Types
158
159
Exceptions thrown during serialization/deserialization operations.
160
161
```kotlin { .api }
162
/**
163
* Exception thrown when no suitable content converter is found
164
* @param message Error description
165
*/
166
class WebsocketConverterNotFoundException(message: String) : Exception(message)
167
168
/**
169
* Exception thrown when frame deserialization fails
170
* @param message Error description
171
* @param frame The WebSocket frame that failed to deserialize
172
*/
173
class WebsocketDeserializeException(message: String, val frame: Frame) : Exception(message)
174
```
175
176
## Serialization Examples
177
178
### JSON Serialization with Kotlinx.serialization
179
180
```kotlin
181
@Serializable
182
data class ChatMessage(
183
val user: String,
184
val message: String,
185
val timestamp: Long = System.currentTimeMillis()
186
)
187
188
@Serializable
189
data class ChatResponse(
190
val type: String,
191
val payload: ChatMessage
192
)
193
194
val client = HttpClient {
195
install(WebSockets) {
196
contentConverter = KotlinxWebsocketSerializationConverter(Json {
197
prettyPrint = true
198
ignoreUnknownKeys = true
199
})
200
}
201
}
202
203
client.webSocket("ws://chat.example.com") {
204
// Send chat message
205
sendSerialized(ChatMessage("user123", "Hello everyone!"))
206
207
// Receive responses
208
while (true) {
209
try {
210
val response = receiveDeserialized<ChatResponse>()
211
when (response.type) {
212
"message" -> println("${response.payload.user}: ${response.payload.message}")
213
"notification" -> println("System: ${response.payload.message}")
214
}
215
} catch (e: ClosedReceiveChannelException) {
216
break
217
}
218
}
219
}
220
```
221
222
### Custom Data Types
223
224
```kotlin
225
@Serializable
226
data class WebSocketCommand(
227
val action: String,
228
val parameters: Map<String, String> = emptyMap()
229
)
230
231
@Serializable
232
data class WebSocketEvent(
233
val event: String,
234
val data: JsonElement
235
)
236
237
client.webSocket("ws://api.example.com") {
238
// Send command
239
sendSerialized(WebSocketCommand(
240
action = "subscribe",
241
parameters = mapOf("channel" to "updates")
242
))
243
244
// Process events
245
for (frame in incoming) {
246
when (frame) {
247
is Frame.Text, is Frame.Binary -> {
248
try {
249
val event = receiveDeserialized<WebSocketEvent>()
250
handleEvent(event.event, event.data)
251
} catch (e: WebsocketDeserializeException) {
252
println("Failed to deserialize frame: ${e.message}")
253
// Handle raw frame if needed
254
if (frame is Frame.Text) {
255
println("Raw text: ${frame.readText()}")
256
}
257
}
258
}
259
is Frame.Close -> break
260
else -> {}
261
}
262
}
263
}
264
```
265
266
### Mixed Serialization and Raw Frames
267
268
```kotlin
269
client.webSocket("ws://example.com") {
270
// Send serialized object
271
sendSerialized(Message("Hello", 123))
272
273
// Send raw text frame
274
send("Raw text message")
275
276
// Send raw binary frame
277
send(byteArrayOf(1, 2, 3, 4))
278
279
// Receive and handle mixed content
280
for (frame in incoming) {
281
when (frame) {
282
is Frame.Text -> {
283
val text = frame.readText()
284
if (text.startsWith("{")) {
285
// Assume JSON, try to deserialize
286
try {
287
val message = receiveDeserialized<Message>()
288
println("Deserialized: $message")
289
} catch (e: WebsocketDeserializeException) {
290
println("Raw text: $text")
291
}
292
} else {
293
println("Raw text: $text")
294
}
295
}
296
is Frame.Binary -> {
297
try {
298
val data = receiveDeserialized<ByteArray>()
299
println("Deserialized binary: ${data.size} bytes")
300
} catch (e: WebsocketDeserializeException) {
301
println("Raw binary: ${frame.data.size} bytes")
302
}
303
}
304
is Frame.Close -> break
305
else -> {}
306
}
307
}
308
}
309
```
310
311
## Error Handling
312
313
### Converter Configuration Errors
314
315
```kotlin
316
client.webSocket("ws://example.com") {
317
try {
318
sendSerialized(Message("test", 123))
319
} catch (e: WebsocketConverterNotFoundException) {
320
println("No content converter configured: ${e.message}")
321
// Fall back to raw frame sending
322
send("""{"text":"test","id":123}""")
323
}
324
}
325
```
326
327
### Deserialization Errors
328
329
```kotlin
330
client.webSocket("ws://example.com") {
331
try {
332
val message = receiveDeserialized<Message>()
333
println("Received: $message")
334
} catch (e: WebsocketDeserializeException) {
335
println("Failed to deserialize frame: ${e.message}")
336
println("Frame type: ${e.frame::class.simpleName}")
337
338
// Handle raw frame content
339
when (val frame = e.frame) {
340
is Frame.Text -> println("Raw text: ${frame.readText()}")
341
is Frame.Binary -> println("Raw binary: ${frame.data.size} bytes")
342
}
343
}
344
}
345
```
346
347
### Type Safety
348
349
```kotlin
350
// Compile-time type safety
351
val message: Message = receiveDeserialized<Message>()
352
353
// Runtime type checking
354
inline fun <reified T> safeReceiveDeserialized(): T? {
355
return try {
356
receiveDeserialized<T>()
357
} catch (e: WebsocketDeserializeException) {
358
null
359
}
360
}
361
362
val maybeMessage = safeReceiveDeserialized<Message>()
363
if (maybeMessage != null) {
364
println("Successfully received: $maybeMessage")
365
}
366
```