or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced.mdannotations.mdbuilders.mdconfiguration.mdindex.mdjson-element.mdplatform.mdserialization.md

platform.mddocs/

0

# Platform-Specific APIs

1

2

Platform-specific extensions providing optimized JSON processing for JVM stream operations and JavaScript dynamic object interoperability.

3

4

## Capabilities

5

6

### JVM Stream Operations

7

8

JVM-specific extensions for working with InputStream and OutputStream, enabling efficient streaming JSON processing.

9

10

```kotlin { .api }

11

/**

12

* Serialize a value directly to an OutputStream

13

* @param serializer Serialization strategy for type T

14

* @param value Object to serialize

15

* @param stream OutputStream to write JSON to

16

*/

17

@ExperimentalSerializationApi

18

fun <T> Json.encodeToStream(

19

serializer: SerializationStrategy<T>,

20

value: T,

21

stream: OutputStream

22

)

23

24

/**

25

* Serialize a value directly to an OutputStream using reified type

26

* @param value Object to serialize

27

* @param stream OutputStream to write JSON to

28

*/

29

@ExperimentalSerializationApi

30

inline fun <reified T> Json.encodeToStream(value: T, stream: OutputStream)

31

32

/**

33

* Deserialize JSON from an InputStream

34

* @param deserializer Deserialization strategy for type T

35

* @param stream InputStream containing JSON data

36

* @return Deserialized object of type T

37

*/

38

@ExperimentalSerializationApi

39

fun <T> Json.decodeFromStream(

40

deserializer: DeserializationStrategy<T>,

41

stream: InputStream

42

): T

43

44

/**

45

* Deserialize JSON from an InputStream using reified type

46

* @param stream InputStream containing JSON data

47

* @return Deserialized object of type T

48

*/

49

@ExperimentalSerializationApi

50

inline fun <reified T> Json.decodeFromStream(stream: InputStream): T

51

52

/**

53

* Decode a sequence of JSON objects from an InputStream

54

* @param stream InputStream containing JSON sequence

55

* @param deserializer Deserialization strategy for type T

56

* @param format Format of the JSON sequence

57

* @return Sequence of deserialized objects

58

*/

59

@ExperimentalSerializationApi

60

fun <T> Json.decodeToSequence(

61

stream: InputStream,

62

deserializer: DeserializationStrategy<T>,

63

format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT

64

): Sequence<T>

65

66

/**

67

* Decode a sequence of JSON objects from an InputStream using reified type

68

* @param stream InputStream containing JSON sequence

69

* @param format Format of the JSON sequence

70

* @return Sequence of deserialized objects

71

*/

72

@ExperimentalSerializationApi

73

inline fun <reified T> Json.decodeToSequence(

74

stream: InputStream,

75

format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT

76

): Sequence<T>

77

78

/**

79

* Mode for decoding JSON sequences

80

*/

81

@ExperimentalSerializationApi

82

enum class DecodeSequenceMode {

83

/** Objects separated by whitespace: {"a":1} {"b":2} */

84

WHITESPACE_SEPARATED,

85

/** Objects wrapped in array: [{"a":1}, {"b":2}] */

86

ARRAY_WRAPPED,

87

/** Automatically detect the format */

88

AUTO_DETECT

89

}

90

```

91

92

**Usage Examples:**

93

94

```kotlin

95

import kotlinx.serialization.*

96

import kotlinx.serialization.json.*

97

import java.io.*

98

99

@Serializable

100

data class LogEntry(

101

val timestamp: Long,

102

val level: String,

103

val message: String,

104

val metadata: Map<String, String> = emptyMap()

105

)

106

107

// Writing to streams

108

val entries = listOf(

109

LogEntry(System.currentTimeMillis(), "INFO", "Application started"),

110

LogEntry(System.currentTimeMillis(), "DEBUG", "Configuration loaded"),

111

LogEntry(System.currentTimeMillis(), "ERROR", "Database connection failed")

112

)

113

114

// Encode single object to stream

115

ByteArrayOutputStream().use { output ->

116

Json.encodeToStream(entries, output)

117

val jsonBytes = output.toByteArray()

118

println(String(jsonBytes))

119

}

120

121

// Encode to file

122

FileOutputStream("logs.json").use { fileOutput ->

123

Json.encodeToStream(entries, fileOutput)

124

}

125

126

// Reading from streams

127

FileInputStream("logs.json").use { fileInput ->

128

val loadedEntries = Json.decodeFromStream<List<LogEntry>>(fileInput)

129

loadedEntries.forEach { println(it) }

130

}

131

132

// Process large JSON array as sequence to avoid loading all into memory

133

FileInputStream("large-logs.json").use { input ->

134

val sequence = Json.decodeToSequence<LogEntry>(input, DecodeSequenceMode.ARRAY_WRAPPED)

135

sequence

136

.filter { it.level == "ERROR" }

137

.take(100)

138

.forEach { println("Error: ${it.message}") }

139

}

140

```

141

142

**Streaming JSON Sequences:**

143

144

```kotlin

145

import kotlinx.serialization.*

146

import kotlinx.serialization.json.*

147

import java.io.*

148

149

@Serializable

150

data class SensorReading(

151

val sensorId: String,

152

val timestamp: Long,

153

val temperature: Double,

154

val humidity: Double

155

)

156

157

// Reading whitespace-separated JSON objects

158

val whitespaceSeparatedJson = """

159

{"sensorId":"temp001","timestamp":1234567890,"temperature":22.5,"humidity":45.0}

160

{"sensorId":"temp002","timestamp":1234567891,"temperature":23.1,"humidity":46.2}

161

{"sensorId":"temp001","timestamp":1234567892,"temperature":22.8,"humidity":44.8}

162

"""

163

164

ByteArrayInputStream(whitespaceSeparatedJson.toByteArray()).use { input ->

165

val readings = Json.decodeToSequence<SensorReading>(

166

input,

167

DecodeSequenceMode.WHITESPACE_SEPARATED

168

)

169

170

readings.forEach { reading ->

171

println("Sensor ${reading.sensorId}: ${reading.temperature}°C, ${reading.humidity}% humidity")

172

}

173

}

174

175

// Reading array-wrapped format

176

val arrayWrappedJson = """

177

[

178

{"sensorId":"temp001","timestamp":1234567890,"temperature":22.5,"humidity":45.0},

179

{"sensorId":"temp002","timestamp":1234567891,"temperature":23.1,"humidity":46.2}

180

]

181

"""

182

183

ByteArrayInputStream(arrayWrappedJson.toByteArray()).use { input ->

184

val readings = Json.decodeToSequence<SensorReading>(

185

input,

186

DecodeSequenceMode.ARRAY_WRAPPED

187

)

188

189

val avgTemp = readings.map { it.temperature }.average()

190

println("Average temperature: $avgTemp°C")

191

}

192

193

// Auto-detect format

194

ByteArrayInputStream(whitespaceSeparatedJson.toByteArray()).use { input ->

195

val readings = Json.decodeToSequence<SensorReading>(

196

input,

197

DecodeSequenceMode.AUTO_DETECT // Will detect whitespace-separated format

198

)

199

200

readings.forEach { println(it) }

201

}

202

```

203

204

### JavaScript Dynamic Object Interop

205

206

JavaScript-specific extensions for seamless interoperability with JavaScript's dynamic object system.

207

208

```kotlin { .api }

209

/**

210

* Deserialize from JavaScript dynamic object

211

* @param deserializer Deserialization strategy for type T

212

* @param dynamic JavaScript dynamic object

213

* @return Deserialized Kotlin object of type T

214

*/

215

@ExperimentalSerializationApi

216

fun <T> Json.decodeFromDynamic(

217

deserializer: DeserializationStrategy<T>,

218

dynamic: dynamic

219

): T

220

221

/**

222

* Deserialize from JavaScript dynamic object using reified type

223

* @param dynamic JavaScript dynamic object

224

* @return Deserialized Kotlin object of type T

225

*/

226

@ExperimentalSerializationApi

227

inline fun <reified T> Json.decodeFromDynamic(dynamic: dynamic): T

228

229

/**

230

* Serialize to JavaScript dynamic object

231

* @param serializer Serialization strategy for type T

232

* @param value Kotlin object to serialize

233

* @return JavaScript dynamic object

234

*/

235

@ExperimentalSerializationApi

236

fun <T> Json.encodeToDynamic(

237

serializer: SerializationStrategy<T>,

238

value: T

239

): dynamic

240

241

/**

242

* Serialize to JavaScript dynamic object using reified type

243

* @param value Kotlin object to serialize

244

* @return JavaScript dynamic object

245

*/

246

@ExperimentalSerializationApi

247

inline fun <reified T> Json.encodeToDynamic(value: T): dynamic

248

```

249

250

**Usage Examples:**

251

252

```kotlin

253

// Kotlin/JS specific code

254

import kotlinx.serialization.*

255

import kotlinx.serialization.json.*

256

257

@Serializable

258

data class UserProfile(

259

val id: Int,

260

val name: String,

261

val email: String,

262

val preferences: Map<String, String>

263

)

264

265

// Working with JavaScript objects in Kotlin/JS

266

external interface JsUserProfile {

267

val id: Int

268

val name: String

269

val email: String

270

val preferences: dynamic

271

}

272

273

// Convert from JavaScript object to Kotlin data class

274

fun processJavaScriptUser(jsUser: JsUserProfile): UserProfile {

275

// Convert JS object to dynamic, then to Kotlin object

276

return Json.decodeFromDynamic<UserProfile>(jsUser.asDynamic())

277

}

278

279

// Convert Kotlin object to JavaScript object

280

fun createJavaScriptUser(user: UserProfile): dynamic {

281

return Json.encodeToDynamic(user)

282

}

283

284

// Usage with browser APIs

285

fun saveUserToLocalStorage(user: UserProfile) {

286

val jsObject = Json.encodeToDynamic(user)

287

kotlinx.browser.localStorage.setItem("user", JSON.stringify(jsObject))

288

}

289

290

fun loadUserFromLocalStorage(): UserProfile? {

291

val userJson = kotlinx.browser.localStorage.getItem("user") ?: return null

292

val jsObject = JSON.parse<dynamic>(userJson)

293

return Json.decodeFromDynamic<UserProfile>(jsObject)

294

}

295

```

296

297

**Advanced JavaScript Interop:**

298

299

```kotlin

300

// Kotlin/JS specific code

301

import kotlinx.serialization.*

302

import kotlinx.serialization.json.*

303

304

@Serializable

305

data class ApiResponse<T>(

306

val success: Boolean,

307

val data: T?,

308

val error: String?,

309

val metadata: Map<String, String> = emptyMap()

310

)

311

312

@Serializable

313

data class Product(

314

val id: Int,

315

val name: String,

316

val price: Double,

317

val categories: List<String>

318

)

319

320

// Interop with JavaScript fetch API

321

suspend fun fetchProducts(): List<Product> {

322

val response = kotlinx.browser.window.fetch("/api/products").await()

323

val jsObject = response.json().await()

324

325

val apiResponse = Json.decodeFromDynamic<ApiResponse<List<Product>>>(jsObject)

326

327

return if (apiResponse.success) {

328

apiResponse.data ?: emptyList()

329

} else {

330

throw Exception(apiResponse.error ?: "Unknown error")

331

}

332

}

333

334

// Send data to JavaScript API

335

suspend fun createProduct(product: Product): Product {

336

val jsProduct = Json.encodeToDynamic(product)

337

338

val response = kotlinx.browser.window.fetch("/api/products", object {

339

val method = "POST"

340

val headers = js("{}")

341

val body = JSON.stringify(jsProduct)

342

}.asDynamic()).await()

343

344

val jsResult = response.json().await()

345

val apiResponse = Json.decodeFromDynamic<ApiResponse<Product>>(jsResult)

346

347

return if (apiResponse.success) {

348

apiResponse.data ?: throw Exception("No product data returned")

349

} else {

350

throw Exception(apiResponse.error ?: "Failed to create product")

351

}

352

}

353

354

// Working with complex nested JavaScript objects

355

external interface ComplexJsObject {

356

val users: Array<dynamic>

357

val settings: dynamic

358

val metadata: dynamic

359

}

360

361

fun processComplexObject(jsObj: ComplexJsObject) {

362

// Convert JavaScript arrays and objects to Kotlin types

363

val users = jsObj.users.map { userJs ->

364

Json.decodeFromDynamic<UserProfile>(userJs)

365

}

366

367

val settings = Json.decodeFromDynamic<Map<String, String>>(jsObj.settings)

368

369

val metadata = Json.decodeFromDynamic<Map<String, Any>>(jsObj.metadata)

370

371

// Process the converted data

372

users.forEach { user ->

373

println("Processing user: ${user.name}")

374

}

375

}

376

```

377

378

### Error Handling in Platform APIs

379

380

Platform-specific APIs can throw additional exceptions related to I/O operations.

381

382

```kotlin

383

import kotlinx.serialization.json.*

384

import java.io.*

385

386

fun safeStreamProcessing(inputFile: String, outputFile: String) {

387

try {

388

FileInputStream(inputFile).use { input ->

389

FileOutputStream(outputFile).use { output ->

390

val data = Json.decodeFromStream<List<String>>(input)

391

val processed = data.map { it.uppercase() }

392

Json.encodeToStream(processed, output)

393

}

394

}

395

} catch (e: IOException) {

396

println("File I/O error: ${e.message}")

397

} catch (e: SerializationException) {

398

println("JSON serialization error: ${e.message}")

399

} catch (e: Exception) {

400

println("Unexpected error: ${e.message}")

401

}

402

}

403

404

// JavaScript error handling

405

fun safeDynamicProcessing(jsObject: dynamic): UserProfile? {

406

return try {

407

Json.decodeFromDynamic<UserProfile>(jsObject)

408

} catch (e: SerializationException) {

409

console.log("Failed to decode JavaScript object: ${e.message}")

410

null

411

} catch (e: Exception) {

412

console.log("Unexpected error: ${e.message}")

413

null

414

}

415

}

416

```

417

418

### Performance Considerations

419

420

**JVM Streams:**

421

- **Memory Efficiency**: Stream APIs avoid loading entire JSON into memory

422

- **Sequence Processing**: `decodeToSequence` enables lazy evaluation for large datasets

423

- **I/O Performance**: Direct stream operations reduce intermediate string allocations

424

425

**JavaScript Dynamic Interop:**

426

- **Object Conversion**: Dynamic object conversion has overhead; cache converted objects when possible

427

- **Type Safety**: Runtime type checking is performed during dynamic conversions

428

- **Memory Usage**: Large objects may require additional memory during conversion

429

430

### Platform Detection

431

432

Code using platform-specific APIs should handle multiplatform scenarios appropriately:

433

434

```kotlin

435

// Multiplatform code structure

436

expect fun platformSpecificJsonProcessing(data: String): String

437

438

// JVM implementation

439

actual fun platformSpecificJsonProcessing(data: String): String {

440

return ByteArrayInputStream(data.toByteArray()).use { input ->

441

val objects = Json.decodeToSequence<Map<String, Any>>(input)

442

val processed = objects.map { /* process */ }.toList()

443

Json.encodeToString(processed)

444

}

445

}

446

447

// JS implementation

448

actual fun platformSpecificJsonProcessing(data: String): String {

449

val jsObject = JSON.parse<dynamic>(data)

450

val kotlinObject = Json.decodeFromDynamic<Map<String, Any>>(jsObject)

451

val processed = /* process kotlinObject */

452

return Json.encodeToString(processed)

453

}

454

```