The original address: developers.google.com/protocol-bu…

Original author:

Release Date:

This page describes the Dart code generated by the protocol buffer compiler for any given protocol definition. Any differences between proto2 and Proto3 generated code are highlighted – please note that these differences are in the generated code described in this document, not in the underlying API, the code for both versions is the same. You should read the Proto2 language guide and/or the Proto3 language Guide before reading this document.

Compiler call

The protocol buffer compiler requires a plug-in to generate the Dart code. Installing it as instructed will provide a protoc-gen-dart binary that protoc uses when called with the –dart_out command line flag. The dart_OUT flag tells the compiler where to write the Dart source file. For input to a.proto file, the compiler produces a.bb.dart file.

The.pb.dart file name is calculated by making two changes to the.proto file name.

  • The extension (.proto) is replaced with.pb.dart. For example, a file named foo.proto produces an output file named foo.bb.dart.
  • The proto path (specified with the –proto_path or -i command line flag) is replaced with the output path (specified with the — dart_OUT flag).

For example, when you call the compiler below.

protoc --proto_path=src --dart_out=build/gen src/foo.proto src/bar/baz.proto
Copy the code

The compiler will read the files SRC /foo.proto and SRC /bar/baz.proto. It produces: build/gen/foo bb. The dart and build/gen/bar/baz bb. Dart. The compiler automatically creates the Build /gen/bar directory if needed, but it does not create build or Build /gen, which must already exist.

The message

Give a simple message declaration.

message Foo {}
Copy the code

The protocol buffer compiler generates a class named Foo that extends the class GeneratedMessage.

The GeneratedMessage class defines methods that let you examine, manipulate, read, or write the entire message. In addition to these methods, the Foo class defines the following methods and constructors.

  • Foo(): default constructor. Create an instance where all singular fields are unset and duplicate fields are empty.
  • Foo.fromBuffer(…) : default constructor. Creates a Foo from the serialization protocol buffer data that represents the message.
  • Foo.fromJson(…) : Creates a Foo from the serialization protocol buffer data representing the message. Create a Foo from the JSON string to encode the message.
  • Foo.clone() : Creates a Foo from the JSON string encoding the message. Create a deep clone of the fields in the message.
  • Foo copyWith(void Function(Foo) updates). Create a writable copy of the message, update it, and mark the copy as read-only before returning.
  • The static Foo the create (). A factory function to create a single Foo.
  • static PbList<Foo> createRepeated(). A factory function that creates a List that implements a variable repetition field for the Foo element.
  • The static Foo getDefault (). Returns a singleton instance of Foo that is exactly the same as a newly constructed instance of Foo (so all singular fields are unset and all duplicate fields are empty).

Nested types

A message can be declared in another message. For example,

message Foo {
  message Bar {}}Copy the code

In this case, the compiler generates two classes. Foo and Foo_Bar.

field

In addition to the methods described in the previous section, the protocol buffer compiler generates accessor methods for each field defined in the message in the.proto file.

Note that the generated names are always named in camel capitals, even though the field names in the.proto file are lowercase with an underscore (as it should be). The case conversion process is as follows.

  • For each underscore in the name, the underscore is removed and the following letter is capitalized.
  • If the name is appended with a prefix (such as” has”), the first letter is capitalized. Otherwise, it is lowercase.

Therefore, for the field foo_bar_baz, the getter becomes get fooBarBaz, and the method prefixed with has will be hasFooBarBaz.

Single primitive field (Proto2

For any of these field definitions.

optional int32 foo = 1;
required int32 foo = 1;
Copy the code

The compiler generates the following access methods in the message class.

  • Int get foo: Returns the current value of the field. If this field is not set, the default value is returned.
  • Bool hasFoo() : Returns the current value of this field. Returns true if the field is set.
  • Set foo(int value): Sets the value of the field. After calling this function, hasFoo() returns true and get foo returns value.
  • Void clearFoo() : Clears the field value. Clears the value of the field. After calling this function, hasFoo() will return false and get foo will return the default.

For other simple field types, select the appropriate Dart type from the table of scalar value types. For message and enumeration types, message or enumeration classes are used instead of value types.

Single primitive field (Proto3)

The definition of this field.

int32 foo = 1;
Copy the code

The compiler generates the following access methods in the message class.

  • Int get foo: Returns the current value of the field. If this field is not set, the default value is returned.
  • Set foo(int value) : Sets the value of the field. Sets the value of the field. When this function is called, get Foo returns the value.
  • Void clearFoo (). Clears the value of the field. When this function is called, get Foo returns the default value.

Single message field

Given message type.

message Bar {}
Copy the code

For a message with a Bar field.

// 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;
}
Copy the code

The compiler generates the following accessor methods in the message class.

  • Bar get Bar: Returns the current value of the field. If this field is not set, the default value is returned.
  • Set bar(bar value) : Sets the value of a field. Sets the value of this field. After calling this function, hasBar() returns true and get bar returns the value.
  • Bool hasBar() : Sets the field value. Returns true if the field is set.
  • Void clearBar() : Clears the field value. Clears the value of the field. After calling this function, hasBar() returns false and get bar returns the default.
  • Bar ensureBar() : Sets Bar to an empty instance. If hasBar() returns false, set bar to an empty instance and return the value of bar. After this function is called, hasBar() returns true.

Duplicate field

The definition of this field.

repeated int32 foo = 1;
Copy the code

The compiler will generate

  • List<int> get foo: Returns the list of supported fields. If this field is not set, an empty list is returned. Changes to the list are reflected in the fields.

Int64 field

The definition of this field.

// proto2
optional int64 bar = 1;

// proto3
int64 bar = 1;
Copy the code

The compiler generates:

  • Int64 get bar: Returns an Int64 object containing the value of the field.

Note that Int64 is not built into the Dart core library. To use these objects, you may need to import the Dart Fixnum library.

import 'package:fixnum/fixnum.dart';
Copy the code

Map field

Give such a map field definition.

map<int32.int32> map_field = 1;
Copy the code

The compiler generates the following getter.

  • Map

    get mapField: Dart Map that supports this field is returned. If this field is not set, an empty space map is returned. Changes to the map are reflected in the field.
    ,>

any

Given an Any field like this.

import "google/protobuf/any.proto";

message ErrorStatus {
  string message = 1;
  google.protobuf.Any details = 2;
}
Copy the code

In our generated code, the getter for the detail field returns a com.google.protobuf.any. The instance. This provides the following special methods for packaging and unpacking values of 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'});
Copy the code

One of the

Give such a definition of oneof.

message Foo {
  oneof test {
    string name = 1;
    SubMessage sub_message = 2; }}Copy the code

The compiler generates the following Dart enumeration types.

 enum Foo_Test { name, subMessage, notSet }
Copy the code

In addition, it generates these methods.

  • Foo_Test whichTest(): Returns an enumeration that shows which field is set. If none is set, foo_test.notset is returned.
  • Void clearTest(). If notSet, return foo_test.notset. Clears the value of the currently set oneof field, if any, and sets the oneof case to foo_test.notSet.

For each field in the Oneof definition, regular field access methods are generated. For example, for name:

  • String get name: Returns the current value of this field if oneof is foo_test. name. Otherwise, the default value is returned.
  • The set name (String value). Set the value of the field and set oneof case to foo_test.name. After calling this function, get name returns value, whichTest() returns foo_test.name.
  • Void clearName (). If oneof case is not foo_test.name, nothing changes. Otherwise, clear the value of the field. After calling this function, get name returns the default value, whichTest() returns foo_test.notset.

The enumeration

Given an enumeration definition, such as

enum Color {
  RED = 0;
  GREEN = 1;
  BLUE = 2;
}
Copy the code

The protocol buffer compiler will generate a class named Color that extends the ProtobufEnum class. This class defines a static Const Color for each of the three values defined, and a static List
containing all three values. It will also contain the following methods.

  • Static Color valueOf(int value): Returns the Color of the given value.

Each value has the following properties.

  • Name: The name of the enumeration, specified in the.proto file.
  • Value: enum Integer value, specified in the. Proto file.

Note that the.proto language allows multiple enumeration symbols to have the same value. Symbols with the same value are synonyms. For example,

enum Foo {
  BAR = 0;
  BAZ = 0;
}
Copy the code

In this case, BAZ is a synonym for BAR and will be defined as such.

static const Foo BAZ = BAR;
Copy the code

An enumeration can be defined within a message type. For example, given an enumeration definition, such as

message Bar {
  enum Color {
    RED = 0;
    GREEN = 1;
    BLUE = 2; }}Copy the code

The protocol buffer compiler will generate a class named Bar that extends GeneratedMessage, and a class named Bar_Color that extends ProtobufEnum.

Extension (Proto2 only)

Given a file named foo_test.proto, include a message with an extended scope and a top-level extension definition.

message Foo {
  extensions 100 to 199;
}

extend Foo {
  optional int32 bar = 101;
}
Copy the code

In addition to the Foo class, the protocol buffer compiler will generate a Foo_test class that will contain the static Extension name for each Extension field in the file and a method to register all extensions in ExtensionRegistry.

  • static final Extension bar
  • Static void registerAllExtensions(ExtensionRegistry registry) : to registerAllExtensions defined in a given registry.

Foo’s extended accessor can be used as follows.

Foo foo = Foo();
foo.setExtension(Foo_test.bar, 1);
assert(foo.hasExtension(Foo_test.bar));
assert(foo.getExtension(Foo_test.bar)) == 1);
Copy the code

Extensions can also declare nesting in another message.

message Baz {
  extend Foo {
    optional int32 bar = 124; }}Copy the code

In this case, the extension bar is declared as a static member of the Baz class.

When parsing a message that may have an extension, you must provide an ExtensionRegistry, in which you must register any extension you wish to be able to resolve. Otherwise, these extensions are treated as unknown fields. For example,

ExtensionRegistry registry = ExtensionRegistry.EMPTY;
registry.add(Baz.bar);
Foo foo = Foo.fromBuffer(input, registry);
Copy the code

If you already have a parsed message that contains an unknown field, you can use reparseMessage on an ExtensionRegistry to parse the message. If the unknown field set contains extensions that exist in the registry, these extension names are resolved and removed from the unknown field set. The extension name that already exists in the message is preserved.

Foo foo = Foo.fromBuffer(input);
ExtensionRegistry registry = ExtensionRegistry.EMPTY;
registry.add(Baz.bar);
Foo reparsed = registry.reparseMessage(foo);
Copy the code

Keep in mind that this method of retrieving extensions is generally expensive. Where possible, we suggest that in GeneratedMessage. FromBuffer, with all the required extension ExtensionRegistry.

service

Given a service definition.

service Foo {
  rpc Bar(FooRequest) returns(FooResponse);
}
Copy the code

The protocol buffer compiler can be called with the “GRPC” option (for example –dart_out= GRPC :output_folder), in which case it will generate grPC-enabled code. See the gRPC Dart Quick Start Guide for more details.


www.deepl.com translation