Java Generated Code

1.   The protocol buffer compiler produces Java output when invoked with the --java_out command-line flag. It creates a single .java for each .proto file input. This file contains a single outer class definition containing several nested classes and static fields based on the declarations in the .proto file.

 

 

2.   The outer class's name is chosen as follows: If the .proto file contains a java_outer_classname option, then the outer class name will be the value of the option. Otherwise, the outer class name is determined by converting the .proto file base name to camel case. For example, foo_bar.proto will become FooBar .

 

3.  Each message defined in the .proto file will be compiled to a static inner class of the outer class for that .proto file. You should not define a message with same name as the outer class.

 

4.   The protocol buffer compiler generates a static inner class for each message which implements the Message interface. The class is declared final; no further subclassing is allowed. It extends GeneratedMessage . By default, the generated class overrides many methods of GeneratedMessage with specialized versions for maximum speed. If you use “optimize_for = CODE_SIZE; ” option, the generated class will override only the minimum set of methods necessary to function and rely on GeneratedMessage 's reflection-based implementations of the rest. If you use “optimize_for = LITE_RUNTIME; ” option, the generated class will include fast implementations of all methods, but will implement the MessageLite interface, which only contains a subset of the methods of Message . In particular, it does not support descriptors or reflection. In this mode, the generated code only needs to link against libprotobuf-lite.jar instead of libprotobuf.jar .

 

5.   Message objects are immutable. To construct a message object, you need to use a builder. Each message class has its own builder class. The protocol buffer compiler generates a nested class Foo.Builder (suppose message name is “Foo ”) which can be used to build a Foo . Foo.Builder implements the Message.Builder interface. It extends the GeneratedMessage.Builder class. Methods that modify the contents of a builder – including field setters – always return a reference to the builder. This allows multiple method calls to be chained together in one line. The build() method of the Builder can generate the message instance.

 

6.   The protocol buffer compiler generates a set of accessor methods for each field defined within the message in the .proto file. The methods that read the field value are defined both in the message class and its corresponding builder; the methods that modify the value are only defined in the builder only.

 

7.   As well as accessor methods, the compiler generates an integer constant for each field containing its field number. The constant name is the field name converted to upper-case followed by _FIELD_NUMBER . For example, given the field optional int32 foo_bar = 5; the compiler will generate the constant public static final int FOO_BAR_FIELD_NUMBER = 5; .

 

8.   For either of these field definitions:

optional int32 foo = 1;

required int32 foo = 1; 
 

The compiler will generate the following accessor methods in both the message class and its builder:

a)   bool hasFoo() : Returns true if the field is set.

b)  int getFoo() : Returns the current value of the field. If the field is not set, returns the default value.

The compiler will generate the following methods only in the message's builder:

a)   Builder setFoo(int value) : Sets the value of the field. After calling this, hasFoo() will return true and getFoo() will return value.

b)   Builder clearFoo() : Clears the value of the field. After calling this, hasFoo() will return false and getFoo() will return the default value.

If the attribute type is a message instead of int , setFoo() also accepts an instance of the message's builder type as the parameter. This is just a shortcut which is equivalent to calling .build() on the builder and passing the result to the method.

 

9.   For this field definition:

repeated int32 foo = 1;
 

  The compiler will generate the following accessor methods in both the message class and its builder:

 

a)   int getFooCount() : Returns the number of elements currently in the field.

b)  i nt getFoo(int index) : Returns the element at the given zero-based index.

c)   List<Integer> getFooList() : Returns the entire field as an immutable list.

The compiler will generate the following methods only in the message's builder:

a)   Builder setFoo(int index, int value) : Sets the value of the element at the given zero-based index.

b)   Builder addFoo(int value) : Appends a new element to the field with the given value.

c)   Builder addAllFoo(List<Integer> value) : Appends all elements in the given list to the field.

d)  Builder clearFoo() : Removes all elements from the field. After calling this, getFooCount() will return zero.

If the attribute type is a message instead of int , setFoo() and addFoo() also accept an instance of the message's builder type as the parameter. This is just a shortcut which is equivalent to calling .build() on the builder and passing the result to the method.

 

10.   Given an enum definition like:

enum Foo {

  VALUE_A = 1;

  VALUE_B = 5;

  VALUE_C = 1234;

}
 

The protocol buffer compiler will generate a Java enum type called Foo with the same set of values and the following special methods:

 

a)   int getNumber() : Returns the object's numeric value as defined in the .proto file.

b)   EnumValueDescriptor getValueDescriptor() : Returns the value's descriptor, which contains information about the value's name, number, and type.

c)   EnumDescriptor getDescriptorForType() : Returns the enum type's descriptor, which contains e.g. information about each defined value.

Additionally, the Foo enum type contains the following static methods:

a)   static Foo valueOf(int value) : Returns the enum object corresponding to the given numeric value.

b)   static Foo valueOf(EnumValueDescriptor descriptor) : Returns the enum object corresponding to the given value descriptor. May be faster than valueOf(int) .

c)   EnumDescriptor getDescriptor() : Returns the enum type's descriptor, which contains e.g. information about each defined value. (This differs from getDescriptorForType() only in that it is a static method.)

An integer constant is also generated with the suffix _VALUE for each enum value.

 

11.   .proto language allows multiple enum symbols to have the same numeric value:

enum Foo {

  BAR = 1;

  BAZ = 1;

}
 

In this case, BAZ is a synonym for BAR . In Java, BAZ will be defined as a static final field like so:

 

static final Foo BAZ = BAR;
 

 

Thus, BAR and BAZ compare equal, and BAZ should never appear in switch statements. The compiler always chooses the first symbol defined with a given numeric value to be the "canonical" version of that symbol; all subsequent symbols with the same number are just aliases.

 

12.   For messages containing sub-messages, the compiler also generates sub builders. For the following message definition :

message Foo {

  optional int32 val = 1;

  // some other fields.

}

 

message Bar {

  optional Foo foo = 1;

  // some other fields.

}

 

message Baz {

  optional Bar bar = 1;

  // some other fields.

}
 

If you have a Baz message already, Instead of:

 

 

baz = baz.toBuilder().setBar(

      baz.getBar().toBuilder().setFoo(

          baz.getBar().getFoo().toBuilder().setVal(10).build()

      ).build()).build(); 
 

 

You can write:

 

Baz.Builder builder = baz.toBuilder();

  builder.getBarBuilder().getFooBuilder().setVal(10);

  baz = builder.build(); 
 

 

 

   

13.   In addition to the Message interface, the generated class (suppose its name is Foo ) defines the following static methods:

a)   static Foo getDefaultInstance() : Returns a singleton instance of Foo , which is identical to what you'd get if you called Foo.newBuilder().build() (so all singular fields are unset and all repeated fields are empty). Note that the default instance of a message can be used as a factory by calling its newBuilderForType() method.

b)   static Descriptor getDescriptor() : Returns the type's descriptor. This contains information about the type, including what fields it has and what their types are. This can be used with the reflection methods of the Message , such as getField() .

c)   static Foo parseFrom(...) : Parses a message of type Foo from the given source and returns it. There is one parseFrom method corresponding to each variant of mergeFrom() in the Message.Builder interface. Note that parseFrom() never throws UninitializedMessageException ; it throws InvalidProtocolBufferException if the parsed message is missing required fields. This makes it subtly different from calling Foo.newBuilder().mergeFrom(...).build() .

d)   Foo.Builder newBuilder() : Creates a new builder.

e)   Foo.Builder newBuilder(Foo prototype) : Creates a new builder with all fields initialized to the same values that they have in prototype. Since embedded message and string objects are immutable, they are shared between the original and the copy.

 

14.   Given a message with an extension range:

message Foo {

  extensions 100 to 199;

}
 

The protocol buffer compiler will make Foo extend GeneratedMessage.ExtendableMessage instead of the usual GeneratedMessage . Similarly, Foo 's builder will extend GeneratedMessage.ExtendableBuilder . You should never refer to these base types by name (GeneratedMessage is considered an implementation detail). Foo and Foo.Builder will inherit the methods hasExtension() , getExtension() , and getExtensionCount() . Additionally, Foo.Builder will inherit methods setExtension() and clearExtension() . Each of these methods takes, as its first parameter, an extension identifier, which identifies an extension field. The remaining parameters and the return value are exactly the same as those for the corresponding accessor methods that would be generated for a normal (non-extension) field of the same type as the extension identifier.

 

Given an extension definition:

extend Foo {

  optional int32 bar = 123;

}
 

The protocol buffer compiler generates an "extension identifier" called bar as a static field of the outer class for the .proto file, which you can use to access this extension:

Foo foo =  Foo.newBuilder().setExtension(bar, 1) .build();
assert foo.hasExtension(bar);
assert foo.getExtension(bar) == 1;
 

 

When parsing a message that might have extensions, you must provide an ExtensionRegistry in which you have registered any extensions that you want to be able to parse. Otherwise, those extensions will just be treated like unknown fields:

ExtensionRegistry registry = ExtensionRegistry.newInstance();
  registry.add(bar);
  Foo foo = Foo.parseFrom(input, registry);
 

 


 

15.   Given a service definition:

service Foo {

  rpc Bar(FooRequest) returns(FooResponse);

}
 

The protocol buffer compiler will generate an abstract class Foo to represent this service. Foo will have an abstract method for each method defined in the service definition. In this case, the method Bar is defined as:

 

abstract void bar(RpcController controller, FooRequest request,
                  RpcCallback <FooResponse> done);
 

 

The parameters are equivalent to the parameters of Service.CallMethod() , except that the method argument is implied and request and done specify their exact type.

Foo subclasses the Service interface. The protocol buffer compiler automatically generates implementations of the methods of Service as follows:

a)   getDescriptorForType : Returns the service's ServiceDescriptor .

b)   callMethod : Determines which method is being called based on the provided method descriptor and calls it directly, down-casting the request message and callback to the correct types.

c)   getRequestPrototype and getResponsePrototype : Returns the default instance of the request or response of the correct type for the given method.

The following static method is also generated:

a)   static ServiceDescriptor getDescriptor() : Returns the type's descriptor, which contains information about what methods this service has and what their input and output types are.

Foo will also contain a nested interface Foo.Interface . This is a pure interface that again contains methods corresponding to each method in your service definition. However, this interface does not extend the Service interface. This is a problem because RPC server implementations are usually written to use abstract Service objects, not your particular service. To solve this problem, if you have an object impl implementing Foo .Interface, you can call Foo.newReflectiveService(impl) to construct an instance of Foo that simply delegates to impl , and implements Service .

To recap, when implementing your own service, you have two options:

a)   Subclass Foo and implement its methods as appropriate, then hand instances of your subclass directly to the RPC server implementation. This is usually easiest, but some consider it less "pure".

b)   Implement Foo.Interface and use Foo.newReflectiveService(Foo.Interface) to construct a Service wrapping it, then pass the wrapper to your RPC implementation.

 

16.   The protocol buffer compiler also generates a "stub" implementation of every service interface, which is used by clients wishing to send requests to servers implementing the service. For the Foo service (above), the stub implementation Foo.Stub will be defined as a nested class.

Foo.Stub is a subclass of Foo which also implements the following methods:

a)   Foo.Stub(RpcChannel channel) : Constructs a new stub which sends requests on the given channel.

b)   RpcChannel getChannel() : Returns this stub's channel, as passed to the constructor.

The stub additionally implements each of the service's methods as a wrapper around the channel. Calling one of the methods simply calls channel.callMethod() .

 

17.   The Protocol Buffer library does not include an RPC implementation. However, it includes all of the tools you need to hook up a generated service class to any arbitrary RPC implementation of your choice. You need only provide implementations of RpcChannel and RpcController .

 

18.   The RPC classes all have non-blocking semantics: when you call a method, you provide a callback object which will be invoked once the method completes. The protocol buffer compiler also generates blocking versions of your service class. Foo.BlockingInterface is equivalent to Foo.Interface except that each method simply returns the result rather than call a callback. So, for example, bar is defined as:

abstract FooResponse bar(RpcControllercontroller, FooRequest request)
                         throws ServiceException ;
 

 

Analogous to non-blocking services, Foo.newReflectiveBlockingService(Foo.BlockingInterface) returns a BlockingService wrapping some Foo.BlockingInterface . Finally, Foo.BlockingStub returns a stub implementation of Foo.BlockingInterface that sends requests to a particular BlockingRpcChannel .

你可能感兴趣的:(java)