uPickle serializer is a lightweight Json library for scala. uPickle is built on top of uJson which are used for easy manipulation of json without the need of converting it to a scala case class. We can even use uJson as standalone too. In this blog, I will focus only on uPickle library.
Note: uPickle does not support Scala 2.10; only 2.11 and 2.12 are supported
uPickle (pronounced micro-pickle) is a lightweight JSON serialization library which is fast than many other json serializers. I will talk more about the comparison of different serializers in my next blog. This blog will cover all the basic stuff about uPickle.
Features
- Simple to use, with nice human-readable JSON output
- Very high Performance; faster than Play-Json, Circe, or Argonaut by a large margin
- Simple & easy to understand JSON Processing API, that should be instantly familiar to anyone whose processed JSON in Python, Ruby, or Javascript
- Flexible and easily customizable
- Zero dependencies; can be included in any project without worrying about conflicts
- ScalaJS support, allowing transfer of structured data between the JVM and Javascript.
If you use uJson you will get basic operations to manipulate JSON:
package object ujson{ | |
def transform[T](t: Transformable, v: Visitor[_, T]) = t.transform(v) | |
def read(s: Transformable): Js.Value = transform(s, Js) | |
def copy(t: Js.Value): Js.Value = transform(t, Js) | |
def write(t: Js.Value, indent: Int = -1): String = { | |
transform(t, StringRenderer(indent)).toString | |
} | |
def writeTo(t: Js.Value, out: java.io.Writer, indent: Int = -1): Unit = { | |
transform(t, Renderer(out, indent)) | |
} | |
def validate(s: Transformable): Unit = transform(s, NoOpVisitor) | |
def reformat(s: Transformable, indent: Int = -1): String = { | |
transform(s, StringRenderer(indent)).toString | |
} | |
def reformatTo(s: Transformable, out: java.io.Writer, indent: Int = -1): Unit = { | |
transform(s, Renderer(out, indent)).toString | |
} | |
// End ujson | |
} |
The uPickle library that uses uJson builds on top of these, exposing similar operations that work on any type T
with a provided Reader
or Writer
:
trait Api { | |
def read[T: Reader](s: Transformable): T = s.transform(reader[T]) | |
def readJs[T: Reader](s: Js.Value): T = s.transform(reader[T]) | |
def reader[T: Reader] = implicitly[Reader[T]] | |
def write[T: Writer](t: T, indent: Int = -1): String = { | |
transform(t).to(StringRenderer(indent)).toString | |
} | |
def writeJs[T: Writer](t: T): Js.Value = transform(t).to[Js.Value] | |
def writeTo[T: Writer](t: T, out: java.io.Writer, indent: Int = -1): Unit = { | |
transform(t).to(new Renderer(out, indent = indent)) | |
} | |
def writer[T: Writer] = implicitly[Writer[T]] | |
def writable[T: Writer](t: T): Transformable = Transformable.fromTransformer(t, writer[T]) | |
def readwriter[T: ReadWriter] = implicitly[ReadWriter[T]] | |
case class transform[T: Writer](t: T) extends Transformable{ | |
def transform[V](f: ujson.Visitor[_, V]): V = writer[T].transform(t, f) | |
def to[V](f: ujson.Visitor[_, V]): V = transform(f) | |
def to[V](implicit f: Reader[V]): V = transform(f) | |
} | |
// End Api | |
} |
Now let’s see how it works.
First, we need to add the dependency in build.sbt
libraryDependencies += “com.lihaoyi” %% “upickle” % “0.6.5”
Then add this import in your code:
import upickle.default._
Scala primitive data types:
write(true: Boolean) returns true (JSON Boolean) write("Hello Upickle": String) returns "Hello Upickle" (Json String) write('A': Char) returns "A" (JSON String) write(10: Int) returns 10 (JSON Number) write(10: Float) returns 10 (JSON Number) write(10.0: Double) returns 10 (JSON Number) write(1000000L: Long) returns "10" (Json String)
Scala Collections:
write(List("Hello", "World")) returns ["Hello","World"] (JSON List) write(Array("Hello", "uPickle")) returns ["Hello","uPickle"] (JSON List)
Scala Options:
write(Some("uPickle")) returns ["uPickle"] (JSON List) write(None) returns [] (JSON List)
Scala case classes
case class MyuPickle(libraryName: String, _type: String) object MyuPickle { implicit def rw: RW[MyuPickle] = macroRW } //now to serialize it write(MyuPickle("uPickle", "JSON Serializer")) returns {"libraryName":"uPickle","_type":"JSON Serializer"} //to deserialize it read[MyuPickle]("{\"libraryName\":\"uPickle\",\"_type\":\"JSON Serializer\"}") returns MyuPickle(uPickle,JSON Serializer)
Custom read/write
import upickle.default._ case class CustomPickle(libraryName: String, _type: String) object CustomPickle { implicit val rw = upickle.default.readwriter[String].bimap[CustomPickle]( customPickle => customPickle.libraryName + " " + customPickle._type, str => { val Array(name, _type) = str.split(" ", 2) new CustomPickle(name, _type) } ) } write(CustomPickle("uPickle", "json serializer")) returns "uPickle json serializer" read[CustomPickle]("\"uPickle json serializer\"") returns CustomPickle(uPickle,json serializer)
Supported Types
uPickle provides read/write for the following types:
Boolean
,Byte
,Char
,Short
,Int
,Long
,Float
,Double
Tuple
s from 1 to 22- Immutable
Seq
,List
,Vector
,Set
,SortedSet
,Option
,Array
,Map
s, and all other collections with a reasonableCanBuildFrom
implementation Duration
,Either
- Stand-alone
case class
es andcase object
s, and their generic equivalents, - Non-generic
case class
es andcase object
s that are part of asealed trait
orsealed class
hierarchy sealed trait
andsealed class
es themselves, assuming that all subclasses are picklableUUID
snull
In my next blog, I will compare different serializers and show you how uPickle stands out from all. But let me share the stats that I have got:
Till then,
Happy reading…
Reference:
2 thoughts on “uPickle: a flexible Json Serializer3 min read”
Comments are closed.