Dart で生成されたコード
proto2 と proto3 で生成されるコードの相違点を強調表示しています。これらの相違点は、このドキュメントで説明されている生成されたコードにあり、ベース API にはないことに注意してください。ベース API は両方のバージョンで同じです。このドキュメントを読む前に、proto2 言語ガイド および/または proto3 言語ガイド をお読みください。
コンパイラの起動
プロトコルバッファコンパイラは、Dart コードを生成するための プラグイン を必要とします。手順 に従ってインストールすると、--dart_out
コマンドラインフラグで呼び出されたときに protoc
が使用する protoc-gen-dart
バイナリが提供されます。--dart_out
フラグは、コンパイラに Dart ソースファイルを書き込む場所を指示します。.proto
ファイル入出力の場合、コンパイラはとりわけ .pb.dart
ファイルを生成します。
.pb.dart
ファイルの名前は、.proto
ファイルの名前を取得し、次の 2 つの変更を加えることによって計算されます。
- 拡張子 (
.proto
) は.pb.dart
に置き換えられます。たとえば、foo.proto
という名前のファイルは、foo.pb.dart
という名前の出力ファイルになります。 - proto パス (
--proto_path
または-I
コマンドラインフラグで指定) は、出力パス (--dart_out
フラグで指定) に置き換えられます。
たとえば、次のようにコンパイラを呼び出すと
protoc --proto_path=src --dart_out=build/gen src/foo.proto src/bar/baz.proto
コンパイラは、ファイル src/foo.proto
および src/bar/baz.proto
を読み取ります。build/gen/foo.pb.dart
および build/gen/bar/baz.pb.dart
を生成します。コンパイラは必要に応じてディレクトリ build/gen/bar
を自動的に作成しますが、build
または build/gen
は作成しません。これらはすでに存在している必要があります。
メッセージ
単純なメッセージ宣言が与えられた場合
message Foo {}
プロトコルバッファコンパイラは、クラス GeneratedMessage
を拡張する Foo
という名前のクラスを生成します。
クラス GeneratedMessage
は、メッセージ全体をチェック、操作、読み取り、または書き込みできるメソッドを定義します。これらのメソッドに加えて、Foo
クラスは次のメソッドとコンストラクタを定義します。
Foo()
: デフォルトコンストラクタ。すべての単数フィールドが設定解除され、繰り返しフィールドが空のインスタンスを作成します。Foo.fromBuffer(...)
: メッセージを表すシリアライズされたプロトコルバッファデータからFoo
を作成します。Foo.fromJson(...)
: メッセージをエンコードする JSON 文字列からFoo
を作成します。Foo clone()
: メッセージ内のフィールドのディープクローンを作成します。Foo copyWith(void Function(Foo) updates)
: このメッセージの書き込み可能なコピーを作成し、それにupdates
を適用し、コピーを読み取り専用にしてから返します。static Foo create()
: 単一のFoo
を作成するファクトリ関数。static PbList<Foo> createRepeated()
:Foo
要素の可変繰り返しフィールドを実装する List を作成するファクトリ関数。static Foo getDefault()
:Foo
のシングルトンインスタンスを返します。これは、新しく構築された Foo のインスタンスと同一です (したがって、すべての単数フィールドは設定解除され、すべての繰り返しフィールドは空です)。
ネストされた型
メッセージは別のメッセージ内で宣言できます。例:
message Foo {
message Bar {
}
}
この場合、コンパイラは 2 つのクラス Foo
と Foo_Bar
を生成します。
フィールド
前のセクションで説明したメソッドに加えて、プロトコルバッファコンパイラは、.proto
ファイル内のメッセージ内で定義された各フィールドのアクセサメソッドを生成します。
生成される名前は常にキャメルケース命名を使用することに注意してください。これは、.proto
ファイル内のフィールド名がアンダースコア付きの小文字 (推奨) を使用している場合でも同様です。ケース変換は次のように機能します。
- 名前の各アンダースコアについて、アンダースコアが削除され、次の文字が大文字になります。
- 名前がプレフィックス (例: "has") を付加する場合、最初の文字は大文字になります。それ以外の場合は、小文字になります。
したがって、フィールド foo_bar_baz
の場合、ゲッターは get fooBarBaz
になり、has
がプレフィックスされたメソッドは hasFooBarBaz
になります。
単数プリミティブフィールド (proto2)
これらのフィールド定義のいずれかについて
optional int32 foo = 1;
required int32 foo = 1;
コンパイラは、メッセージクラスに次のアクセサメソッドを生成します。
int get foo
: フィールドの現在の値を返します。フィールドが設定されていない場合は、デフォルト値を返します。bool hasFoo()
: フィールドが設定されている場合はtrue
を返します。set foo(int value)
: フィールドの値を設定します。これを呼び出すと、hasFoo()
はtrue
を返し、get foo
はvalue
を返します。void clearFoo()
: フィールドの値をクリアします。これを呼び出すと、hasFoo()
はfalse
を返し、get foo
はデフォルト値を返します。
他の単純なフィールドタイプの場合、対応する Dart タイプは スカラー値型テーブル に従って選択されます。メッセージ型および enum 型の場合、値型はメッセージまたは enum クラスに置き換えられます。
単数プリミティブフィールド (proto3)
このフィールド定義の場合
int32 foo = 1;
コンパイラは、メッセージクラスに次のアクセサメソッドを生成します。
int get foo
: フィールドの現在の値を返します。フィールドが設定されていない場合は、デフォルト値を返します。set foo(int value)
: フィールドの値を設定します。これを呼び出すと、get foo
はvalue
を返します。void clearFoo()
: フィールドの値をクリアします。これを呼び出すと、get foo
はデフォルト値を返します。bool hasFoo()
: フィールドが設定されている場合はtrue
を返します。void clearFoo()
: フィールドの値をクリアします。これを呼び出すと、hasFoo()
はfalse
を返し、get foo
はデフォルト値を返します。
単数メッセージフィールド
メッセージ型が与えられた場合
message Bar {}
Bar
フィールドを持つメッセージの場合
// proto2
message Baz {
optional Bar bar = 1;
// The generated code is the same result if required instead of optional.
}
// proto3
message Baz {
Bar bar = 1;
}
コンパイラは、メッセージクラスに次のアクセサメソッドを生成します。
Bar get bar
: フィールドの現在の値を返します。フィールドが設定されていない場合は、デフォルト値を返します。set bar(Bar value)
: フィールドの値を設定します。これを呼び出すと、hasBar()
はtrue
を返し、get bar
はvalue
を返します。bool hasBar()
: フィールドが設定されている場合はtrue
を返します。void clearBar()
: フィールドの値をクリアします。これを呼び出すと、hasBar()
はfalse
を返し、get bar
はデフォルト値を返します。Bar ensureBar()
:hasBar()
がfalse
を返す場合、bar
を空のインスタンスに設定し、bar
の値を返します。これを呼び出すと、hasBar()
はtrue
を返します。
繰り返しフィールド
このフィールド定義の場合
repeated int32 foo = 1;
コンパイラは以下を生成します。
List<int> get foo
: フィールドをバッキングするリストを返します。フィールドが設定されていない場合は、空のリストを返します。リストへの変更はフィールドに反映されます。
Int64 フィールド
このフィールド定義の場合
// proto2
optional int64 bar = 1;
// proto3
int64 bar = 1;
コンパイラは以下を生成します。
Int64 get bar
: フィールド値を含むInt64
オブジェクトを返します。
Int64
は Dart コアライブラリに組み込まれていないことに注意してください。これらのオブジェクトを操作するには、Dart fixnum
ライブラリをインポートする必要がある場合があります。
import 'package:fixnum/fixnum.dart';
Map フィールド
map
フィールド定義が次のように与えられた場合
map<int32, int32> map_field = 1;
コンパイラは次のゲッターを生成します。
Map<int, int> get mapField
: フィールドをバッキングする Dart マップを返します。フィールドが設定されていない場合は、空のマップを返します。マップへの変更はフィールドに反映されます。
Any
Any
フィールドが次のように与えられた場合
import "google/protobuf/any.proto";
message ErrorStatus {
string message = 1;
google.protobuf.Any details = 2;
}
生成されたコードでは、details
フィールドのゲッターは com.google.protobuf.Any
のインスタンスを返します。これにより、Any
の値をパックおよびアンパックするための次の特別なメソッドが提供されます。
/// Unpacks the message in [value] into [instance].
///
/// Throws a [InvalidProtocolBufferException] if [typeUrl] does not correspond
/// to the type of [instance].
///
/// A typical usage would be `any.unpackInto(new Message())`.
///
/// Returns [instance].
T unpackInto<T extends GeneratedMessage>(T instance,
{ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY});
/// Returns `true` if the encoded message matches the type of [instance].
///
/// Can be used with a default instance:
/// `any.canUnpackInto(Message.getDefault())`
bool canUnpackInto(GeneratedMessage instance);
/// Creates a new [Any] encoding [message].
///
/// The [typeUrl] will be [typeUrlPrefix]/`fullName` where `fullName` is
/// the fully qualified name of the type of [message].
static Any pack(GeneratedMessage message,
{String typeUrlPrefix = 'type.googleapis.com'});
Oneof
oneof
定義が次のように与えられた場合
message Foo {
oneof test {
string name = 1;
SubMessage sub_message = 2;
}
}
コンパイラは次の Dart enum 型を生成します。
enum Foo_Test { name, subMessage, notSet }
さらに、次のメソッドを生成します。
Foo_Test whichTest()
: 設定されているフィールドを示す enum を返します。いずれも設定されていない場合はFoo_Test.notSet
を返します。void clearTest()
: 現在設定されている oneof フィールドの値をクリアし (存在する場合)、oneof ケースをFoo_Test.notSet
に設定します。
oneof 定義内の各フィールドについて、通常のフィールドアクセサメソッドが生成されます。たとえば、name
の場合
String get name
: oneof ケースがFoo_Test.name
の場合、フィールドの現在の値を返します。それ以外の場合は、デフォルト値を返します。set name(String value)
: フィールドの値を設定し、oneof ケースをFoo_Test.name
に設定します。これを呼び出すと、get name
はvalue
を返し、whichTest()
はFoo_Test.name
を返します。void clearName()
: oneof ケースがFoo_Test.name
でない場合、何も変更されません。それ以外の場合は、フィールドの値をクリアします。これを呼び出すと、get name
はデフォルト値を返し、whichTest()
はFoo_Test.notSet
を返します。
列挙型
enum 定義が次のように与えられた場合
enum Color {
COLOR_UNSPECIFIED = 0;
COLOR_RED = 1;
COLOR_GREEN = 2;
COLOR_BLUE = 3;
}
プロトコルバッファコンパイラは、ProtobufEnum
クラスを拡張する Color
という名前のクラスを生成します。このクラスには、4 つの値のそれぞれに対して static const Color
が含まれ、値を格納する static const List<Color>
も含まれます。
static const List<Color> values = <Color> [
COLOR_UNSPECIFIED,
COLOR_RED,
COLOR_GREEN,
COLOR_BLUE,
];
また、次のメソッドも含まれます。
static Color? valueOf(int value)
: 指定された数値に対応するColor
を返します。
各値には次のプロパティがあります。
name
: .proto ファイルで指定された enum の名前。value
: .proto ファイルで指定された enum の整数値。
.proto
言語では、複数の enum シンボルが同じ数値を持つことができることに注意してください。同じ数値を持つシンボルは同義語です。例:
enum Foo {
BAR = 0;
BAZ = 0;
}
この場合、BAZ
は BAR
の同義語であり、次のように定義されます。
static const Foo BAZ = BAR;
enum は、メッセージ型内でネストして定義できます。たとえば、enum 定義が次のように与えられた場合
message Bar {
enum Color {
COLOR_UNSPECIFIED = 0;
COLOR_RED = 1;
COLOR_GREEN = 2;
COLOR_BLUE = 3;
}
}
プロトコルバッファコンパイラは、GeneratedMessage
を拡張する Bar
という名前のクラスと、ProtobufEnum
を拡張する Bar_Color
という名前のクラスを生成します。
拡張機能 (proto2 のみ)
拡張機能の範囲 とトップレベルの拡張機能定義を含むファイル foo_test.proto
が与えられた場合
message Foo {
extensions 100 to 199;
}
extend Foo {
optional int32 bar = 101;
}
プロトコルバッファコンパイラは、Foo
クラスに加えて、ファイル内の各拡張機能フィールドの static Extension
と、ExtensionRegistry
内のすべての拡張機能を登録するためのメソッドを含む Foo_test
クラスを生成します。
static final Extension bar
static void registerAllExtensions(ExtensionRegistry registry)
: 指定されたレジストリ内の定義されたすべての拡張機能を登録します。
Foo
の拡張機能アクセサは次のように使用できます。
Foo foo = Foo();
foo.setExtension(Foo_test.bar, 1);
assert(foo.hasExtension(Foo_test.bar));
assert(foo.getExtension(Foo_test.bar)) == 1);
拡張機能は、別のメッセージ内にネストして宣言することもできます。
message Baz {
extend Foo {
optional int32 bar = 124;
}
}
この場合、拡張機能 bar
は、代わりに Baz
クラスの静的メンバーとして宣言されます。
拡張機能を持つ可能性のあるメッセージを解析するときは、解析できるようにする拡張機能を登録した ExtensionRegistry
を提供する必要があります。そうしないと、これらの拡張機能は不明なフィールドとして扱われます。例:
ExtensionRegistry registry = ExtensionRegistry();
registry.add(Baz.bar);
Foo foo = Foo.fromBuffer(input, registry);
不明なフィールドを持つ解析済みのメッセージがすでにある場合は、ExtensionRegistry
で reparseMessage
を使用してメッセージを再解析できます。不明なフィールドのセットにレジストリに存在する拡張機能が含まれている場合、これらの拡張機能が解析され、不明なフィールドセットから削除されます。メッセージにすでに存在する拡張機能は保持されます。
Foo foo = Foo.fromBuffer(input);
ExtensionRegistry registry = ExtensionRegistry();
registry.add(Baz.bar);
Foo reparsed = registry.reparseMessage(foo);
拡張機能を取得するこの方法は、全体的によりコストがかかることに注意してください。可能な場合は、GeneratedMessage.fromBuffer
を実行するときに、必要なすべての拡張機能を含む ExtensionRegistry
を使用することをお勧めします。
サービス
サービス定義が与えられた場合
service Foo {
rpc Bar(FooRequest) returns(FooResponse);
}
プロトコルバッファコンパイラは、grpc
オプション (例: --dart_out=grpc:output_folder
) を指定して呼び出すことができます。この場合、gRPC をサポートするコードが生成されます。詳細については、gRPC Dart クイックスタートガイド を参照してください。