### Standalone MessagePack Manipulation with upack.read/write Source: https://context7.com/com-lihaoyi/upickle/llms.txt Parse and produce MessagePack binary data using the upack.Msg AST directly, independent of upickle's typeclass system. Supports building Msg manually, serializing to bytes, deserializing, AST navigation, writing to streams, and validation. ```scala import upack._ // Build a Msg manually val msg = upack.Obj( upack.Str("id") -> upack.Int32(1), upack.Str("name") -> upack.Str("Alice"), upack.Str("data") -> upack.Arr(upack.Float64(1.5), upack.Bool(true), upack.Null) ) // Serialize to bytes val bytes: Array[Byte] = upack.write(msg) // Deserialize back val parsed: upack.Msg = upack.read(bytes) // Navigate the AST parsed.obj(upack.Str("name")).str // "Alice" parsed.obj(upack.Str("id")).int32 // 1 parsed.obj(upack.Str("data")).arr(0).float64 // 1.5 // Write to OutputStream val out = new java.io.ByteArrayOutputStream upack.writeTo(msg, out) // Validate without building AST upack.validate(bytes) // succeeds silently // Ext type (custom MessagePack extension) val ext = upack.Ext(tag = 1, data = Array[Byte](0x01, 0x02)) val extBytes = upack.write(upack.Arr(ext)) ``` -------------------------------- ### MessagePack Serialization with upickle.default.readBinary / writeBinary Source: https://context7.com/com-lihaoyi/upickle/llms.txt Serializes Scala values to and from compact binary MessagePack format. Accepts any upack.Readable (byte array, Array[Byte], InputStream). Primitives and collections work identically to complex types. ```scala import upickle.default._ case class Event(id: Long, name: String, tags: List[String]) object Event { implicit val rw: ReadWriter[Event] = macroRW } val ev = Event(1L, "click", List("ui", "web")) // Serialize to MessagePack bytes val bytes: Array[Byte] = writeBinary(ev) // Deserialize from bytes val ev2 = readBinary[Event](bytes) assert(ev == ev2) // Write to OutputStream val baos = new java.io.ByteArrayOutputStream writeBinaryTo(ev, baos) // Primitives and collections work identically val numBytes = writeBinary(42) assert(readBinary[Int](numBytes) == 42) val listBytes = writeBinary(List("a", "b", "c")) assert(readBinary[List[String]](listBytes) == List("a", "b", "c")) ``` -------------------------------- ### Fine-grained control annotations: @upickle.implicits.allowUnknownKeys / serializeDefaults Source: https://context7.com/com-lihaoyi/upickle/llms.txt Control unknown key handling and default value serialization on a per-class basis, overriding global configurations. ```APIDOC ## `@upickle.implicits.allowUnknownKeys` / `serializeDefaults` — Fine-grained control annotations Per-class control over unknown key handling and default value serialization, overriding the pickler-level configuration. ```scala import upickle.default._ import upickle.implicits.{allowUnknownKeys, serializeDefaults} // By default, unknown keys are silently ignored case class Flexible(id: Int, name: String) object Flexible { implicit val rw: ReadWriter[Flexible] = macroRW } read[Flexible]{"{"id":1,"name":"x","extra":"ignored"}"} // Reject unknown keys for this class specifically @allowUnknownKeys(false) case class Strict(id: Int, name: String) object Strict { implicit val rw: ReadWriter[Strict] = macroRW } try read[Strict]{"{"id":1,"name":"x","extra":"fail"}"} catch { case e: upickle.core.AbortException => println("unknown key rejected") } // Always write default values for this class @serializeDefaults(true) case class WithDefaults(x: Int = 0, y: Int = 0) object WithDefaults { implicit val rw: ReadWriter[WithDefaults] = macroRW } write(WithDefaults()) // => "{\"x\":0,\"y\":0}" (defaults included) ``` ``` -------------------------------- ### Standalone MessagePack Manipulation Source: https://context7.com/com-lihaoyi/upickle/llms.txt Utilize `upack.read` and `upack.write` for direct MessagePack binary data parsing into the `upack.Msg` AST and serialization. This operates independently of upickle's typeclass system. ```APIDOC ## `upack.read` / `write` — Standalone MessagePack manipulation Parse and produce MessagePack binary data using the `upack.Msg` AST directly, independent of upickle's typeclass system. ```scala import upack._ // Build a Msg manually val msg = upack.Obj( upack.Str("id") -> upack.Int32(1), upack.Str("name") -> upack.Str("Alice"), upack.Str("data") -> upack.Arr(upack.Float64(1.5), upack.Bool(true), upack.Null) ) // Serialize to bytes val bytes: Array[Byte] = upack.write(msg) // Deserialize back val parsed: upack.Msg = upack.read(bytes) // Navigate the AST parsed.obj(upack.Str("name")).str // "Alice" parsed.obj(upack.Str("id")).int32 // 1 parsed.obj(upack.Str("data")).arr(0).float64 // 1.5 // Write to OutputStream val out = new java.io.ByteArrayOutputStream upack.writeTo(msg, out) // Validate without building AST upack.validate(bytes) // succeeds silently // Ext type (custom MessagePack extension) val ext = upack.Ext(tag = 1, data = Array[Byte](0x01, 0x02)) val extBytes = upack.write(upack.Arr(ext)) ``` ``` -------------------------------- ### Custom Pickler Instances Source: https://context7.com/com-lihaoyi/upickle/llms.txt Configure custom serialization behavior by creating an `upickle.AttributeTagged` object. This allows overriding settings like discriminator key names, key mappings, default value handling, and unknown key policies. ```APIDOC ## Custom upickle pickler instances — Configuration overrides Create a custom `upickle.AttributeTagged` object to override global serialization behavior: discriminator key name, key mapping, default value handling, fully-qualified type names, and unknown key policy. ```scala // Custom pickler: snake_case keys, "_tag" discriminator, reject unknown keys object MyPickler extends upickle.AttributeTagged { override def tagName: String = "_tag" override def allowUnknownKeys: Boolean = false override def serializeDefaults: Boolean = true override def objectAttributeKeyReadMap(s: CharSequence): CharSequence = s.toString.split("_").zipWithIndex.map { case (w, 0) => w case (w, _) => w.capitalize }.mkString override def objectAttributeKeyWriteMap(s: CharSequence): CharSequence = s.toString.replaceAll("([A-Z])", "_$1").toLowerCase.stripPrefix("_") } case class UserProfile(userId: Int, firstName: String) object UserProfile { implicit val rw: MyPickler.ReadWriter[UserProfile] = MyPickler.macroRW } MyPickler.write(UserProfile(1, "Alice")) // => "{\"user_id\":1,\"first_name\":\"Alice\"}" MyPickler.read[UserProfile]("{\"user_id\":2,\"first_name\":\"Bob\"}") // UserProfile(2, "Bob") ``` ``` -------------------------------- ### upickle.default.readBinary / writeBinary Source: https://context7.com/com-lihaoyi/upickle/llms.txt Serializes Scala values to and from MessagePack binary format. Accepts any upack.Readable input for reading and writes to a stream for writing. ```APIDOC ## upickle.default.readBinary / writeBinary — MessagePack serialization Serializes Scala values to/from compact binary MessagePack format. Accepts any `upack.Readable` (byte array, `Array[Byte]`, `InputStream`) for reading, and supports writing to `OutputStream`. ### `readBinary[T]` Method `readBinary[T](input: upack.Readable)(implicit reader: Reader[T]): T` ### `writeBinary` Method `writeBinary[T](value: T)(implicit writer: Writer[T]): Array[Byte]` ### `writeBinaryTo` Method `writeBinaryTo[T](value: T, output: java.io.OutputStream)(implicit writer: Writer[T]): Unit` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```scala import upickle.default._ case class Event(id: Long, name: String, tags: List[String]) object Event { implicit val rw: ReadWriter[Event] = macroRW } val ev = Event(1L, "click", List("ui", "web")) // Serialize to MessagePack bytes val bytes: Array[Byte] = writeBinary(ev) // Deserialize from bytes val ev2 = readBinary[Event](bytes) assert(ev == ev2) // Write to OutputStream val baos = new java.io.ByteArrayOutputStream writeBinaryTo(ev, baos) // Primitives and collections work identically val numBytes = writeBinary(42) assert(readBinary[Int](numBytes) == 42) val listBytes = writeBinary(List("a", "b", "c")) assert(readBinary[List[String]](listBytes) == List("a", "b", "c")) ``` ### Response #### Success Response (`readBinary`) Returns the deserialized Scala value of type `T`. #### Success Response (`writeBinary`) Returns the MessagePack binary representation as an `Array[Byte]`. #### Success Response (`writeBinaryTo`) Writes the MessagePack binary representation to the provided `OutputStream`. ``` -------------------------------- ### Standalone JSON Parsing and Rendering Source: https://context7.com/com-lihaoyi/upickle/llms.txt Use `ujson.read` and `ujson.write` for direct JSON parsing into the `ujson.Value` AST and rendering JSON text. This is useful for dynamic JSON manipulation without involving upickle's typeclass system. ```APIDOC ## `ujson.read` / `write` — Standalone JSON parsing and rendering Parse JSON text directly into the `ujson.Value` AST without going through upickle's typeclass layer. Useful for dynamic JSON manipulation. ```scala import ujson._ // Parse val v: ujson.Value = ujson.read("{\"name\":\"Alice\",\"scores\":[10,20,30]}") // Traverse v("name").str // "Alice" v("scores")(1).num // 20.0 v("scores").arr.map(_.num) // ArrayBuffer(10.0, 20.0, 30.0) // Mutate in place v("name") = "Bob" v("scores")(0) = 99 ujson.write(v) // => "{\"name\":\"Bob\",\"scores\":[99,20,30]}" // Build from scratch val obj = ujson.Obj( "id" -> 42, "tags" -> ujson.Arr("scala", "json"), "meta" -> ujson.Obj("active" -> true, "score" -> 3.14) ) ujson.write(obj, indent = 2) // { // "id": 42, // "tags": ["scala","json"], // "meta": {"active":true,"score":3.14} // } // Reformat (parse + re-render with options, no full AST allocation) ujson.reformat("{\"b\":2,\"a\":1}", indent = 2, sortKeys = true) // => "{\n \"a\": 1,\n \"b\": 2\n}" // Validate (parse without building AST) ujson.validate("[1,2,3]") // succeeds silently ujson.validate("[1,2,\"") // throws ujson.ParseException ``` ``` -------------------------------- ### Control Unknown Keys and Default Serialization with Annotations Source: https://context7.com/com-lihaoyi/upickle/llms.txt Use `@allowUnknownKeys` to control whether unknown keys in JSON input are rejected or ignored for a specific case class. Use `@serializeDefaults` to control whether default values are included in the JSON output. ```scala import upickle.default._ import upickle.implicits.{allowUnknownKeys, serializeDefaults} // By default, unknown keys are silently ignored case class Flexible(id: Int, name: String) object Flexible { implicit val rw: ReadWriter[Flexible] = macroRW } read[Flexible]($""{"id":1,"name":"x","extra":"ignored"}$"") // Flexible(1,"x") // Reject unknown keys for this class specifically @allowUnknownKeys(false) case class Strict(id: Int, name: String) object Strict { implicit val rw: ReadWriter[Strict] = macroRW } try read[Strict]($""{"id":1,"name":"x","extra":"fail"}$"") catch { case e: upickle.core.AbortException => println("unknown key rejected") } // Always write default values for this class @serializeDefaults(true) case class WithDefaults(x: Int = 0, y: Int = 0) object WithDefaults { implicit val rw: ReadWriter[WithDefaults] = macroRW } write(WithDefaults()) // => $""{"x":0,"y":0}$"" (defaults included) ``` -------------------------------- ### Cross-Format Conversion with `writeJs`, `readJs`, and `transform` Source: https://context7.com/com-lihaoyi/upickle/llms.txt Convert between Scala values and `ujson.Value` ASTs, and between JSON and MessagePack ASTs, without intermediate string serialization. Use `writeJs` and `readJs` for JSON AST conversion, and `transform` for JSON string to MessagePack bytes. ```scala import upickle.default._ case class Config(host: String, port: Int) object Config { implicit val rw: ReadWriter[Config] = macroRW } // Scala value → ujson.Value AST val jsVal: ujson.Value = writeJs(Config("localhost", 8080)) // ujson.Obj(LinkedHashMap("host" -> Str("localhost"), "port" -> Num(8080.0))) jsVal("host").str // "localhost" jsVal("port").num // 8080.0 // ujson.Value AST → Scala value val cfg = read[Config](jsVal) // Config("localhost", 8080) // Scala value → upack.Msg AST val msgVal: upack.Msg = writeMsg(Config("localhost", 8080)) // Cross-format: JSON string → MessagePack bytes (no intermediate Scala object) val jsonStr = $""{"host":"example.com","port":443}$""" val msgBytes: Array[Byte] = transform(ujson.read(jsonStr)).to[Array[Byte]] // Or more explicitly: val msgFromJson = transform(jsonStr).to[upack.Msg] ``` -------------------------------- ### Streaming JSON and MessagePack Output Source: https://context7.com/com-lihaoyi/upickle/llms.txt Generate `geny.Writable` instances for streaming JSON or MessagePack data directly to an `OutputStream`. This enables zero-copy streaming, particularly useful for HTTP frameworks. ```APIDOC ## `upickle.default.stream` / `streamBinary` — Streaming output via `geny.Writable` Returns a `geny.Writable` that writes JSON or MessagePack bytes directly to an `OutputStream` on demand, enabling zero-copy streaming with HTTP frameworks that accept `geny.Writable`. ```scala import upickle.default._ case class Response(status: Int, body: String) object Response { implicit val rw: ReadWriter[Response] = macroRW } val resp = Response(200, "OK") // JSON streaming val writable: geny.Writable = stream(resp, indent = 2) writable.writeBytesTo(System.out) // prints: { // "status": 200, // "body": "OK" // } // MessagePack streaming val binaryWritable: geny.Writable = streamBinary(resp) val baos = new java.io.ByteArrayOutputStream binaryWritable.writeBytesTo(baos) val bytes = baos.toByteArray // Pass `binaryWritable` directly to any framework accepting geny.Writable ``` ``` -------------------------------- ### Stream JSON/MessagePack Output with geny.Writable Source: https://context7.com/com-lihaoyi/upickle/llms.txt Write JSON or MessagePack bytes directly to an OutputStream on demand. This enables zero-copy streaming with HTTP frameworks that accept geny.Writable. ```scala import upickle.default._ case class Response(status: Int, body: String) object Response { implicit val rw: ReadWriter[Response] = macroRW } val resp = Response(200, "OK") // JSON streaming val writable: geny.Writable = stream(resp, indent = 2) writable.writeBytesTo(System.out) // prints: { // "status": 200, // "body": "OK" // } // MessagePack streaming val binaryWritable: geny.Writable = streamBinary(resp) val baos = new java.io.ByteArrayOutputStream binaryWritable.writeBytesTo(baos) val bytes = baos.toByteArray // Pass `binaryWritable` directly to any framework accepting geny.Writable ``` -------------------------------- ### upickle.default.writeJs / readJs / transform — Cross-format conversion Source: https://context7.com/com-lihaoyi/upickle/llms.txt Convert between Scala values and the `ujson.Value` AST, and between JSON and MessagePack ASTs, without intermediate string serialization. ```APIDOC ## `upickle.default.writeJs` / `readJs` / `transform` — Cross-format conversion Converts between Scala values and the `ujson.Value` AST, and between JSON and MessagePack ASTs, without going through string serialization. ```scala import upickle.default._ case class Config(host: String, port: Int) object Config { implicit val rw: ReadWriter[Config] = macroRW } // Scala value → ujson.Value AST val jsVal: ujson.Value = writeJs(Config("localhost", 8080)) // ujson.Obj(LinkedHashMap("host" -> Str("localhost"), "port" -> Num(8080.0))) jsVal("host").str // "localhost" jsVal("port").num // 8080.0 // ujson.Value AST → Scala value val cfg = read[Config](jsVal) // Config("localhost", 8080) // Scala value → upack.Msg AST val msgVal: upack.Msg = writeMsg(Config("localhost", 8080)) // Cross-format: JSON string → MessagePack bytes (no intermediate Scala object) val jsonStr = "{\"host\":\"example.com\",\"port\":443}" val msgBytes: Array[Byte] = transform(ujson.read(jsonStr)).to[Array[Byte]] // Or more explicitly: val msgFromJson = transform(jsonStr).to[upack.Msg] ``` ``` -------------------------------- ### upickle.default.macroRW Source: https://context7.com/com-lihaoyi/upickle/llms.txt Derives a `ReadWriter[T]` for case classes and sealed traits at compile time via macros. Place the implicit in the companion object for automatic pickup. ```APIDOC ## `upickle.default.macroRW` — Automatic ReadWriter derivation Derives a `ReadWriter[T]` for case classes and sealed traits at compile time via macros. Place the implicit in the companion object for automatic pickup. ```scala import upickle.default._ // Simple case class case class Point(x: Double, y: Double) object Point { implicit val rw: ReadWriter[Point] = macroRW } write(Point(1.0, 2.0)) // => """{"x":1,"y":2}""" read[Point]("""{"x":3,"y":4}""") // Point(3.0, 4.0) // Sealed trait hierarchy — tagged with {"$type":"ClassName"} sealed trait Shape object Shape { implicit val rw: ReadWriter[Shape] = macroRW } case class Circle(radius: Double) extends Shape object Circle { implicit val rw: ReadWriter[Circle] = macroRW } case class Rectangle(w: Double, h: Double) extends Shape object Rectangle { implicit val rw: ReadWriter[Rectangle] = macroRW } write[Shape](Circle(5.0)) // => """{"$type":"Circle","radius":5}""" write[Shape](Rectangle(3.0, 4.0)) // => """{"$type":"Rectangle","w":3,"h":4}""" read[Shape]("""{"$type":"Circle","radius":2.5}""") // Shape: Circle(2.5) // Default values are automatically omitted on write and filled on read case class User(name: String, role: String = "guest", active: Boolean = true) object User { implicit val rw: ReadWriter[User] = macroRW } write(User("alice")) // => """{"name":"alice"}""" read[User]("""{"name":"bob"}""") // User("bob","guest",true) ``` ``` -------------------------------- ### Handle Default Values with upickle.default.macroRW Source: https://context7.com/com-lihaoyi/upickle/llms.txt Case classes with default values are handled automatically. Default values are omitted during writing and filled during reading if not present. ```scala case class User(name: String, role: String = "guest", active: Boolean = true) object User { implicit val rw: ReadWriter[User] = macroRW } write(User("alice")) // => """{"name":"alice"}""" read[User]("""{"name":"bob"}""") // User("bob","guest",true) ``` -------------------------------- ### Standalone JSON Parsing and Rendering with ujson.read/write Source: https://context7.com/com-lihaoyi/upickle/llms.txt Parse JSON text directly into the ujson.Value AST without using upickle's typeclass layer. Useful for dynamic JSON manipulation, traversal, mutation, and building JSON from scratch. ```scala import ujson._ // Parse val v: ujson.Value = ujson.read(""{"name":"Alice","scores":[10,20,30]}"""") // Traverse v("name").str // "Alice" v("scores")(1).num // 20.0 v("scores").arr.map(_.num) // ArrayBuffer(10.0, 20.0, 30.0) // Mutate in place v("name") = "Bob" v("scores")(0) = 99 ujson.write(v) // => """{"name":"Bob","scores":[99,20,30]}""" // Build from scratch val obj = ujson.Obj( "id" -> 42, "tags" -> ujson.Arr("scala", "json"), "meta" -> ujson.Obj("active" -> true, "score" -> 3.14) ) ujson.write(obj, indent = 2) // { // "id": 42, // "tags": ["scala","json"], // "meta": {"active":true,"score":3.14} // } // Reformat (parse + re-render with options, no full AST allocation) ujson.reformat(""{"b":2,"a":1}""", indent = 2, sortKeys = true) // => "{\n \"a\": 1,\n \"b\": 2\n}" // Validate (parse without building AST) ujson.validate("[1,2,3]") // succeeds silently ujson.validate("[1,2,\"") // throws ujson.ParseException ``` -------------------------------- ### Custom upickle Pickler Instances for Configuration Overrides Source: https://context7.com/com-lihaoyi/upickle/llms.txt Create a custom upickle.AttributeTagged object to override global serialization behavior, such as discriminator key name, key mapping, and unknown key policy. Ensure to define the ReadWriter using the custom pickler. ```scala // Custom pickler: snake_case keys, "_tag" discriminator, reject unknown keys object MyPickler extends upickle.AttributeTagged { override def tagName: String = "_tag" override def allowUnknownKeys: Boolean = false override def serializeDefaults: Boolean = true override def objectAttributeKeyReadMap(s: CharSequence): CharSequence = s.toString.split("_").zipWithIndex.map { case (w, 0) => w case (w, _) => w.capitalize }.mkString override def objectAttributeKeyWriteMap(s: CharSequence): CharSequence = s.toString.replaceAll("([A-Z])", "_$1").toLowerCase.stripPrefix("_") } case class UserProfile(userId: Int, firstName: String) object UserProfile { implicit val rw: MyPickler.ReadWriter[UserProfile] = MyPickler.macroRW } MyPickler.write(UserProfile(1, "Alice")) // => """{"user_id":1,"first_name":"Alice"}""" MyPickler.read[UserProfile]("""{"user_id":2,"first_name":"Bob"}"""") // UserProfile(2, "Bob") ``` -------------------------------- ### Custom ReadWriter via bimap / readwriter Source: https://context7.com/com-lihaoyi/upickle/llms.txt Define custom serialization formats for types by mapping them to and from existing serializable types using `.bimap` or `readwriter[Base].bimap[T]`. ```APIDOC ## Custom `ReadWriter` via `bimap` / `readwriter` — Custom serialization format Defines a custom `ReadWriter[T]` by mapping to/from an existing serializable type using `.bimap` or `readwriter[Base].bimap[T]`. ```scala import upickle.default._ // Serialize a custom class as a compact string "i s" class Point(val x: Int, val y: Int) implicit val pointRW: ReadWriter[Point] = readwriter[String].bimap[Point]( p => s"${p.x},${p.y}", str => { val Array(x, y) = str.split(","); new Point(x.toInt, y.toInt) } ) write(new Point(3, 4)) // => "\"3,4\"" val p = read[Point]("\"10,20\"") // p.x == 10, p.y == 20 // Map to ujson.Value directly for full control case class RawWrapper(data: String) implicit val rwRW: ReadWriter[RawWrapper] = readwriter[ujson.Value].bimap[RawWrapper]( w => ujson.Obj("payload" -> w.data, "version" -> 1), v => RawWrapper(v("payload").str) ) write(RawWrapper("hello")) // => "{\"payload\":\"hello\",\"version\":1}" read[RawWrapper]{"{"payload":"world","version":2}"} // RawWrapper("world") ``` ``` -------------------------------- ### Custom Serialization with `bimap` Source: https://context7.com/com-lihaoyi/upickle/llms.txt Define custom serialization logic for a type by mapping it to and from an existing serializable type using `.bimap`. This is useful for custom string formats or mapping to `ujson.Value` for full control. ```scala import upickle.default._ // Serialize a custom class as a compact string "i s" class Point(val x: Int, val y: Int) implicit val pointRW: ReadWriter[Point] = readwriter[String].bimap[Point]( p => s"${p.x},${p.y}", str => { val Array(x, y) = str.split(","); new Point(x.toInt, y.toInt) } ) write(new Point(3, 4)) // => """3,4""" val p = read[Point]("""10,20""") // p.x == 10, p.y == 20 // Map to ujson.Value directly for full control case class RawWrapper(data: String) implicit val rwRW: ReadWriter[RawWrapper] = readwriter[ujson.Value].bimap[RawWrapper]( w => ujson.Obj("payload" -> w.data, "version" -> 1), v => RawWrapper(v("payload").str) ) write(RawWrapper("hello")) // => $""{"payload":"hello","version":1}$"" read[RawWrapper]($""{"payload":"world","version":2}$"") // RawWrapper("world") ``` -------------------------------- ### Derive ReadWriter for Case Classes with upickle.default.macroRW Source: https://context7.com/com-lihaoyi/upickle/llms.txt Use `macroRW` in the companion object to automatically derive `ReadWriter` for case classes. This handles basic serialization and deserialization. ```scala import upickle.default._ // Simple case class case class Point(x: Double, y: Double) object Point { implicit val rw: ReadWriter[Point] = macroRW } write(Point(1.0, 2.0)) // => """{"x":1,"y":2}""" read[Point]("""{"x":3,"y":4}""") // Point(3.0, 4.0) ``` -------------------------------- ### Legacy Array-Based Tagged Union Format Source: https://context7.com/com-lihaoyi/upickle/llms.txt Uses an alternate API that serializes sealed trait instances as two-element arrays `["TypeName", {...}]` instead of the default dictionary-with-`$type` format, for compatibility with older uPickle output. Import `upickle.legacy._` instead of `upickle.default._`. ```scala import upickle.legacy._ // instead of upickle.default._ sealed trait Expr case class Num(value: Double) extends Expr case class Add(a: Expr, b: Expr) extends Expr object Num { implicit val rw: ReadWriter[Num] = macroRW } object Add { implicit val rw: ReadWriter[Add] = macroRW } object Expr { implicit val rw: ReadWriter[Expr] = ReadWriter.merge( macroRW[Num], macroRW[Add] ) } // Legacy format uses ["TypeTag", {fields}] write[Expr](Add(Num(1.0), Num(2.0))) ``` ```scala // Default format uses {"$type":"TypeTag", fields...} upickle.default.write[Expr](Add(Num(1.0), Num(2.0))) ``` -------------------------------- ### Manual Sealed Trait `ReadWriter` Construction with `ReadWriter.merge` Source: https://context7.com/com-lihaoyi/upickle/llms.txt Construct a `ReadWriter` for a sealed trait by merging the `ReadWriter`s of its subtypes using `ReadWriter.merge`. This is useful when subtypes are defined in separate files or the trait cannot be sealed. ```scala import upickle.default._ sealed trait Command case class Move(dx: Int, dy: Int) extends Command case class Fire(weapon: String) extends Command case object Stop extends Command object Move { implicit val rw: ReadWriter[Move] = macroRW } object Fire { implicit val rw: ReadWriter[Fire] = macroRW } object Stop { implicit val rw: ReadWriter[Stop.type] = macroRW } object Command { implicit val rw: ReadWriter[Command] = ReadWriter.merge( macroRW[Move], macroRW[Fire], macroRW[Stop.type] ) } write[Command](Move(1, 2)) // => $""{"$$type":"Move","dx":1,"dy":2}$""" write[Command](Fire("laser")) // => $""{"$$type":"Fire","weapon":"laser"}$""" write[Command](Stop) // => """Stop""" read[Command]($""{"$$type":"Move","dx":3,"dy":4}$"") // Move(3, 4) ``` -------------------------------- ### upickle.default.write Source: https://context7.com/com-lihaoyi/upickle/llms.txt Serializes a Scala value with an implicit Writer[T] into a JSON string. Supports options for pretty-printing, unicode escaping, and key sorting. ```APIDOC ## upickle.default.write — Serialize a Scala value to JSON Converts any value with an implicit `Writer[T]` to a JSON string. Supports pretty-printing, unicode escaping, and key sorting. ### Method `write[T](value: T, indent: Int = -1, sortKeys: Boolean = false, escapeUnicode: Boolean = false)(implicit writer: Writer[T]): String` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```scala import upickle.default._ case class Config(host: String, port: Int, debug: Boolean = false) object Config { implicit val rw: ReadWriter[Config] = macroRW } // Compact output (default: indent = -1) write(Config("localhost", 8080)) // => """{"host":"localhost","port":8080}""" // Note: fields equal to their default value are omitted automatically // Pretty-printed write(Config("localhost", 8080, debug = true), indent = 2) // => """{ // "host": "localhost", // "port": 8080, // "debug": true // }""" // Sorted keys write(Config("localhost", 8080), sortKeys = true) // => """{"host":"localhost","port":8080}""" // Escape unicode write("叉烧包", escapeUnicode = true) // => "\\"\\u53c9\\u70e7\\u5305\\"" // Write to stream (avoids building intermediate string) val out = new java.io.ByteArrayOutputStream writeToOutputStream(Config("host", 80), out) ``` ### Response #### Success Response (String) Returns the JSON string representation of the Scala value. ``` -------------------------------- ### Deserialize JSON to Scala Value with upickle.default.read Source: https://context7.com/com-lihaoyi/upickle/llms.txt Reads JSON from various sources (String, byte array, File) into a Scala type T. Requires an implicit Reader[T], automatically derived for case classes and sealed traits via macroRW. Handles collections, primitives, and Options. Throws AbortException on malformed input. ```scala import upickle.default._ case class Person(name: String, age: Int) object Person { implicit val rw: ReadWriter[Person] = macroRW } // From string val p = read[Person]("""{"name":"Alice","age":30}""") // p: Person = Person("Alice", 30) // From byte array val bytes = """{"name":"Bob","age":25}""".getBytes("UTF-8") val p2 = read[Person](bytes) // p2: Person = Person("Bob", 25) // From file val p3 = read[Person](new java.io.File("person.json")) // Collections, primitives, Option val nums = read[List[Int]]("[1,2,3]") // List(1, 2, 3) val opt = read[Option[String]]("\"hello\"") // Some("hello") val nopt = read[Option[String]]("null") // None // Error handling — throws upickle.core.AbortException on malformed input try read[Person]("""{"name":"bad"}""") catch { case e: upickle.core.AbortException => println(e.getMessage) } ``` -------------------------------- ### ReadWriter.merge — Manual sealed trait ReadWriter construction Source: https://context7.com/com-lihaoyi/upickle/llms.txt Explicitly construct a `ReadWriter` for a sealed trait by merging `ReadWriter`s of its subtypes. Useful for traits that cannot be sealed or have subtypes in separate files. ```APIDOC ## `ReadWriter.merge` — Manual sealed trait ReadWriter construction Explicitly constructs a `ReadWriter` for a sealed trait by merging `ReadWriter`s of its subtypes. Useful when the trait cannot be sealed or when subtypes are defined in separate files. ```scala import upickle.default._ sealed trait Command case class Move(dx: Int, dy: Int) extends Command case class Fire(weapon: String) extends Command case object Stop extends Command object Move { implicit val rw: ReadWriter[Move] = macroRW } object Fire { implicit val rw: ReadWriter[Fire] = macroRW } object Stop { implicit val rw: ReadWriter[Stop.type] = macroRW } object Command { implicit val rw: ReadWriter[Command] = ReadWriter.merge( macroRW[Move], macroRW[Fire], macroRW[Stop.type] ) } write[Command](Move(1, 2)) // => "{\"$\":\"Move\",\"dx\":1,\"dy\":2}" write[Command](Fire("laser")) // => "{\"$\":\"Fire\",\"weapon\":\"laser\"}" write[Command](Stop) // => "\"Stop\"" read[Command]{"{"$\":\"Move\",\"dx\":3,\"dy\":4}"} // Move(3, 4) ``` ``` -------------------------------- ### Serialize Scala Value to JSON with upickle.default.write Source: https://context7.com/com-lihaoyi/upickle/llms.txt Converts a Scala value with an implicit Writer[T] to a JSON string. Supports pretty-printing, unicode escaping, and key sorting. Fields equal to their default value are omitted automatically. Can write directly to an OutputStream to avoid intermediate string building. ```scala import upickle.default._ case class Config(host: String, port: Int, debug: Boolean = false) object Config { implicit val rw: ReadWriter[Config] = macroRW } // Compact output (default: indent = -1) write(Config("localhost", 8080)) // => """{"host":"localhost","port":8080}""" // Note: fields equal to their default value are omitted automatically // Pretty-printed write(Config("localhost", 8080, debug = true), indent = 2) // => """{ // "host": "localhost", // "port": 8080, // "debug": true // }""" // Sorted keys write(Config("localhost", 8080), sortKeys = true) // => """{"host":"localhost","port":8080}""" // Escape unicode write("叉烧包", escapeUnicode = true) // => "\"\\u53c9\\u70e7\\u5305\"" // Write to stream (avoids building intermediate string) val out = new java.io.ByteArrayOutputStream writeToOutputStream(Config("host", 80), out) ``` -------------------------------- ### Derive ReadWriter for Sealed Traits with upickle.default.macroRW Source: https://context7.com/com-lihaoyi/upickle/llms.txt Derive `ReadWriter` for sealed traits to serialize/deserialize different subtypes. Subtypes are automatically tagged with their class name for discrimination. ```scala sealed trait Shape object Shape { implicit val rw: ReadWriter[Shape] = macroRW } case class Circle(radius: Double) object Circle { implicit val rw: ReadWriter[Circle] = macroRW } case class Rectangle(w: Double, h: Double) object Rectangle { implicit val rw: ReadWriter[Rectangle] = macroRW } write[Shape](Circle(5.0)) // => """{"$$type":"Circle","radius":5}""" write[Shape](Rectangle(3.0, 4.0)) // => """{"$$type":"Rectangle","w":3,"h":4}""" read[Shape]("""{"$$type":"Circle","radius":2.5}""") // Shape: Circle(2.5) ``` -------------------------------- ### Use Non-String Types as JSON Object Keys Source: https://context7.com/com-lihaoyi/upickle/llms.txt Marks a `ReadWriter[T]` so that `Map[T, V]` serializes as a JSON object `{"keyStr": value}` rather than an array of pairs `[["keyStr", value]]`. Use `stringKeyRW` for this purpose. ```scala import upickle.default._ // Without stringKeyRW: Map[Int, String] → [["1","a"],["2","b"]] write(Map(1 -> "a", 2 -> "b")) ``` ```scala // With stringKeyRW: Map[Int, String] → {"1":"a","2":"b"} implicit val intKeyRW: ReadWriter[Int] = stringKeyRW(ReadWriter.join(IntReader, IntWriter)) write(Map(1 -> "a", 2 -> "b")) ``` ```scala // Works with custom types too case class MyKey(value: String) implicit val myKeyRW: ReadWriter[MyKey] = stringKeyRW(readwriter[String].bimap[MyKey](_.value, MyKey.apply)) write(Map(MyKey("foo") -> 1, MyKey("bar") -> 2)) ``` -------------------------------- ### upickle.default.read Source: https://context7.com/com-lihaoyi/upickle/llms.txt Deserializes a JSON string or other readable input into a Scala value of type T. Requires an implicit Reader[T] in scope, which is automatically derived for case classes and sealed traits using macroRW. ```APIDOC ## upickle.default.read — Deserialize JSON to a Scala value Reads a JSON string (or any `ujson.Readable` input: `String`, `Array[Byte]`, `ByteBuffer`, `java.io.File`, `java.nio.file.Path`, `InputStream`) into a Scala type `T`. Requires an implicit `Reader[T]` in scope, derived automatically for case classes and sealed traits via `macroRW`. ### Method `read[T](input: ujson.Readable)(implicit reader: Reader[T]): T` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```scala import upickle.default._ case class Person(name: String, age: Int) object Person { implicit val rw: ReadWriter[Person] = macroRW } // From string val p = read[Person]("""{"name":"Alice","age":30}""") // p: Person = Person("Alice", 30) // From byte array val bytes = """{"name":"Bob","age":25}""".getBytes("UTF-8") val p2 = read[Person](bytes) // p2: Person = Person("Bob", 25) // From file val p3 = read[Person](new java.io.File("person.json")) // Collections, primitives, Option val nums = read[List[Int]]("[1,2,3]") // List(1, 2, 3) val opt = read[Option[String]]("\"hello\"") // Some("hello") val nopt = read[Option[String]]("null") // None // Error handling — throws upickle.core.AbortException on malformed input try read[Person]("""{"name":"bad"}""") catch { case e: upickle.core.AbortException => println(e.getMessage) } ``` ### Response #### Success Response (T) Returns the deserialized Scala value of type `T`. #### Response Example (See Request Example for output of `read` calls) ``` -------------------------------- ### Generate JSON Schema from ReadWriter (Scala 3) Source: https://context7.com/com-lihaoyi/upickle/llms.txt Derives a JSON Schema (draft 2020-12) from the same `ReadWriter` types used for serialization. Ensure `upickle.jsonschema` is imported. ```scala import upickle.default._ import upickle.jsonschema.JsonSchema case class Address(street: String, zip: String) object Address { implicit val rw: ReadWriter[Address] = macroRW } case class Person( name: String, age: Int, address: Option[Address] = None, tags: List[String] = Nil ) object Person { implicit val rw: ReadWriter[Person] = macroRW } // Generate schema val schema: ujson.Value = upickle.default.schema[Person] ujson.write(schema, indent = 2) ``` ```scala sealed trait Shape case class Circle(radius: Double) extends Shape case class Rect(w: Double, h: Double) extends Shape object Shape { implicit val rw: ReadWriter[Shape] = macroRW } object Circle { implicit val rw: ReadWriter[Circle] = macroRW } object Rect { implicit val rw: ReadWriter[Rect] = macroRW } val shapeSchema = upickle.default.schema[Shape] ``` -------------------------------- ### @upickle.implicits.key Source: https://context7.com/com-lihaoyi/upickle/llms.txt Overrides the JSON key name for a case class field, the `$type` tag value for a case class in a sealed hierarchy, or the discriminator key name for a sealed trait. ```APIDOC ## `@upickle.implicits.key` — Rename fields and discriminator tags Overrides the JSON key name for a case class field, the `$type` tag value for a case class in a sealed hierarchy, or the discriminator key name for a sealed trait. ```scala import upickle.default._ import upickle.implicits.key // Rename individual fields case class ApiUser( @key("user_id") id: Int, @key("full_name") name: String ) object ApiUser { implicit val rw: ReadWriter[ApiUser] = macroRW } write(ApiUser(1, "Alice")) // => """{"user_id":1,"full_name":"Alice"}""" read[ApiUser]("""{"user_id":2,"full_name":"Bob"}""") // ApiUser(2,"Bob") // Override $type tag value on a case class sealed trait Animal @key("cat") case class Cat(lives: Int) extends Animal @key("dog") case class Dog(breed: String) extends Animal object Animal { implicit val rw: ReadWriter[Animal] = macroRW } object Cat { implicit val rw: ReadWriter[Cat] = macroRW } object Dog { implicit val rw: ReadWriter[Dog] = macroRW } write[Animal](Cat(9)) // => """{"$type":"cat","lives":9}""" write[Animal](Dog("Lab")) // => """{"$type":"dog","breed":"Lab"}""" // Override the discriminator key name on the sealed trait itself @key("kind") sealed trait Vehicle case class Car(make: String) extends Vehicle object Vehicle { implicit val rw: ReadWriter[Vehicle] = macroRW } object Car { implicit val rw: ReadWriter[Car] = macroRW } write[Vehicle](Car("Toyota")) // => """{"kind":"Car","make":"Toyota"}""" ``` ``` -------------------------------- ### Override Discriminator Tags with @upickle.implicits.key Source: https://context7.com/com-lihaoyi/upickle/llms.txt Use the `@key` annotation on case classes within a sealed hierarchy to override the default `$type` discriminator tag value. This allows for custom string representations of subtypes. ```scala sealed trait Animal @key("cat") case class Cat(lives: Int) extends Animal @key("dog") case class Dog(breed: String) extends Animal object Animal { implicit val rw: ReadWriter[Animal] = macroRW } object Cat { implicit val rw: ReadWriter[Cat] = macroRW } object Dog { implicit val rw: ReadWriter[Dog] = macroRW } write[Animal](Cat(9)) // => """{"$$type":"cat","lives":9}""" write[Animal](Dog("Lab")) // => """{"$$type":"dog","breed":"Lab"}""" ``` -------------------------------- ### Rename JSON Fields with @upickle.implicits.key Source: https://context7.com/com-lihaoyi/upickle/llms.txt Use the `@key` annotation to specify custom JSON field names for case class members. This is useful for integrating with APIs that use different naming conventions. ```scala import upickle.default._ import upickle.implicits.key case class ApiUser( @key("user_id") id: Int, @key("full_name") name: String ) object ApiUser { implicit val rw: ReadWriter[ApiUser] = macroRW } write(ApiUser(1, "Alice")) // => """{"user_id":1,"full_name":"Alice"}""" read[ApiUser]("""{"user_id":2,"full_name":"Bob"}""") // ApiUser(2,"Bob") ``` -------------------------------- ### Override Discriminator Key Name with @upickle.implicits.key Source: https://context7.com/com-lihaoyi/upickle/llms.txt Apply the `@key` annotation to a sealed trait itself to change the name of the discriminator key from the default `$type` to a custom name. ```scala @key("kind") sealed trait Vehicle case class Car(make: String) extends Vehicle object Vehicle { implicit val rw: ReadWriter[Vehicle] = macroRW } object Car { implicit val rw: ReadWriter[Car] = macroRW } write[Vehicle](Car("Toyota")) // => """{"kind":"Car","make":"Toyota"}""" ```