m-namikiの日記

おもしろき こともなき世を おもしろく

Protocol Buffers

Protocol BuffersGoogleが開発したシリアライズフォーマットです。次案件で利用することになりそうなので、勉強を兼ねてメモを残しておきます。

ダウンロードとビルド

こちら からパッケージをダウンロードしました。今回ダウンロードしたのは「protobuf-2.4.1.zip」と「protoc-2.4.1-win32.zip」です。Win32の方にはJavaライブラリのビルドに利用する「protoc.exe」が含まれています。C++の環境がある場合は自分でビルドできるので不要ですが、そんな環境はないのでダウンロードしました。
なお、ここではC:\javaで「protobuf-2.4.1.zip」と「protoc-2.4.1-win32.zip」を展開します。
win32の方を展開したら「protoc.exe」が存在するディレクトリを環境変数のPathに追加しておきます。(ここではC:\java\protoc-2.4.1-win32)追加したらコマンドプロンプトから以下のコマンドを実行して確認します。

> protoc --version
libprotoc 2.4.1

次に「protobuf-2.4.1.zip」を展開します。展開したら「protoc-2.4.1\src」に「protoc.exe」をコピーしておき、JavaライブラリをMaven2でビルドします。

cd C:\java\protobuf-2.4.1\java
mvn install

ビルドが終了すると、「target」に「protobuf-java-2.4.1.jar」が作成されます。またMaven2のローカルリポジトリにもインストールされるので、Maven2を利用しているプロジェクトの場合、プロジェクトのpom.xmlで指定することで利用することが可能です。

<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>2.4.1</version>
</dependency>

.protoの作成

.protoは、シリアライズするデータの構造を定義するファイルです。.protoファイルの書式等の説明はこちらにあります。で、これとtutorialを参考に以下のようなperson.protoを作成してsrc/main/javaの直下に置いておきます。

package net.masa.sandbox.protobuf;
option java_outer_classname = "PersonProto";

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
}

.protoのコンパイルと自動生成

この.protoとprotocを使って、Javaソースを自動生成します。コマンドプロンプトで以下のコマンドを実行します。

cd C:\eclipse\workspace\sandbox\src\main\java
protoc --java_out=. person.proto

実行後、src/main/javaの下にnet.masa.sandbox.protobuf.PersonProtoが作成されます。これが.protoを元に作成されたJavaソースです。

メッセージの読み書き

自動生成されたJavaソースを利用して、シリアライズとデシリアライズを行ってみます。XMLと違ってパースとか余計なことを考えないで済むのがお手軽ですね。

public static void main(String[] args) throws Exception {
    // ファイルへの書き出し
    File file = new File("/temp", "person.data");
    PersonProto.Person.Builder builder = PersonProto.Person.newBuilder();
    PersonProto.Person johnDo = builder.setName("John Do").setId(1)
            .setEmail("sample@example.com").build();
    OutputStream out = new FileOutputStream(file);
    johnDo.writeTo(out);
    out.close();

    // ファイルの読み込み
    InputStream in = new FileInputStream(file);
    PersonProto.Person person = PersonProto.Person.parseFrom(in);
    in.close();
    System.out.printf("Name:%s Id:%d Email:%s%n", person.getName(), person
            .getId(), person.getEmail());
}

今回は簡単なサンプルでの検証したが、Protocol Buffersを使って何が嬉しいかというとRPCに対応しているところになんだと思います。なので、次回はRPC機能を利用してみたいと思います。