Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Last active November 16, 2018 08:57
Show Gist options
  • Save xuwei-k/5e902a3875153cffa25f48ba7def4188 to your computer and use it in GitHub Desktop.
Save xuwei-k/5e902a3875153cffa25f48ba7def4188 to your computer and use it in GitHub Desktop.
msgpack4zとmsgpack4z-circeのサンプル
scalaVersion := "2.12.6"
libraryDependencies ++= Seq(
"com.github.xuwei-k" %% "msgpack4z-circe" % "0.6.0",
"com.github.xuwei-k" %% "msgpack4z-native" % "0.3.5", // もしくは https://github.com/msgpack4z/msgpack4z-java 使うことも可能
"io.circe" %% "circe-parser" % "0.9.3"
)
package example
import msgpack4z._
import msgpack4z.CodecInstances.all._
import scalaz.{\/-, -\/}
// テスト用case class
case class TestClass(foo: Int, bar: String)
object TestClass {
// json以外のサンプルはこっちでも同じようなことをしているので参照
// https://github.com/msgpack4z/msgpack4z-core/blob/v0.3.9/src/test/scala/msgpack4z/CaseClassExample.scala
// シリアライズ部分と型クラス部分がライブラリ分かれてるので、このオブジェクトどこかで一度だけ作る処理が必要
val factory = new PackerUnpackerFactory {
def packer = MsgOutBuffer.create()
def unpacker(bytes: Array[Byte]) = MsgInBuffer(bytes)
}
// msgpack の map としてシリアライズする場合
// これも immutable で再利用可能なので、case classごとではなく、どこかで一回作れば良い
val mapCodecStringKey = CaseMapCodec.string(factory)
// arrayにシリアライズする場合はこっち使う
// mapかarrayか?は、読みやすさや、互換保ちやすさ、データ量などのトレードオフ
// https://github.com/msgpack4z/msgpack4z-core/blob/v0.3.9/src/main/scala/msgpack4z/CaseCodec.scala
// mapにシリアライズするがcase class の field のシリアライズ時の key を Int にしてデータ量を少しでも節約したい場合はこっち
val mapCodecIntKey = CaseMapCodec.int(factory)
// シリアライズ、デシリアライズのための型クラスのインスタンス生成
//
// マクロなどで自動でcase classのfield名取得する機能はないので、
// mapにシリアライズする場合のkeyはここで明示的に指定しないといけない
implicit val instance: MsgpackCodec[TestClass] =
mapCodecStringKey.codec(TestClass.apply _, TestClass.unapply _)("foo", "bar")
}
object Example {
def main(args: Array[String]): Unit = {
val value1 = TestClass(42, "abcdef")
// バイナリ生成(case classからmsgpackへのシリアライズ)
val bytes = MsgpackCodec[TestClass].toBytes(value1, MsgOutBuffer.create())
// デシリアライズは失敗しうるので scalaz の \/ で返ってくる
val result = MsgpackCodec[TestClass].unpackAndClose(MsgInBuffer(bytes))
result match {
case \/-(value2) =>
// デシリアライズ成功
println(value2)
assert(value1 == value2)
case -\/(error) =>
// デシリアライズ失敗
throw error
}
// ここまでmsgpack4z自体で主にcase classをシリアライズ、デシリアライズする場合の使い方で、
// ここからmsgpack4z-circe関連
// msgpack4z-circe以外のjson相互変換関連の、msgpack4z-argonaut や msgpack4z-play も、ほぼ同じ使い方
// json <=> msgpack 変換のためのオブジェクト生成。
// jsonとmsgpackには細かいところでインピーダンスミスマッチ?的なものがあるので、
// オプションで、(NaNやInfinityや、"String以外のKey" などを)どう変換するか?を指定可能
val jsonCodec = CirceMsgpack.jsonCodec(CirceUnpackOptions.default)
// msgpackのbyte列から、circeのJsonのオブジェクトに変換
println(jsonCodec.unpackAndClose(MsgInBuffer(bytes)))
// circeのjsonを生成(以下の1行はcirce自体の使い方でmsgpack関係ない)
val Right(json) = io.circe.parser.parse(""" { "foo" : 42 , "bar" : "abcdef" } """)
// circeのjsonから、msgpackのbyte列に変換
assert(java.util.Arrays.equals(jsonCodec.toBytes(json, MsgOutBuffer.create()), bytes))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment