or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

builtin-types.mdcore-serialization.mdindex.mdjson-integration.mdmessagepack-integration.mdsealed-traits.mdstreaming.mdtype-classes.md

json-integration.mddocs/

0

# JSON Integration

1

2

Direct integration with ujson for working with JSON AST and value types. This provides seamless interoperability between uPickle serialization and ujson manipulation.

3

4

## Capabilities

5

6

### JSON AST Writing

7

8

Writes Scala values directly to ujson AST types for manipulation and processing.

9

10

```scala { .api }

11

/**

12

* Write the given Scala value as a JSON struct (ujson.Value)

13

* @param t Value to serialize

14

* @return ujson.Value representation

15

*/

16

def writeJs[T: Writer](t: T): ujson.Value

17

```

18

19

**Usage Examples:**

20

21

```scala

22

import upickle.default._

23

import ujson._

24

25

case class Person(name: String, age: Int)

26

val person = Person("Alice", 30)

27

28

// Convert to ujson AST

29

val jsonAst = writeJs(person)

30

// Result: ujson.Obj("name" -> ujson.Str("Alice"), "age" -> ujson.Num(30))

31

32

// Manipulate JSON AST

33

val modifiedAst = jsonAst.obj("age") = ujson.Num(31)

34

35

// Convert back to string

36

val jsonString = jsonAst.toString

37

// Result: {"name":"Alice","age":30}

38

39

// Pretty print

40

val prettyJson = ujson.write(jsonAst, indent = 2)

41

```

42

43

### ujson.Value Reader and Writer

44

45

Built-in support for reading and writing ujson.Value and its subtypes.

46

47

```scala { .api }

48

/**

49

* Reader for generic ujson.Value

50

*/

51

implicit def JsValueR: Reader[ujson.Value]

52

53

/**

54

* Writer for generic ujson.Value

55

*/

56

implicit def JsValueW: Writer[ujson.Value]

57

```

58

59

**Usage Examples:**

60

61

```scala

62

import upickle.default._

63

import ujson._

64

65

// Reading ujson.Value from JSON string

66

val jsonStr = """{"name":"Alice","items":[1,2,3],"active":true}"""

67

val jsonValue = read[ujson.Value](jsonStr)

68

69

// Working with the parsed value

70

val name = jsonValue("name").str // "Alice"

71

val items = jsonValue("items").arr.map(_.num.toInt) // List(1, 2, 3)

72

val active = jsonValue("active").bool // true

73

74

// Writing ujson.Value back to JSON

75

val backToJson = write(jsonValue)

76

```

77

78

### Specific ujson Type Readers

79

80

Readers for specific ujson value types with type safety.

81

82

```scala { .api }

83

implicit def JsObjR: Reader[ujson.Obj]

84

implicit def JsArrR: Reader[ujson.Arr]

85

implicit def JsStrR: Reader[ujson.Str]

86

implicit def JsNumR: Reader[ujson.Num]

87

implicit def JsBoolR: Reader[ujson.Bool]

88

implicit def JsTrueR: Reader[ujson.True.type]

89

implicit def JsFalseR: Reader[ujson.False.type]

90

implicit def JsNullR: Reader[ujson.Null.type]

91

```

92

93

**Usage Examples:**

94

95

```scala

96

import upickle.default._

97

import ujson._

98

99

// Read specific JSON types

100

val objValue = read[ujson.Obj]("""{"key":"value"}""")

101

val arrValue = read[ujson.Arr]("""[1,2,3]""")

102

val strValue = read[ujson.Str](""""hello"""")

103

val numValue = read[ujson.Num]("""42.5""")

104

val boolValue = read[ujson.Bool]("""true""")

105

val nullValue = read[ujson.Null.type]("""null""")

106

107

// Type-safe access

108

val keyValue = objValue.value("key") // ujson.Str

109

val firstItem = arrValue.value(0) // ujson.Num

110

val stringContent = strValue.value // String

111

val numberContent = numValue.value // Double

112

```

113

114

### Specific ujson Type Writers

115

116

Writers for specific ujson value types.

117

118

```scala { .api }

119

implicit def JsObjW: Writer[ujson.Obj]

120

implicit def JsArrW: Writer[ujson.Arr]

121

implicit def JsStrW: Writer[ujson.Str]

122

implicit def JsNumW: Writer[ujson.Num]

123

implicit def JsBoolW: Writer[ujson.Bool]

124

implicit def JsTrueW: Writer[ujson.True.type]

125

implicit def JsFalseW: Writer[ujson.False.type]

126

implicit def JsNullW: Writer[ujson.Null.type]

127

```

128

129

**Usage Examples:**

130

131

```scala

132

import upickle.default._

133

import ujson._

134

135

// Create ujson values

136

val obj = ujson.Obj("name" -> ujson.Str("Alice"), "age" -> ujson.Num(30))

137

val arr = ujson.Arr(ujson.Num(1), ujson.Num(2), ujson.Num(3))

138

139

// Write specific types back to JSON

140

val objJson = write(obj) // {"name":"Alice","age":30}

141

val arrJson = write(arr) // [1,2,3]

142

val strJson = write(ujson.Str("hello")) // "hello"

143

val numJson = write(ujson.Num(42)) // 42

144

```

145

146

### JSON Transformation Patterns

147

148

Common patterns for working with JSON data using ujson integration.

149

150

**Usage Examples:**

151

152

```scala

153

import upickle.default._

154

import ujson._

155

156

// Transform JSON structure

157

def transformJson(input: String): String = {

158

val json = read[ujson.Value](input)

159

160

// Add timestamp

161

json("timestamp") = ujson.Str(java.time.Instant.now().toString)

162

163

// Transform nested objects

164

json("users").arr.foreach { user =>

165

user("id") = ujson.Str(java.util.UUID.randomUUID().toString)

166

}

167

168

write(json)

169

}

170

171

// Merge JSON objects

172

def mergeJson(json1: String, json2: String): String = {

173

val obj1 = read[ujson.Obj](json1)

174

val obj2 = read[ujson.Obj](json2)

175

176

// Merge objects

177

obj2.value.foreach { case (key, value) =>

178

obj1(key) = value

179

}

180

181

write(obj1)

182

}

183

184

// Filter JSON arrays

185

def filterJsonArray(input: String, predicate: ujson.Value => Boolean): String = {

186

val json = read[ujson.Value](input)

187

188

json match {

189

case arr: ujson.Arr =>

190

val filtered = ujson.Arr(arr.value.filter(predicate): _*)

191

write(filtered)

192

case _ => input

193

}

194

}

195

196

// Usage examples

197

val original = """{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}"""

198

val transformed = transformJson(original)

199

200

val json1 = """{"a":1,"b":2}"""

201

val json2 = """{"c":3,"d":4}"""

202

val merged = mergeJson(json1, json2) // {"a":1,"b":2,"c":3,"d":4}

203

204

val arrayJson = """[1,2,3,4,5]"""

205

val filtered = filterJsonArray(arrayJson, _.num > 3) // [4,5]

206

```

207

208

### Direct ujson Operations

209

210

Core ujson module functions for JSON processing and manipulation.

211

212

```scala { .api }

213

/**

214

* Read JSON input into ujson.Value AST

215

* @param s JSON input (string, InputStream, etc.)

216

* @param trace Enable tracing for debugging

217

* @return ujson.Value AST representation

218

*/

219

def ujson.read(s: ujson.Readable, trace: Boolean = false): ujson.Value

220

221

/**

222

* Write ujson.Value to JSON string

223

* @param t ujson.Value to serialize

224

* @param indent Indentation level (-1 for compact, >=0 for pretty printing)

225

* @param escapeUnicode Whether to escape unicode characters

226

* @param sortKeys Whether to sort object keys alphabetically

227

* @return JSON string representation

228

*/

229

def ujson.write(t: ujson.Value, indent: Int = -1, escapeUnicode: Boolean = false, sortKeys: Boolean = false): String

230

231

/**

232

* Write ujson.Value directly to Writer

233

*/

234

def ujson.writeTo(t: ujson.Value, out: java.io.Writer, indent: Int = -1, escapeUnicode: Boolean = false, sortKeys: Boolean = false): Unit

235

236

/**

237

* Write ujson.Value to OutputStream as UTF-8 bytes

238

*/

239

def ujson.writeToOutputStream(t: ujson.Value, out: java.io.OutputStream, indent: Int = -1, escapeUnicode: Boolean = false, sortKeys: Boolean = false): Unit

240

241

/**

242

* Write ujson.Value to byte array

243

*/

244

def ujson.writeToByteArray(t: ujson.Value, indent: Int = -1, escapeUnicode: Boolean = false, sortKeys: Boolean = false): Array[Byte]

245

```

246

247

**Usage Examples:**

248

249

```scala

250

import ujson._

251

252

// Direct ujson operations

253

val jsonString = """{"name":"Alice","scores":[85,90,88],"active":true}"""

254

255

// Parse to ujson.Value

256

val jsonAst = ujson.read(jsonString)

257

258

// Access values

259

val name = jsonAst("name").str // "Alice"

260

val scores = jsonAst("scores").arr.map(_.num.toInt) // Vector(85, 90, 88)

261

val active = jsonAst("active").bool // true

262

263

// Modify the AST

264

jsonAst("active") = ujson.Bool(false)

265

jsonAst("lastLogin") = ujson.Str("2024-01-15")

266

267

// Write back to JSON

268

val modifiedJson = ujson.write(jsonAst, indent = 2)

269

270

// Write to file

271

val fileWriter = new java.io.FileWriter("output.json")

272

try {

273

ujson.writeTo(jsonAst, fileWriter, indent = 2)

274

} finally {

275

fileWriter.close()

276

}

277

278

// Write to byte array for network transmission

279

val jsonBytes = ujson.writeToByteArray(jsonAst)

280

```

281

282

### JSON Validation

283

284

Validate JSON input without parsing to check syntax correctness.

285

286

```scala { .api }

287

/**

288

* Validate JSON syntax without full parsing

289

* @param s JSON input to validate

290

* @throws ujson.ParseException if invalid JSON

291

*/

292

def ujson.validate(s: ujson.Readable): Unit

293

```

294

295

**Usage Examples:**

296

297

```scala

298

import ujson._

299

300

// Validate JSON strings

301

try {

302

ujson.validate("""{"valid": "json"}""")

303

println("Valid JSON")

304

} catch {

305

case e: ujson.ParseException => println(s"Invalid JSON: ${e.getMessage}")

306

}

307

308

// Validate JSON from file

309

try {

310

val fileContent = scala.io.Source.fromFile("data.json").mkString

311

ujson.validate(fileContent)

312

println("File contains valid JSON")

313

} catch {

314

case e: ujson.ParseException => println(s"Invalid JSON in file: ${e.getMessage}")

315

}

316

317

// Use before expensive parsing operations

318

def safeParseJson(input: String): Option[ujson.Value] = {

319

try {

320

ujson.validate(input)

321

Some(ujson.read(input))

322

} catch {

323

case _: ujson.ParseException => None

324

}

325

}

326

```

327

328

### JSON Reformatting

329

330

Reformat JSON with different styles without full object model conversion.

331

332

```scala { .api }

333

/**

334

* Reformat JSON input with new formatting options

335

* @param s JSON input to reformat

336

* @param indent Indentation level (-1 for compact, >=0 for pretty printing)

337

* @param escapeUnicode Whether to escape unicode characters

338

* @param sortKeys Whether to sort object keys alphabetically

339

* @return Reformatted JSON string

340

*/

341

def ujson.reformat(s: ujson.Readable, indent: Int = -1, escapeUnicode: Boolean = false, sortKeys: Boolean = false): String

342

343

/**

344

* Reformat JSON directly to Writer

345

*/

346

def ujson.reformatTo(s: ujson.Readable, out: java.io.Writer, indent: Int = -1, escapeUnicode: Boolean = false, sortKeys: Boolean = false): Unit

347

348

/**

349

* Reformat JSON to OutputStream

350

*/

351

def ujson.reformatToOutputStream(s: ujson.Readable, out: java.io.OutputStream, indent: Int = -1, escapeUnicode: Boolean = false, sortKeys: Boolean = false): Unit

352

353

/**

354

* Reformat JSON to byte array

355

*/

356

def ujson.reformatToByteArray(s: ujson.Readable, indent: Int = -1, escapeUnicode: Boolean = false, sortKeys: Boolean = false): Array[Byte]

357

```

358

359

**Usage Examples:**

360

361

```scala

362

import ujson._

363

364

// Compact JSON to pretty-printed

365

val compactJson = """{"name":"Alice","data":{"scores":[85,90,88],"active":true}}"""

366

val prettyJson = ujson.reformat(compactJson, indent = 2)

367

println(prettyJson)

368

// Result:

369

// {

370

// "name": "Alice",

371

// "data": {

372

// "scores": [85, 90, 88],

373

// "active": true

374

// }

375

// }

376

377

// Sort keys alphabetically

378

val sortedJson = ujson.reformat(compactJson, indent = 2, sortKeys = true)

379

380

// Escape unicode characters

381

val unicodeJson = """{"message":"Hello 世界"}"""

382

val escapedJson = ujson.reformat(unicodeJson, escapeUnicode = true)

383

// Result: {"message":"Hello \\u4e16\\u754c"}

384

385

// Reformat large file without loading into memory

386

val inputFile = new java.io.FileInputStream("input.json")

387

val outputFile = new java.io.FileOutputStream("output.json")

388

try {

389

ujson.reformatToOutputStream(inputFile, outputFile, indent = 2, sortKeys = true)

390

} finally {

391

inputFile.close()

392

outputFile.close()

393

}

394

```

395

396

### Low-level JSON Processing

397

398

Advanced functions for custom JSON processing workflows.

399

400

```scala { .api }

401

/**

402

* Transform JSON using custom visitor

403

* @param t JSON input

404

* @param v Custom visitor for processing

405

* @param sortKeys Whether to sort keys during processing

406

*/

407

def ujson.transform[T](t: ujson.Readable, v: upickle.core.Visitor[_, T], sortKeys: Boolean = false): T

408

409

/**

410

* Copy ujson.Value creating a deep clone

411

* @param t ujson.Value to copy

412

* @return Deep copy of the input

413

*/

414

def ujson.copy(t: ujson.Value): ujson.Value

415

```

416

417

**Usage Examples:**

418

419

```scala

420

import ujson._

421

import upickle.core._

422

423

// Custom visitor to count JSON elements

424

class CountingVisitor extends Visitor[Any, Int] {

425

private var count = 0

426

427

override def visitArray(length: Int, index: Int) = new ArrVisitor[Any, Int] {

428

def subVisitor = CountingVisitor.this

429

def visitValue(v: Any, index: Int): Unit = count += 1

430

def visitEnd(index: Int) = count

431

}

432

433

override def visitObject(length: Int, jsonableKeys: Boolean, index: Int) = new ObjVisitor[Any, Int] {

434

def subVisitor = CountingVisitor.this

435

def visitKey(index: Int) = CountingVisitor.this

436

def visitKeyValue(s: Any): Unit = {}

437

def visitValue(v: Any, index: Int): Unit = count += 1

438

def visitEnd(index: Int) = count

439

}

440

441

override def visitString(s: CharSequence, index: Int) = { count += 1; count }

442

override def visitNum(d: Double, decIndex: Int, expIndex: Int, index: Int) = { count += 1; count }

443

override def visitBool(b: Boolean, index: Int) = { count += 1; count }

444

override def visitNull(index: Int) = { count += 1; count }

445

}

446

447

// Count elements in JSON

448

val jsonString = """{"users":[{"name":"Alice"},{"name":"Bob"}],"count":2}"""

449

val elementCount = ujson.transform(jsonString, new CountingVisitor())

450

println(s"JSON contains $elementCount elements")

451

452

// Deep copy ujson.Value

453

val original = ujson.Obj("data" -> ujson.Arr(ujson.Num(1), ujson.Num(2)))

454

val copied = ujson.copy(original)

455

456

// Modify copy without affecting original

457

copied("data").arr += ujson.Num(3)

458

println(ujson.write(original)) // {"data":[1,2]}

459

println(ujson.write(copied)) // {"data":[1,2,3]}

460

```

461

462

### Mixed Type Serialization

463

464

Using ujson integration for heterogeneous data structures.

465

466

**Usage Examples:**

467

468

```scala

469

import upickle.default._

470

import ujson._

471

472

// Working with mixed data types

473

case class MixedData(

474

metadata: ujson.Obj,

475

payload: ujson.Value,

476

timestamp: Long

477

)

478

479

implicit val mixedDataRW: ReadWriter[MixedData] = macroRW

480

481

val mixedData = MixedData(

482

metadata = ujson.Obj("version" -> ujson.Str("1.0"), "source" -> ujson.Str("api")),

483

payload = ujson.Arr(ujson.Num(1), ujson.Str("test"), ujson.Bool(true)),

484

timestamp = System.currentTimeMillis()

485

)

486

487

val json = write(mixedData)

488

val parsed = read[MixedData](json)

489

490

// Dynamic JSON construction

491

def buildDynamicJson(data: Map[String, Any]): ujson.Value = {

492

val obj = ujson.Obj()

493

494

data.foreach {

495

case (key, value: String) => obj(key) = ujson.Str(value)

496

case (key, value: Int) => obj(key) = ujson.Num(value)

497

case (key, value: Double) => obj(key) = ujson.Num(value)

498

case (key, value: Boolean) => obj(key) = ujson.Bool(value)

499

case (key, value: List[_]) => obj(key) = ujson.Arr(value.map(writeJs): _*)

500

case (key, null) => obj(key) = ujson.Null

501

case (key, value) => obj(key) = writeJs(value)

502

}

503

504

obj

505

}

506

507

val dynamicData = Map(

508

"name" -> "Alice",

509

"age" -> 30,

510

"active" -> true,

511

"scores" -> List(85.5, 90.0, 88.5)

512

)

513

514

val dynamicJson = buildDynamicJson(dynamicData)

515

val jsonString = write(dynamicJson)

516

```

517

518

## Types

519

520

```scala { .api }

521

/**

522

* ujson.Value is the base type for all JSON AST nodes

523

*/

524

sealed trait ujson.Value {

525

def apply(s: ujson.Selector): ujson.Value

526

def update(s: ujson.Selector, v: ujson.Value): Unit

527

}

528

529

/**

530

* Specific ujson value types

531

*/

532

case class ujson.Obj(value: mutable.LinkedHashMap[String, ujson.Value]) extends ujson.Value

533

case class ujson.Arr(value: mutable.Buffer[ujson.Value]) extends ujson.Value

534

case class ujson.Str(value: String) extends ujson.Value

535

case class ujson.Num(value: Double) extends ujson.Value

536

case class ujson.Bool(value: Boolean) extends ujson.Value

537

case object ujson.True extends ujson.Bool(true)

538

case object ujson.False extends ujson.Bool(false)

539

case object ujson.Null extends ujson.Value

540

541

/**

542

* ujson.Readable represents sources that can provide JSON data

543

*/

544

trait ujson.Readable {

545

def transform[T](f: ujson.Visitor[_, T]): T

546

}

547

```