機能エディションの設定

Protobuf エディションの機能と、それらが protobuf の動作にどのように影響するか。

このトピックでは、Edition 2023 に含まれる機能の概要を説明します。以降のエディションの機能はすべてこのトピックに追加されます。新しいエディションについては、ニュースセクションでお知らせします。

新しいスキーマ定義コンテンツで機能設定を構成する前に、それらを使用する理由を理解していることを確認してください。機能の思考停止は避けてください。

Prototiller

Prototiller は、proto2 および proto3 定義ファイルを Editions 構文に変換するコマンドラインツールです。まだリリースされていませんが、このトピック全体で参照されています。

機能

以下のセクションでは、Edition 2023 の機能を使用して設定可能なすべての動作について説明します。proto2 または proto3 の動作の維持では、proto 定義ファイルが proto2 または proto3 ファイルのように動作するように、デフォルトの動作をオーバーライドする方法を示します。エディションと機能が連携して動作を設定する方法の詳細については、Protobuf エディションの概要を参照してください。

以下の各セクションには、機能が適用されるスコープのエントリがあります。これには、ファイル、enum、メッセージ、またはフィールドが含まれます。次のサンプルは、各スコープに適用されるモック機能を示しています。

edition = "2023";

// File-scope definition
option features.bar = BAZ;

enum Foo {
  // Enum-scope definition
  option features.bar = QUX;

  A = 1;
  B = 2;
}

message Corge {
  // Message-scope definition
  option features.bar = QUUX;

  // Field-scope definition
  Foo A = 1 [features.bar = GRAULT];
}

この例では、フィールドスコープ機能定義の GRAULT 設定は、メッセージスコープの QUUX 設定をオーバーライドします。

features.enum_type

この機能は、定義されたセットに含まれていない enum 値の処理方法の動作を設定します。オープン 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 {
  option features.enum_type = CLOSED;
  A = 2;
  B = 4;
  C = 6;
}

features.field_presence

この機能は、フィールドの存在、つまり protobuf フィールドに値があるかどうかの概念を追跡する動作を設定します。

利用可能な値

  • LEGACY_REQUIRED: フィールドは、解析およびシリアライゼーションに必須です。明示的に設定された値はすべて、(デフォルト値と同じであっても) ワイヤにシリアライズされます。
  • EXPLICIT: フィールドには明示的な存在追跡があります。明示的に設定された値はすべて、(デフォルト値と同じであっても) ワイヤにシリアライズされます。単数プリミティブフィールドの場合、has_* 関数は EXPLICIT に設定されたフィールドに対して生成されます。
  • IMPLICIT: フィールドには存在追跡がありません。デフォルト値は、(明示的に設定されていても) ワイヤにシリアライズされません。has_* 関数は、IMPLICIT に設定されたフィールドに対して生成されません。

適用可能なスコープ: ファイル、フィールド

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 {
  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";
option features.field_presence = IMPLICIT;

message Bar {
  int32 x = 1;
  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 の解析とシリアライゼーションを最大限に実行します。特定の proto は、ランタイムで未指定の動作 (多対 1 または 1 対多のマッピングなど) を引き起こす可能性のあるものが許可されています。

適用可能なスコープ: ファイル、メッセージ、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";
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 での動作: グループを除き LENGTH_PREFIXED。グループはデフォルトで DELIMITED

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

この機能は、proto2/proto3 の packed オプションが Editions に移行されたものです。

利用可能な値

  • 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;
}

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 の動作の維持

エディション形式に移行したいが、生成されたコードの動作方法の更新に対処したくない場合があります。このセクションでは、Prototiller ツールが .proto ファイルに加えて、Edition 2023 proto を proto2 または proto3 ファイルのように動作させる変更を示します。

これらの変更がファイルレベルで行われると、proto2 または proto3 のデフォルトが取得されます。下位レベル (メッセージレベル、フィールドレベル) でオーバーライドして、追加の動作の違い (required、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_presenceEXPLICIT に変更します。
  • 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 ファイルの場合、packed フィールドオプションを削除し、Proto2 の動作で設定した EXPANDED 動作が必要ない場合は、フィールドレベルで [features.repeated_field_encoding=PACKED] を追加します。エディション形式に変換された proto3 ファイルの場合、デフォルトの proto3 動作が必要ない場合は、フィールドレベルで [features.repeated_field_encoding=EXPANDED] を追加します。