cornerman / chameleon   0.3.7

MIT License GitHub

Typeclasses for serialization in scala

Scala versions: 3.x 2.13 2.12 2.11
Scala.js versions: 1.x 0.6

Chameleon

chameleon

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.3.5"

Or get development snapshots via jitpack:

resolvers += "jitpack" at "https://jitpack.io"
libraryDependencies += "com.github.cornerman.chameleon" %%% "chameleon" % "master-SNAPSHOT"

Usage

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._

Motivation

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()

Support additional Serializers

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.