エディションの機能設定
このトピックでは、Edition 2023 に含まれる機能の概要を説明します。以降のエディションの機能もこのトピックに追加されます。新しいエディションはニュースセクションで発表されます。
新しいスキーマ定義コンテンツで機能設定を構成する前に、それらを使用する理由を理解していることを確認してください。機能のカーゴ・カルトは避けてください。
Prototiller
Prototiller は、proto2 および proto3 定義ファイルを Editions 構文に変換するコマンドラインツールです。まだリリースされていませんが、このトピック全体で参照されています。
機能
以下のセクションには、Edition 2023 の機能を使用して構成できるすべての動作が含まれています。proto2 または proto3 の動作の保持では、proto 定義ファイルが proto2 または proto3 ファイルのように動作するように、デフォルトの動作をオーバーライドする方法を示します。エディションと機能が連携して動作を設定する方法の詳細については、Protobuf Editions 概要を参照してください。
機能設定は異なるレベルで適用されます
ファイルレベル: これらの設定は、オーバーライド設定を持たないすべての要素(メッセージ、フィールド、列挙型など)に適用されます。
非ネスト: メッセージ、列挙型、サービスは、ファイルレベルで行われた設定をオーバーライドできます。これらは、オーバーライドされない限り、それらの中のすべて(メッセージフィールド、列挙値)に適用されますが、他の並列のメッセージや列挙型には適用されません。
ネスト: Oneof、メッセージ、列挙型は、ネストされているメッセージからの設定をオーバーライドできます。
最下位レベル: フィールド、拡張機能、列挙値、拡張範囲、およびメソッドは、設定をオーバーライドできる最下位レベルです。
以下の各セクションには、機能が適用できるスコープを示すコメントがあります。以下のサンプルは、各スコープに適用されたモック機能を示しています。
edition = "2023";
// File-level scope definition
option features.bar = BAZ;
enum Foo {
// Enum (non-nested scope) definition
option features.bar = QUX;
A = 1;
B = 2;
}
message Corge {
// Message (non-nested scope) definition
option features.bar = QUUX;
message Garply {
// Message (nested scope) definition
option features.bar = WALDO;
string id = 1;
}
// Field (lowest-level scope) definition
Foo A = 1 [features.bar = GRAULT];
}
この例では、最下位レベルのスコープ機能定義にある「GRAULT
」設定が、非ネストスコープの「QUUX
」設定をオーバーライドします。そして、Garply メッセージ内では、「WALDO
」が「QUUX
」をオーバーライドします。
features.enum_type
この機能は、定義されたセットに含まれていない enum 値の処理方法の動作を設定します。オープンおよびクローズド enum の詳細については、Enum の動作を参照してください。
この機能は proto3 ファイルには影響しないため、このセクションには proto3 ファイルの変更前後の例はありません。
利用可能な値
CLOSED:
クローズド enum は、範囲外の enum 値を未知のフィールドセットに格納します。OPEN:
オープン enum は、範囲外の値を直接そのフィールドにパースします。
適用可能なスコープ: ファイル、Enum
Edition 2023 のデフォルトの動作: OPEN
proto2 の動作: CLOSED
proto3 の動作: OPEN
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
enum Foo {
A = 2;
B = 4;
C = 6;
}
Prototillerを実行した後、同等のコードは次のようになります。
edition = "2023";
enum Foo {
// Setting the enum_type feature overrides the default OPEN enum
option features.enum_type = CLOSED;
A = 2;
B = 4;
C = 6;
}
features.field_presence
この機能は、フィールドの存在、つまり Protobuf フィールドが値を持っているかどうかの追跡動作を設定します。
利用可能な値
LEGACY_REQUIRED
: このフィールドはパースとシリアル化に必須です。明示的に設定された値は、デフォルト値と同じであっても、ワイヤ上にシリアル化されます。EXPLICIT
: このフィールドは明示的な存在追跡を行います。明示的に設定された値は、デフォルト値と同じであっても、ワイヤ上にシリアル化されます。単一のプリミティブフィールドの場合、EXPLICIT
に設定されたフィールドに対してhas_*
関数が生成されます。IMPLICIT
: このフィールドは存在追跡を行いません。デフォルト値は、明示的に設定されていてもワイヤ上にシリアル化されません。IMPLICIT
に設定されたフィールドに対してhas_*
関数は生成されません。
適用可能なスコープ: ファイル、フィールド
Edition 2023 のデフォルトの動作: EXPLICIT
proto2 の動作: EXPLICIT
proto3 の動作: optional
ラベルを持つフィールドでない限りIMPLICIT
です。その場合はEXPLICIT
のように動作します。詳細については、Proto3 API における存在を参照してください。
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
message Foo {
required int32 x = 1;
optional int32 y = 2;
repeated int32 z = 3;
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
message Foo {
// Setting the field_presence feature retains the proto2 required behavior
int32 x = 1 [features.field_presence = LEGACY_REQUIRED];
int32 y = 2;
repeated int32 z = 3;
}
以下に proto3 ファイルを示します。
syntax = "proto3";
message Bar {
int32 x = 1;
optional int32 y = 2;
repeated int32 z = 3;
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
// Setting the file-level field_presence feature matches the proto3 implicit default
option features.field_presence = IMPLICIT;
message Bar {
int32 x = 1;
// Setting the field_presence here retains the explicit state that the proto3
// field has because of the optional syntax
int32 y = 2 [features.field_presence = EXPLICIT];
repeated int32 z = 3;
}
required
および optional
ラベルは Editions には存在しなくなりました。対応する動作はfield_presence
機能によって明示的に設定されるためです。
features.json_format
この機能は、JSON のパースとシリアル化の動作を設定します。
この機能は proto3 ファイルには影響しないため、このセクションには proto3 ファイルの変更前後の例はありません。Editions の動作は proto3 の動作と一致します。
利用可能な値
ALLOW
: ランタイムは JSON のパースとシリアル化を許可する必要があります。JSON への明確なマッピングが存在することを確認するために、proto レベルでチェックが適用されます。LEGACY_BEST_EFFORT
: ランタイムは JSON のパースとシリアル化に最善を尽くします。ランタイムで未指定の動作(多対1または1対多のマッピングなど)を招く可能性がある特定の proto が許可されます。
適用可能なスコープ: ファイル、メッセージ、Enum
Edition 2023 のデフォルトの動作: ALLOW
proto2 の動作: LEGACY_BEST_EFFORT
proto3 の動作: ALLOW
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
message Foo {
// Warning only
string bar = 1;
string bar_ = 2;
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
option features.json_format = LEGACY_BEST_EFFORT;
message Foo {
string bar = 1;
string bar_ = 2;
}
features.message_encoding
この機能は、シリアル化時にフィールドをエンコードする際の動作を設定します。
この機能は proto3 ファイルには影響しないため、このセクションには proto3 ファイルの変更前後の例はありません。
言語によっては、「グループのような」フィールドは、proto2 との後方互換性を提供するために、生成されたコードやテキスト形式で予期しない大文字化が行われる場合があります。メッセージフィールドが「グループのような」であるのは、以下のすべての条件が満たされた場合です。
DELIMITED
メッセージエンコーディングが指定されている- メッセージ型がフィールドと同じスコープで定義されている
- フィールド名が型名の小文字と完全に一致する
利用可能な値
LENGTH_PREFIXED
: フィールドは、メッセージ構造で説明されている LEN ワイヤタイプを使用してエンコードされます。DELIMITED
: メッセージ型フィールドは、グループとしてエンコードされます。
適用可能なスコープ: ファイル、フィールド
Edition 2023 のデフォルトの動作: LENGTH_PREFIXED
proto2 の動作: グループはデフォルトでDELIMITED
ですが、それ以外はLENGTH_PREFIXED
です。
proto3 の動作: LENGTH_PREFIXED
。Proto3 はDELIMITED
をサポートしていません。
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
message Foo {
group Bar = 1 {
optional int32 x = 1;
repeated int32 y = 2;
}
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
message Foo {
message Bar {
int32 x = 1;
repeated int32 y = 2;
}
Bar bar = 1 [features.message_encoding = DELIMITED];
}
features.repeated_field_encoding
この機能は、Editions でrepeated
フィールドの proto2/proto3 のpacked
オプションが移行されたものです。
利用可能な値
PACKED
: プリミティブ型のRepeated
フィールドは、各要素が連結された単一の LEN レコードとしてエンコードされます。EXPANDED
:Repeated
フィールドは、各値に対してフィールド番号とともにそれぞれエンコードされます。
適用可能なスコープ: ファイル、フィールド
Edition 2023 のデフォルトの動作: PACKED
proto2 の動作: EXPANDED
proto3 の動作: PACKED
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
message Foo {
repeated int32 bar = 6 [packed=true];
repeated int32 baz = 7;
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
option features.repeated_field_encoding = EXPANDED;
message Foo {
repeated int32 bar = 6 [features.repeated_field_encoding=PACKED];
repeated int32 baz = 7;
}
以下に proto3 ファイルを示します。
syntax = "proto3";
message Foo {
repeated int32 bar = 6;
repeated int32 baz = 7 [packed=false];
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
message Foo {
repeated int32 bar = 6;
repeated int32 baz = 7 [features.repeated_field_encoding=EXPANDED];
}
features.utf8_validation
この機能は、文字列がどのように検証されるかを設定します。これは、それをオーバーライドする言語固有のutf8_validation
機能がある場合を除き、すべての言語に適用されます。Java 言語固有の機能については、features.(pb.java).utf8_validation
を参照してください。
この機能は proto3 ファイルには影響しないため、このセクションには proto3 ファイルの変更前後の例はありません。
利用可能な値
VERIFY
: ランタイムは UTF-8 を検証する必要があります。これは proto3 のデフォルトの動作です。NONE
: このフィールドは、ワイヤ上で未検証のbytes
フィールドのように動作します。パーサーは、無効な文字を置換するなど、予測できない方法でこの種のフィールドを処理する可能性があります。これは proto2 のデフォルトの動作です。
適用可能なスコープ: ファイル、フィールド
Edition 2023 のデフォルトの動作: VERIFY
proto2 の動作: NONE
proto3 の動作: VERIFY
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
message MyMessage {
string foo = 1;
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
message MyMessage {
string foo = 1 [features.utf8_validation = NONE];
}
言語固有の機能
一部の機能は特定の言語に適用され、他の言語の同じ proto には適用されません。これらの機能を使用するには、その言語のランタイムから対応する *_features.proto ファイルをインポートする必要があります。以下のセクションの例でこれらのインポートを示します。
features.(pb.cpp/pb.java).legacy_closed_enum
言語: C++、Java
この機能は、オープンな enum 型を持つフィールドがクローズド enum のように動作すべきかどうかを決定します。これにより、エディションは proto2 および proto3 からの Java および C++ における非準拠の動作を再現できます。
この機能は proto3 ファイルには影響しないため、このセクションには proto3 ファイルの変更前後の例はありません。
利用可能な値
true
:enum_type
に関わらず、enum をクローズドとして扱います。false
:enum_type
に設定されているものを尊重します。
適用可能なスコープ: ファイル、フィールド
Edition 2023 のデフォルトの動作: false
proto2 の動作: true
proto3 の動作: false
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
import "myproject/proto3file.proto";
message Msg {
myproject.proto3file.Proto3Enum name = 1;
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
import "myproject/proto3file.proto";
import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";
message Msg {
myproject.proto3file.Proto3Enum name = 1 [
features.(pb.cpp).legacy_closed_enum = true,
features.(pb.java).legacy_closed_enum = true
];
}
features.(pb.cpp).string_type
言語: C++
この機能は、生成されたコードが文字列フィールドをどのように扱うべきかを決定します。これは proto2 および proto3 のctype
オプションを置き換え、新しいstring_view
機能を提供します。Edition 2023 では、フィールドでctype
またはstring_type
のいずれかを指定できますが、両方を指定することはできません。
利用可能な値
VIEW
: フィールドのstring_view
アクセサを生成します。これは将来のエディションでデフォルトになります。CORD
: フィールドのCord
アクセサを生成します。STRING
: フィールドのstring
アクセサを生成します。
適用可能なスコープ: ファイル、フィールド
Edition 2023 のデフォルトの動作: STRING
proto2 の動作: STRING
proto3 の動作: STRING
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
message Foo {
optional string bar = 6;
optional string baz = 7 [ctype = CORD];
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
import "google/protobuf/cpp_features.proto";
message Foo {
string bar = 6;
string baz = 7 [features.(pb.cpp).string_type = CORD];
}
以下に proto3 ファイルを示します。
syntax = "proto3"
message Foo {
string bar = 6;
string baz = 7 [ctype = CORD];
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
import "google/protobuf/cpp_features.proto";
message Foo {
string bar = 6;
string baz = 7 [features.(pb.cpp).string_type = CORD];
}
features.(pb.java).utf8_validation
言語: Java
この言語固有の機能により、Java のフィールドレベルでのファイルレベル設定をオーバーライドできます。
この機能は proto3 ファイルには影響しないため、このセクションには proto3 ファイルの変更前後の例はありません。
利用可能な値
DEFAULT
: 動作はfeatures.utf8_validation
で設定されたものと一致します。VERIFY
: ファイルレベルのfeatures.utf8_validation
設定をオーバーライドし、Java のみVERIFY
を強制します。
適用可能なスコープ: フィールド、ファイル
Edition 2023 のデフォルトの動作: DEFAULT
proto2 の動作: DEFAULT
proto3 の動作: DEFAULT
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
以下のコードサンプルは proto2 ファイルを示しています
syntax = "proto2";
option java_string_check_utf8=true;
message MyMessage {
string foo = 1;
string bar = 2;
}
Prototiller を実行した後、同等のコードは次のようになります。
edition = "2023";
import "google/protobuf/java_features.proto";
option features.utf8_validation = NONE;
option features.(pb.java).utf8_validation = VERIFY;
message MyMessage {
string foo = 1;
string bar = 2;
}
features.(pb.java).large_enum
言語: Java
この言語固有の機能により、コンパイラエラーを引き起こすことなく、Java で大規模な enum を処理する新しい機能を採用できます。
これは新しい動作であるため、proto2 または proto3 のスキーマ定義ファイルには影響しません。
利用可能な値
true
: Java の enum は新しい機能を使用します。false
: Java の enum は引き続き Java の enum を使用します。
適用可能なスコープ: Enum
Edition 2023 のデフォルトの動作: false
proto2 の動作: false
proto3 の動作: false
注: 異なるスキーマ要素の機能設定は異なるスコープを持ちます。
proto2 または proto3 の動作の保持
エディション形式に移行したいが、生成コードの動作方法の更新にはまだ対応したくない場合があります。このセクションでは、Edition 2023 の proto が proto2 または proto3 ファイルのように動作するように、Prototiller ツールが .proto ファイルに行う変更を示します。
これらの変更がファイルレベルで行われると、proto2 または proto3 のデフォルトが適用されます。より低いレベル(メッセージレベル、フィールドレベル)でオーバーライドして、追加の動作の違い(必須、proto3 の optionalなど)を考慮したり、定義をほとんど proto2 または proto3 のようにしたい場合に適用できます。
Prototiller を使用しない特定の理由がない限り、Prototiller の使用をお勧めします。Prototiller を使用せずにこれらすべてを手動で適用するには、以下のセクションのコンテンツを .proto ファイルの先頭に追加してください。
Proto2 の動作
edition = "2023";
import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";
option features.field_presence = EXPLICIT;
option features.enum_type = CLOSED;
option features.repeated_field_encoding = EXPANDED;
option features.json_format = LEGACY_BEST_EFFORT;
option features.utf8_validation = NONE;
option features.(pb.cpp).legacy_closed_enum = true;
option features.(pb.java).legacy_closed_enum = true;
Proto3 の動作
// proto3 behaviors
edition = "2023";
import "google/protobuf/cpp_features.proto";
import "google/protobuf/java_features.proto";
option features.field_presence = IMPLICIT;
option features.enum_type = OPEN;
// `packed=false` needs to be transformed to field-level repeated_field_encoding
// features in Editions syntax
option features.json_format = ALLOW;
option features.utf8_validation = VERIFY;
option features.(pb.cpp).legacy_closed_enum = false;
option features.(pb.java).legacy_closed_enum = false;
注意点と例外
このセクションでは、Prototiller を使用しない場合に手動で行う必要がある変更を示します。
前のセクションで示したファイルレベルのデフォルトを設定すると、ほとんどの場合でデフォルトの動作が設定されますが、いくつかの例外があります。
optional
:optional
ラベルのすべてのインスタンスを削除し、ファイルデフォルトがIMPLICIT
の場合は、features.field_presence
をEXPLICIT
に変更します。required
:required
ラベルのすべてのインスタンスを削除し、フィールドレベルでfeatures.field_presence=LEGACY_REQUIRED
オプションを追加します。groups
:groups
を個別のメッセージに展開し、フィールドレベルでfeatures.message_encoding = DELIMITED
オプションを追加します。詳細については、features.message_encoding
を参照してください。java_string_check_utf8
: このファイルオプションを削除し、features.(pb.java).utf8_validation
に置き換えます。言語固有の機能で説明されているように、Java の機能をインポートする必要があります。packed
: エディション形式に変換された proto2 ファイルの場合、Proto2 の動作で設定したEXPANDED
の動作が不要な場合は、packed
フィールドオプションを削除し、フィールドレベルで[features.repeated_field_encoding=PACKED]
を追加します。エディション形式に変換された proto3 ファイルの場合、デフォルトの proto3 の動作が不要な場合は、フィールドレベルで[features.repeated_field_encoding=EXPANDED]
を追加します。