ザネリは列車を見送った

ブログという名の備忘録

MessagePack for Java を Scala から実行する

MessagePackJava版をScalaから使ってみた。

なんでこんなことをしたかというと

MessagePack for Scalaは現状 Scala 2.10には対応していないらしく
(java.lang.NoClassDefFoundError: scala/reflect/ClassManifestエラーが発生する)、
2.10 対応版フォークを使用する、
自分で公式リポジトリから clone してワークアラウンドコードを入れてみる、
など対応方法はあると思うけど、
MessagePack for Javaを使ってみるとどんな感じになるかを試してみた。
今回は JSON ⇔ MessagePack の変換。

MessagePack to JSON

org.msgpack.type.Value.toString() が JSON フォーマットの文字列を返してくれるので
それを呼んで scala.util.parsing.json.JSON.parseFull() とかしてやればおしまい。
ただそれでは面白くないので愚直に書くとどうなるかやってみた。
こういうのを作って、

val value: org.msgpack.`type`.Value = ... // new MessagePack().read() とかで取得
val map = Value2JsonMap.createMap(value)

こんな感じで Map[String, Any] を作れるので、後は如何様にも。
Java だと if (value.isRawValue) value.asRawValue.getString とかやるところが
パターンマッチでまかなえて良い感じかも。

JSON to MessagePack

さっきの逆パターンの object を作る。

val map: Map[String, _] = ...
val value = JsonMap2Value.createValue(map)

こんな感じで org.msgpack.type.Value を作れるので、後は write するだけ。
(型のパターンは網羅が足りてないけど…)

JSON to MessagePack(別バージョン)

上記はMapに入っているもの全部を Value にするけど、
キーを指定して特定の値のみ選択したい場合。

こういうトレイトを作っておいて、これをミックスインして使う。
たとえばこんなJSONを処理したい場合、

{
    "id" : 1,
    "name" : "zaneli",
    "friend" : [{"id" : 2}, {"id" : 3}, {"id" : 4}],
    "address" : {
      "zipcode" : "xxx-yyyy",
      "city" : "ihatov"
    }
}

こうする。

case class UserFactory(map: Map[String, _]) extends KeyValueFactory {
  def createValue: Value = {
    mapValue(map,
      intKeyValue("id"),
      rawKeyValue("name"),
      (arrayKeyValue("friend") { value: Map[String, Any] => mapValue(value, intKeyValue("id")) }),
      mapKeyValue("address")(
        rawKeyValue("zipcode"),
        rawKeyValue("city")))
  }
}

…おや、元々のJSONとcreateValueメソッドの見た目が似ていて、けっこう個人的には見栄え良く感じた。
こうなるとarrayKeyValueのところももっと簡潔にならないかなぁ…。