Typeclasses for serialization
Currently supports:
We build one artifact with an Optional
dependency on each of the above serialization libraries.
This will not bloat your project. It only has an effect if you explicitly depend on the serialization library yourself.
Get latest release:
libraryDependencies += "com.github.cornerman" %%% "chameleon" % "0.4.1"
We additionally publish sonatype snapshots for every commit on master.
Using for example boopickle:
import chameleon._
// boopickle-specific imports
import chameleon.ext.boopickle._
import java.nio.ByteBuffer
import boopickle.Default._
val serializer = Serializer[String, ByteBuffer]
val deserializer = Deserializer[String, ByteBuffer]
val input = "chameleon"
val serialized = serializer.serialize(input)
val deserialized = deserializer.deserialize(serialized)
Have typeclasses for cats (Contravariant
, Functor
, Invariant
):
import chameleon.ext.cats._
We have an extra package to integrate http4s
with chameleon Serializer
and Deserializer
. Specifically to create EntityEncoder
and EntityDecoder
.
Usage:
libraryDependencies += "com.github.cornerman" %%% "chameleon-http4s" % "0.4.1"
To work with json inside your API:
import chameleon.ext.http4s.JsonStringCodec.*
import chameleon.ext.upickle.*
// serialize case class as json response
Ok(json(MyCaseClass("hallo")))
// deserialize json request into case class
jsonAs[MyCaseClass](someRequest)
You can also use the auto import, which provides implicit EntityEncoder
/ EntityDecoder
for all types with Serializer
/ Deserializer
. This should only be imported when exclusively working with json.
import chameleon.ext.http4s.JsonStringCodec.auto.*
import chameleon.ext.upickle.*
// serialize
Ok(MyCaseClass("hallo"))
// deserialize
someRequest.as[MyCaseClass]
There are similar helpers for other types than String
, for example Array[Byte]
. Also there are other serialization targets than json
like text
, binary
, and messagePack
- this depends on the semantics of the used serialization method. See here.
Say, you want to write a library that needs serialization but abstracts over the type of serialization. Then you might end up with something like this:
trait Library[PickleType] {
def readAndDo() = {
val pickled: PickleType = ???
???
}
def writeAndDo() = {
val thing: Thing = ???
???
}
}
But how can you deserialize the pickled
value and how do you serialize a thing
? You then need to let the user provide an implementation for their serialization of PickleType
.
With chameleon, you can use existing typeclasses Serializer
and Deserializer
which are generic on the pickled type:
import chameleon._
trait Library[PickleType] {
def readAndDo(implicit d: Deserializer[Thing, PickleType]) = {
val pickled: PickleType = ???
d.deserialize(pickled) match {
case Right(thing: Thing) => ???
case Left(err: Throwable) => ???
}
}
def writeAndDo(implicit s: Serializer[Thing, PickleType]) = {
val thing: Thing = ???
val pickled: PickleType = s.serialize(thing)
???
}
}
Users of this library can now decide what kind of serialization they want to use and rely on existing implementation for some serializers. If you want to use this library with, e.g., JSON using circe, you can do:
import io.circe._, io.circe.syntax._, io.circe.generic.auto._
import chameleon.ext.circe._
val lib: Library[String] = ???
lib.readAndDo()
lib.writeAndDo()
If your favorite serialization library is not supported yet, you can easily add it (see existing implementations). You need to define implicit Serializer
and Deserializer
instances for that library. Then, please add a PR for it.