メッセージタイプの拡張
ここからはさらに応用的な話題として、メッセージタイプの拡張やRPC、様々なオプションについて解説する。
まずは「メッセージタイプの拡張」だ。これは、既存のメッセージタイプをいじることなく、フィールドを追加することができる仕組みのことである。
例えば、拡張可能なPersonクラスを作っておくと、別のユーザが同じPerson型を拡張し、「体重」などのフィールドを追加して利用することができる。
メッセージタイプを拡張し、それを利用するには、以下の3つの手順を踏む必要がある。
- メッセージタイプを拡張可能にしておく
- メッセージを拡張する
- 拡張されたメッセージを利用する
順に説明していこう。
メッセージタイプを拡張可能にしておく
では、Personクラスを拡張可能にしてみよう。そのためには、メッセージタイプ内に「拡張用として使用するタグの範囲」を指定するためのextensionを宣言する。以下のような感じだ。
message Person {
...
extensions 1000 to max;
}
「extensions 1000 to max;」となっている部分が拡張の指定だ。ここでは、1000以上のタグは拡張用に予約すると言う意味になる。maxは指定できるタグの最大値であり、536,870,911を表す。
メッセージタイプを拡張する
メッセージタイプを拡張するには、以下のようにextendキーワードを使用する。
extend Person {
optional int32 weight = 1000;
}
これで、体重を表す「weight」というフィールドを持つ、自分だけのPersonができあがった。では、この拡張されたPerson型を用いてプログラミングを行ってみよう。
拡張されたメッセージを利用する
拡張されたメッセージを利用すると言っても、基本は変わらない。拡張フィールド以外へのアクセス方法は先ほどと同様だ。ただし、拡張フィールドを利用する場合はいろいろと勝手が異なるので注意してほしい。
まず、拡張フィールドの読み書きにはsetExtension()、getExtension()といったメソッドを使用する必要がある。これらのメソッドを使う際には、拡張フィールドの情報を表す定数(ここではPersons2.weight)を第一引数として指定する。
Persons.Person shiraishi = shiraishiBuilder
.setName(shiraishiName)
...(略)...
// 拡張フィールドに値をセット
.setExtension(Persons.weight, 65)
.build();
System.out.printf("名前:%s 年齢:%d 性別:%s 体重:%d%n",
shiraishi.getName(), shiraishi.getAge(),
shiraishi.getGender(),
// 拡張フィールドから値を取得
shiraishi.getExtension(Persons.weight));
加えて、拡張フィールドを含むバイナリからオブジェクトを復元する際、拡張フィールドの値も同時に読み出すには、「ExtensionRegistry」という特殊なクラスを指定して、「どの拡張フィールドを読み出すか」を指定する必要もある。
// ファイルからの読み込み
InputStream in = new FileInputStream(FILE_NAME);
// ExtensionRegistryの作成
ExtensionRegistry registry = ExtensionRegistry.newInstance();
// weightフィールドを追加する
registry.add(Persons.weight);
// ExtensionRegistryを指定して、入力ストリームからオブジェクトを構築
shiraishi = Persons.Person.parseFrom(in, registry);
ExtensionRegistory.newInstance()を用いて拡張レジストリのインスタンスを作成した後、add()メソッドを用いて「どの拡張フィールドを同時に読み込むか」を指定する。
さらにその拡張レジストリを、parseFrom()メソッド(バイナリからオブジェクトを復元するメソッド)に引き渡すことで、指定した拡張フィールドもきちんと読み込まれたPersonインスタンスが作成される。
少々回りくどい方法だが、互換性やセキュリティ、パフォーマンスなどの理由から、あえてこのような設計にしたとのことだ。