mplexでソースコードレベルメタプログラミング

Webアプリケーションを作るとき、HTMLを生成するテンプレートエンジンをよく使いますが、これはパラメータに応じて様々なコードを生成する自動生成ツールであると言えます。
mplexは、プログラムを生成するためのテンプレートエンジンです。


実は MessagePack-RPC for C++ の実装に使っています。似たような関数をたくさんオーバーロードするために活用しています。(そろそろ可変長templateを使いたいですねぇ)

昔はeRubyを使っていたのですが、HTML用のテンプレートエンジンはソースコードがあまりに読みにくくなるので自作しました。


mplexを使うと、普通のプログラムの中にRubyのコードを埋め込むことができます:

// クラスを4つ生成
%4.times do |i|
class Test[%i%] {
public:
    %if i % 2 == 0
    int even;    // iが偶数ならメンバ変数を宣言
    %end

    %i.times do |n|
    int member[%n%];    // 複数のメンバ変数を生成
    %end
};
%end

このコードから↓このようなコードが生成されます:


さらに、if文やイテレータには後置構文を使えます:

%4.times do |i|
class Test[%i%] {
public:
    // 後置構文でシンプルに書く
    int even;  %> if num % 2 == 0
    int member[%n%];  %|n| i.times
};
%end


マクロ(メソッド)を定義することもできます。

%# マクロ定義
%def genABC(ns)
namespace [%ns%] {
  % %w[A B C].each do |a|
  % yield a
  % end
}
%end

%# マクロ呼び出し
%genABC("my_package") do |a|
void func[%a%]();
%end


ソースコードにパラメータを埋め込むこともできます。
ソースコードと「context script」を渡すと、ソースコード内に記述した変数に値が埋め込まれます:

# 連想配列を返すcontext script
{
    "Get" => {
        "std::string"  => "key",
        "uint32_t"     => "flags",
    },

    "Put" => {
        "std::string" => "key",
        "std::string" => "value",
    },
}
// selfにcontext scriptが渡される
%self.each_pair do |name, args|
void [%name%]( [%args.map {|type,name| "#{type} #{name}" }.join(", ")%] );
%end

mplex は ./configure && make install もしくは rubygems でインストールできます:

$ gem install mplex
$ git clone https://github.com/frsyuki/mplex.git
$ cd mplex
$ ./bootstrap
$ ./configure && make && sudo make install


MessagePack-RPCのIDLでも、コード生成の部分で使おうとしているところです。


Enjoy Hacking!

MessagePack for PHP@Webホスティング

先日 phpのserializeを使うより高速でサイズもコンパクトに仕上げる「MessagePack」とPHP拡張 でも紹介されている MessagePack for PHP ですが、Webホスティングサービスにも標準で組み込まれ始めているようです:


MessagePackはオープンソースで開発が進んでいるプロジェクトです。そして各言語版はそれぞれの言語のエキスパートによって実装されるという形態になっています(自然にそうなったのですが^^;)。
PHP版はadvectさんによる実装です。


実はPHP版には以前に別の実装があり、advectさんから新しい実装が送られてきたときは 2,3回くらい提案された実装を全部リジェクトした という経緯があるのですが(笑)、最終的に取り込まれている現在の実装は、非常に高品質になっています。
性能的にはまだ酔狂にチューニングできる余地がありそうですが、テストケースが充実しており、機能的には安心して使える品質かと思います。


コードを読むと、どうやらセッションのシリアライザを置き換える機能も実装されているようです。
php.ini に session.serialize_handler = msgpack と書くと、セッションにオブジェクトを保存する際にMessagePackでシリアライズされるようになるようです。


ここで、MessagePackではクラスをシリアライズする場合は「配列」としてシリアライズするという規約があります。つまりメンバ変数の変数名は保存されないというわけです。

しかしPHP版の実装では、デフォルトで「連想配列」としてシリアライズされるようになっています。つまり変数名まで保存されます。これはPHPだけで使う場合には非常に便利なのですが、JavaRubyなど他の言語とインスタンスをやりとりしたい場合に問題になることがあります。
そういう場合には、php.ini に msgpack.php_only = 0 と書くと良いようです。

また、msgpack.error_display = 0 という設定項目もあります。


Enjoy MessagePack!

Kyoto Tycoon に MessagePack-RPC をプラグインして Java から使う

Tokyo Cabinet を始めとする Tokyo シリーズの作者として知られる平林幹雄さんですが、Tokyo シリーズに続く新製品として、Kyoto シリーズがリリースされています。
Kyoto Tycoon(以下KT)は、ネットワーク経由で使えるデータベースサーバで、Tokyo Tyrantの後継製品に当たります*1


KT は HTTP ベースのプロトコルで操作することができますが、別のプロトコルを追加することもできます。
実際に memcached プロトコルのプラグインが標準でバンドルされています。(memcachedプロトコルをKTにプラグインする


と言うわけで、KT を MessagePack-RPC で使えるようにするプラグインを書いてみました。github からダウンロードできます。


MessagePack-RPC を使うと、通信を非同期化したり、他の MessagePack-RPC サーバと同時に通信したりするプログラムを簡単に書けます。そして何より、高速です。

コンパイルしたライブラリを KT の -plsv オプションに指定すると、MessagePack-RPC でアクセスできるようになります:

$ ktserver -plsv /usr/local/libexec/libktmsgpack.dylib -plex 'port=18801'


この MessagePack-RPC をプラグインした KT を、Javaから利用してみます。
MessagePack-RPC の Java 版は、最近のバージョンアップで使い勝手が大きく向上しています:

import java.util.List;
import org.msgpack.rpc.Client;
import org.msgpack.rpc.loop.EventLoop;

public class SimpleExample {
  // RPCのインタフェースを宣言
  public static interface KyotoTycoonClient {
    void set(String key, String value);
    String get(String key);
    List<String> match_prefix(String prefix);
  }

  public static void main(String[] args) throws Exception {
    EventLoop loop = EventLoop.defaultEventLoop();
    Client cli = new Client("127.0.0.1", 18801, loop);
    KyotoCabinetClient kt = cli.proxy(KyotoCabinetClient.class);  // ココがポイント

    // setとget
    kt.set("k1", "v1");
    kt.set("k2", "v2");
    String v1 = kt.get("k1");
    String v2 = kt.get("k2");

    // プレフィックスで検索
    List<String> match = kt.match_prefix("k");

    System.out.println(v1);  #=> "v1"
    System.out.println(v2);  #=> "v2"
    System.out.println(match);   #=> ["k1", "k2"]

    cli.close();
    loop.shutdown();
  }
}


KyotoTycoonClient kt = cli.proxy(KyotoTycoonClient.class); の行がポイントです。
proxy() メソッドにインタフェースを渡すと、そのインタフェースが自動的に実装されたオブジェクト*2が返ってきます。このオブジェクトのメソッドを呼ぶと、リモートサーバの機能を呼び出せます。


この KyotoTycoonClient インタフェースは、kt-msgpack パッケージの中に同梱しています:


インタフェースの定義で返り値を Future にすると、非同期型の呼び出しになります。非同期呼び出しを使うと、遅延を隠蔽して処理時間を短縮することができます。立て続けに複数の呼び出しを行うときに効果的です。
↓このプログラムは、入力データを処理しながら KT から次々にデータを取り出し、最後に結果を表示するプログラムです。

import java.util.Map;
import java.util.HashMap;
import org.msgpack.rpc.Client;
import org.msgpack.rpc.loop.EventLoop;
import org.msgpack.rpc.Future;

public class Test {
  // RPCのインタフェースを宣言
  public static interface KyotoTycoonClient { 
    void set(String key, String value);
    String get(String key);

    // 戻り値をFuture<T>にして、メソッド名の末尾に "Async "を付ける
    Future<String> getAsync(String key);
  }

  public static Future<String> getUserInfo(KyotoTycoonClient kt, String user) {
    return kt.getAsync(user+"/info");
  }

  public static void main(String[] args) throws Exception {
    EventLoop loop = EventLoop.defaultEventLoop();
    Client cli = new Client("127.0.0.1", 18801, loop);
    KyotoTycoonClient kt = cli.proxy(KyotoTycoonClient.class);

    // とりあえずデータをセットしておく
    kt.set("viver/info", "http://d.hatena.ne.jp/viver");
    kt.set("frsyuki/info", "http://github.com/frsyuki");
    kt.set("muga/info", "http://github.com/muga");
    kt.set("msgpack/info", "http://github.com/msgpack");

    // 入力データ:
    String[] input = new String[] { "viver", "frsyuki", "muga", "msgpack" };

    // KTから非同期にデータを取り出していく...
    Map<String, Future<String>> map = new HashMap<String, Future<String>>();
    for(String user : input) {
      Future<String> data = getUserInfo(c, user);
      map.put(user, data);
    }

    // 通信はこの間にバックグラウンドで進行...

    // 最後にデータを出力
    StringBuilder sb = new StringBuilder();
    for(Map.Entry<String, Future<String>> pair : map.entrySet()) {
      sb.append(pair.getKey());
      sb.append(":  ");
      sb.append(pair.getValue().get());
      sb.append("\n");
    }
    // 出力結果:
    //   msgpack:  http://github.com/msgpack
    //   muga:  http://github.com/muga
    //   frsyuki:  http://github.com/frsyuki
    //   viver:  http://d.hatena.ne.jp/viver

    System.out.println(sb.toString());

    cli.close();
    loop.shutdown();
  }
}

*1:今ならKTの説明会が無償^^; [http://fallabs.com/mikio/tech/promenade.cgi?id=113:title=Kyoto Tycoon普及大作戦]

*2:実体はjava.lang.reflect.Proxy。動的コード生成によってリフレクションを排除する実装も進んでいます。

世界の「NoSQL」開発者が東京に集結 - NOSQL afternoon in Japan

NoSQLと呼ばれる新型の分散データストアの開発者が一堂に会するイベント NOSQL afternoon in Japan が、2010年11月1日、楽天タワーで開かれました。
海外からは「Cassandra」のサポートを行う Riptano や、「MongoDB」を開発する 10gen、「Couch DB」の Cloudant、「Hadoop」の Cloudera のエンジニアが登壇し、日本からは HibariOkuyamaROMA、そして kumofs の開発者が講演しました:


ContentsPresenters
HibariJoe NortonGemini Mobile Technologies
OkuyamaTakahiro Iwase
CassandraNate McCallRiptano
ROMAMuga NishizawaRakuten
Mongo DBRoger Bodamer10 gen
kumofsSadayuki Furuhashi
Couch DBAlan HoffmanCloudant
HBASE/HadoopTodd LipconCloudera

インターネット普及による爆発的な情報量の増加に伴い、テラバイト、ペタバイトというBig Dataを日常的に処理する時代を迎えています。このようなBig Dataを扱うためには、SQL対応データベースに限らない、Not Only SQL(以下、NOSQL)と呼ばれるような多様なタイプのデータベース、データ処理技術を駆使することが求められます。新しい技術トレンドであるNOSQLについては、日本において先進的な技術者が主催するHadoopやCassandraの勉強会にて活発に議論されていることと同様に、欧米でもNOSQL Meetupなどと呼ばれる会合において更に幅広い調査研究と情報交換がおこなわれています。


このたび、日本国内においてもNOSQLの分散KVSとなるHibariのオープンソースリリースを行ったGemini Mobile Technologiesと、グローバルなNOSQL論文読書会である「A nosql summer」の主催者であり、InfiniteGraphと Scalityから後援を得ているTim Angladeが幹事となり、概要以下により、「NOSQL afternoon in Japan」として、日米のNOSQL開発者が集う会議を開催することとなりました。


「NOSQL afternoon in Japan」開催のお知らせ


最初は100人くらいの小さなイベントが想定されていたのですが、ふたを開けてみれば400人もの聴衆を集めた一大イベントになりました。
Ustream.tvでも中継され、Twitterでも#nosqlgogoハッシュタグで議論が盛り上がりました。


そのTwitter上の議論はTogetterにまとめられており、プレゼンテーションの録画もUstream.tvで見ることができます:


当日の会場の様子についても Shudo's Notes(2010/11) で写真が公開されています。


各発表者のプレゼンテーション資料も公開されており、Brief reviews of "NOSQL AFTERNOON in JAPAN"NoSQL Afternoon in Japan の発表スライド にまとめられています。


NOSQL AFTERNOON IN JAPANの振り返り

Kumofs and the MessagePack project

私は日本勢として、分散Key-valueストア Kumofs と、高速メッセージングシステム MessagePack について発表してきました。



今回は日本国外のエンジニアの目の前で直接プレゼンテーションができるチャンスだったので、英語でプレゼンテーションしてみました。
英語でプレゼンするのは6月にシリコンバレーに行ってきて、Doug Cutting(現在Cloudera社)とディスカッションしてきてから以来、2回目です。
そのうえ今回は聴衆が何百人もいる会場で、かなり緊張していたのですが、最終的には何とかなりました^^;


Twitterで好感触なコメントもいただきました。

@rogerb roger bodamer
@rogerb
http://10gen.com
Interesting: msgpack (http://msgpack.org) and bson (http://bsonspec.org/) #nosqlgogo
@nemoton Naoki Nemoto
@nemoton
Roger さんが、ガンガンMessagePack をググって、ブックマークしつつ、tweetしまくっている件について。 #nosqlgogo
@nemoton Naoki Nemoto
@nemoton
真後ろに座っているので覗き見してましたw tweetは一回でしたが、興味津々で聞かれてましたね
@timanglade Tim Anglade
@timanglade
Getting a comprehensive #kumofs overview from @frsyuki at #nosqlgogo. Seems to me like it’s another NOSQL gem everybody should know about!
http://twitter.com/rogerb/status/29351647637
http://twitter.com/nemoton/status/29351602317 http://twitter.com/nemoton/status/29352003210
http://twitter.com/timanglade/status/29351687570


その後、「ROMA の Nishizawa-san が Cassandra を MessagePack で使えるようにするパッチを書いているよ」という話を Nate McCall(Riptano)にしたところ、「そういう話は早く Cassandra のチケットに上げてくれ」という反応だったので、今にわかにJava版の開発が活気づいているところです。


今回のプレゼンテーションでは、kumofs と MessagePack の概要について話しました。特に kumofs は他のNoSQLデータストアと比べた独自性について、MessagePack は主にRPCについて、他のシステムには無い優位性を解説することに重点に置いています。

もっと詳しく知りたい方は、以下の資料をどうぞ:


今は新しいシステムの開発にも着手し始めました。MessagePackのお陰で分散システムの開発は飛躍的に簡単になっています。
色々な意味でスピード重視で "MessagePack Platform" を展開していきたいと思っているところです。

高速メッセージングシステムMessagePack - 楽天テクノロジーカンファレンス2010

もはや先月のことですが、楽天テクノロジーカンファレンス2010で発表してきました。
MessagePackについて、かなり詳しく紹介しています。


Ustream.tvの録画はこちら

MessagePackの概要(7ページ目〜)

MessagePack は、It's like JSON, but very fast and small. のフレーズの通り、「JSONみたいに使えるけど速くて小さい」シリアライズ形式です。
JSONがテキスト形式のシリアライズフォーマットであるのに対し、MessagePackは様々な工夫を取り入れたバイナリ形式のシリアライズフォーマットです。


MessagePack-RPC は、MessagePackをプロトコルに使ったRPCシステムです。多言語で利用することができ、RailsのアプリとJavaのシステムを繋げる、JavaのシステムからC++のサーバを呼び出すといった、異種言語間の通信を可能にします。kumofsのI/Oシステムから由来した設計で、高い並列性を発揮します。また、コネクションプーリングや非同期呼び出しなどをサポートし、非常に高機能であると同時に、FutureやSessionなどのコンセプトに裏打ちされた使い勝手の良いAPIを提供します。

MessagePackプロジェクトの成り立ち(13ページ目〜)

新しい分散システムを作るには、プロトコルの実装が必要になります。特に V-FIELDCagraKastor のようなストレージシステムでは、通信のオーバーヘッドが性能に直接影響してくるため、プロトコルの実装も手を抜くわけにはいきません。しかし、プロトコルの実装は非常に面倒です。
通信の問題が解決されれば、スケールアウトの恩恵を受けられるネットワークアプリケーションを、簡単に実装できる様になります。並列性や耐障害性など、本質的なシステムの設計に集中することができます。


また、CPU負荷やメモリ容量がボトルネックになるシステムの場合、サーバはC++で書きたくなります。しかし、効率的に管理タスクを自動化するには、管理ツールはC++よりもRubyなどの言語で実装したくなります。


そこで、様々なシステムの実装に使えるような汎用性があり、かつ多言語で使えるRPCシステムが欲しくなります。これが MessagePack の開発を始めたきっかけです。
MessagePackは最初に kumofs に実装し、後にこれを切り出してオープンソース化しました。

詳解MessagePack-RPC(19ページ目〜)

MessagePack-RPCは、Request, Response, Notify の3種類のメッセージだけからなる、シンプルなプロトコルです。
Request と Response にはメッセージIDが含まれており、これを対応づけることで、クライアント側でRPC要求とRPC応答を紐付けます。まずこれによって Parallel Pipeliningという並列性を高める機能を実現します。

I/Oアーキテクチャ(26ページ目〜)

I/Oアーキテクチャは、イベント駆動型になっています。サーバ側の実装をイベント駆動I/Oで実装するのはよくある構成ですが、MessagePack-RPCではクライアント側でもイベント駆動I/Oを採用しています。


まず、複数のクライアントインスタンスを一つのイベントループに載せることが可能です。これによって、スレッドプログラミングをすることなく、複数のサーバと同時に通信するアプリケーションを書くことができます。
また、サーバとクライアントの実装アーキテクチャが同じであることから、一つのイベントループ上にサーバとクライアントの両方を載せることが可能です。これによって、サーバとクライアントの両方の性質を持つアプリケーション、すなわちサーバ同士が通信するクラスタアプリケーションを簡単に実装することができます。


さらに、イベントループには、MessagePack-RPC以外のプロトコルを扱うイベントハンドラや、タイマーやシグナルのハンドラも載せることができます。これにより、HTTPとMessagePack-RPCの両方に対応したアプリケーションや、kumo-gatewayのようなプロトコルを変換するゲートウェイサーバを簡単に実装することができます。
先日リリースしたMessagePack-RPC Java版では、イベントループに JBoss XNIO を使っています。

FutureとSession(35ページ目〜)

イベント駆動型I/Oを駆使するプログラムは複雑になりがちですが、MessagePack-RPCでは、これをFutureという概念で扱うことによって隠蔽します。
また、Sessionは、コネクションの概念を隠蔽します。コネクションの確立、接続維持、再接続は、MessagePack-RPCのライブラリ内で自動的に行うため、面倒なコードを一切記述することなく、コネクションプーリングなどの高度な機能を利用することが可能です。

MessagePackの未来(64ページ目〜)

MessagePackは、Sedue Search CloudAmebaなうなどで既に利用されています。
コミッタには海外の開発者も含まれており、開発は非常に活発です。


「学生」「余暇の時間に」といったオープンソースの "瞬発力" や "斬新さ" を取り入れるには、MessagePackプロジェクトが「魅力的」である必要があるだろうと考えています。
また一方で、「システムの開発に」「製品に」といった "持続力" や "堅牢さ" を取り入れるためには、「有用」である必要があるだろうと思います。
この両方を実現していくには、コミッタの力が欠かせません。ぜひ開発者にエールを送っていただければ幸いです。
# 開発者はTwitterMessagePack OR msgpack と検索すると見つかります^^;


The MessagePack Project


MessagePackについてもっと詳しく知りたい方は、gumiStudy#7 でお会いしましょう^^;

日本OSS奨励賞を受賞しました

このたび、独立行政法人 情報処理推進機構 日本OSS奨励賞を受賞いたしました。ITPro
他に受賞された方々の名前を拝見すると恐縮ではありますが、高く評価していただいたことを大変光栄に思います。


受賞理由は、「分散Key-valueストアである「kumofs」を開発し、OSSとして公開している」ことと、「MessagePackを精力的に開発し、こちらもOSSとして公開している」ことの2点で、新たに開発したオープンソースソフトウェアを公開している点を評価していただいたようです。


kumofsを共に開発したえとらぼ株式会社の皆様、そしてコミュニティの方々に感謝します。

また、MessagePackのコミットログを見ると分かりますが、MessagePackの各言語版の実装は私の手によるものではなく、各言語のエキスパートの方々によって実装されています。
先日にもMessagePack for Java 0.4をリリースしたところですが、これからもガツガツと 設計 & 実装 & 宣伝 を実施していきたいと思っているところです。


MessagePack for Java 0.4 開発版リリース!

バイナリシリアライズ形式 MessagePackJava版の最新版をリリースしました!
新しいAPIを大量に追加し、使い勝手が大幅に向上しています。


今回は開発版のリリースで、安定版のリリースはもう少し先になります。
こういうAPIの方が良いのではないか、ここの実装にバグがある、このコードはもっと最適化できる、こんな用途に使ってみた などなど、フィードバックをお待ちしていますm(_ _)m


ここでは極めて重要な新機能である、

  • 動的コード生成
  • optionalフィールド
  • 動的型付けオブジェクト
  • テンプレート

について紹介します。

動的コード生成

リフレクションを使うと、クラスからメンバ変数の一覧を取得することができ、ユーザー定義のクラスをシリアライズ・デシリアライズできるようになります。これは非常に便利で、わざわざシリアライズ用のメソッドを自前で実装することなく、オブジェクトを渡すだけでシリアライズできるようになります。
しかし、リフレクションは遅いという重大な欠点があります。


そこで MessagePack では、リフレクションで取り出した情報を元にJavaのコードを生成し、それを実行時にコンパイル・リンクすることで、シリアライズ速度を大幅に高速化します。

使い方は↓このようになります。単にオブジェクトを渡すだけでシリアライズでき、クラスを指定するだけでデシリアライズできます:

import org.msgpack.MessagePack;
import org.msgpack.annotation.MessagePackMessage;

public class Main {
    // ユーザー定義のクラス
    // アノテーションを付ける
    @MessagePackMessage
    public static class MyClass {
        public String str;
        public double num;
    }

    public static void main(String[] args) {
        MyClass src = new MyClass();
        src.str = "msgpack";
        src.num = 0.4;

        // シリアライズ
        byte[] raw = MessagePack.pack(src);

        // デシリアライズ
        MyClass dst = MessagePack.unpack(raw, MyClass.class);
    }
}

とても簡単ですね! 革命的な使いやすさです。
このようにアノテーションを付けるだけで、高速にシリアライズ・デシリアライズができます。


何かの事情でアノテーションを付けられない場合でも、事前に登録しておけば同じ効果が得られます。

        // ユーザー定義クラスを事前に登録しておく
        MessagePack.register(MyClass.class);


動的コード生成機能の実装は、分散Key-valueストア「ROMA」の開発者としても知られる @muga_nishizawaさんによるものです。実はJavaで定番の動的コード生成ライブラリであるJavassistの開発者でもあったようです。

optionalフィールド

データの寿命は、プログラムの寿命より長いことがあります。
このためデータとプログラムはできるだけ分離しておくのがセオリーとされますが、ここでデータとプログラムの間に立つシリアライザは、悩ましい問題を抱えることになります。プログラムが変更され、データのフォーマットが変更されたときでも、残されている古いデータも正しく扱えなければなりません。


この問題に対して MessagePack では、オブジェクトをシリアライズシリアライズしているとき、互換性を保ったままメンバフィールドを追加できるようにする仕組みを提供します。

まず↓このようなクラスがあったとします:

@MessagePackMessage
public static class MyClass {
    public String str;
    public double num;
}

この定義に従ってシリアライズされたデータがたくさん蓄積されていたり、この定義に従って動いている再起動したくないサーバがあるとします。
これらとの互換性を保ったまま、クラスの定義を↓このように変更することができます:

@MessagePackMessage
public static class MyClass {
    public String str;
    public double num;

    // 新しいフィールドをオプショナルとして追加
    @MessagePackOptional
    public int flag = 0;
}

新しく追加したフィールドにはアノテーションを付け、optionalなフィールドにします。


この定義に従って古いデータを読み込むと、optionalなフィールドにはデフォルト値が設定されます。
逆に、新しいフィールドが追加されているデータを古いコードで読み込むこともできます。その場合は新しいフィールドは単に無視されます。これによって古いサーバと新しいサーバが相互に通信することができます。ローリングアップデートができますね。

動的型付けオブジェクト

MessagePack は、シリアライズ後のバイト列にオブジェクトの「型」を保存します。このバイト列をデシリアライズする側から見ると、デシリアライズ時=実行時に型が決定される動的型付けの性質を持っていると言えます。
例えば Ruby は動的型付け言語なので、このデータそのまま扱えるのですが、Java は静的型付け言語なので、そのままではうまく扱えません。具体的に言えば、デシリアライズされたオブジェクトの型が Object だと非常に使いにくいです。


そこで MessagePack では、動的型付けオブジェクトテンプレート という2つの機能を提供します。


まず MessagePackObject は、動的に型付けされたオブジェクトを表現するクラスです。
MessagePack.unpack(byte[] buffer) などのデシリアライズAPIの返り値は、このMessagePackObjectになります。このクラスは、実際の型を検査するメソッド(isIntegerType()isListType()など)や、静的な型に変換するメソッド(asString()convert(Template)など)を持っています。

MessagePackObject を使うことで、コンパイル時には知り得ない未知のデータ をうまく取り扱うことができます。

テンプレート

テンプレートは、デシリアライズされたオブジェクトを静的な型に変換する機能を提供します。同時に型チェックを行い、想定外のデータだったら例外(MessageTypeException)を投げます。
テンプレートは↓このように使います:

import java.util.ArrayList;
import java.util.List;

import org.msgpack.MessagePack;
import static org.msgpack.Templates.*;

public class Main {
    public static void main(String[] args) {
        // シリアライズするオブジェクトを作成
        List<String> src = new ArrayList();
        src.add("msgpack");
        src.add("kumofs");
        src.add("viver");

        // バイト列にシリアライズ
        byte[] raw = MessagePack.pack(src);

        // 方法1: テンプレートを指定して直接デシリアライズ
        List<String> dst1 = (List<String>)MessagePack.unpack(raw, tList(TString));

        // 方法2: いったん動的型付けオブジェクトにデシリアライズしてから型変換
        MessagePackObject dynamic = MessagePack.unpack(raw);
        List<String> dst2 = (List<String>)dynamic.convert(tList(TString));
    }
}

テンプレートは org.msgpack.Templates.* に定義されており、import static すると tList(Template elementTemplate)tArray(Template elementTemplate)TStringTIntegerなどのテンプレートが使えるようになります。

使い方

多くの機能は org.msgpack.MessagePack クラスで使えるようになっています:

package org.msgpack;
public class MessagePack {
    public static byte[] pack(Object obj);
    public static byte[] pack(Object obj, Template tmpl) throws MessageTypeException;
    public static void pack(OutputStream out, Object obj) throws IOException;
    public static void pack(OutputStream out, Object obj, Template tmpl) throws IOException;

    public static MessagePackObject unpack(byte[] buffer) throws MessageTypeException;
    public static MessagePackObject unpack(InputStream in) throws IOException;
    public static Object unpack(byte[] buffer, Template tmpl) throws MessageTypeException;
    public static Object unpack(InputStream in, Template tmpl) throws IOException, MessageTypeException;
    public static <T> T unpack(byte[] buffer, Class<T> klass) throws MessageTypeException;
    public static <T> T unpack(InputStream in, Class<T> klass) throws IOException, MessageTypeException;

    public static void register(Class<?> target);
    public static void register(Class<?> target, Template tmpl);
    public static void registerPacker(Class<?> target, MessagePacker packer);
    public static void registerConverter(Class<?> target, MessageConverter converter);
    public static void registerUnpacker(Class<?> target, MessageUnpacker unpacker);
}

インストール

MessagePack for Java 0.4-devel は、mavenを使ってインストールできます。
mavenリポジトリhttp://msgpack.org/maven2/org/msgpack/msgpack/ にあります。*1
ソースコードhttp://github.com/msgpack/msgpack にあります。


フィードバックはTwitterでお気軽に!

現在のJava版のメンテナは@muga_nishizawa@frsyukiで捕捉できます。

メーリングリストとIRCもあります。ぜひどうぞ。MessagePack Users


The MessagePack Project

*1:javassistのバージョン3.12.1.GA以降に依存しています。javassistは[https://repository.jboss.org/nexus/content/groups/public/:title=JBossのmavenリポジトリ]にあります。