Java Generated Code Guide

Describes exactly what Java code the Protobuf compiler generates for any given protocol definition.

Any differences between proto2, proto3, and Editions generated code are highlighted—note that these differences are in the generated code as described in this document, not the base message classes/interfaces, which are the same in all versions. You should read the proto2 language guide, proto3 language guide, and/or Editions language guide before reading this document.

Note that no Java Protobuf methods accept or return nulls unless otherwise specified.

Compiler Invocation

The Protobuf compiler produces Java output when invoked with the --java_out= command-line flag. The parameter to the --java_out= option is the directory where you want the compiler to write your Java output. For each .proto file input, the compiler creates a wrapper .java file containing a Java class that represents the .proto file itself.

If the .proto file contains a line like the following:

option java_multiple_files = true;

Then the compiler will also create separate .java files for each of the classes/enums which it will generate for each top-level message, enumeration, and service declared in the .proto file.

Otherwise (when the java_multiple_files option is disabled, which is the default), the aforementioned wrapper class will also be used as an outer class, and the generated classes/enums for each top-level message, enumeration, and service declared in the .proto file will all be nested within the outer wrapper class. Thus the compiler will only generate a single .java file for the entire .proto file, and it will have an extra layer in the package

The wrapper class’s name is chosen as follows: If the .proto file contains a line like the following:

option java_outer_classname = "Foo";

Then the wrapper class name will be Foo. Otherwise, the wrapper class name is determined by converting the .proto file base name to camel case. For example, foo_bar.proto will generate a class name of FooBar. If there’s a service, enum, or message (including nested types) in the file with the same name, “OuterClass” will be appended to the wrapper class’s name. Examples:

  • If foo_bar.proto contains a message called FooBar, the wrapper class will generate a class name of FooBarOuterClass.
  • If foo_bar.proto contains a service called FooService, and java_outer_classname is also set to the string FooService, then the wrapper class will generate a class name of FooServiceOuterClass.

In addition to any nested classes, the wrapper class itself will have the following API (assuming the wrapper class is named Foo and was generated from foo.proto):

public final class Foo {
  private Foo() {}  // Not instantiable.

  /** Returns a FileDescriptor message describing the contents of {@code foo.proto}. */
  public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor();
  /** Adds all extensions defined in {@code foo.proto} to the given registry. */
  public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry);
  public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry);

  // (Nested classes omitted)
}

The Java package name is chosen as described under Packages, below.

The output file is chosen by concatenating the parameter to --java_out=, the package name (with .s replaced with /s), and the .java file name.

So, for example, let’s say you invoke the compiler as follows:

protoc --proto_path=src --java_out=build/gen src/foo.proto

If foo.proto’s Java package is com.example and it doesn’t enable java_multiple_files and its outer classname is FooProtos, then the Protobuf compiler will generate the file build/gen/com/example/FooProtos.java. The Protobuf compiler will automatically create the build/gen/com and build/gen/com/example directories if needed. However, it will not create build/gen or build; they must already exist. You can specify multiple .proto files in a single invocation; all output files will be generated at once.

When outputting Java code, the Protobuf compiler’s ability to output directly to JAR archives is particularly convenient, as many Java tools are able to read source code directly from JAR files. To output to a JAR file, simply provide an output location ending in .jar. Note that only the Java source code is placed in the archive; you must still compile it separately to produce Java class files.

Packages

The generated class is placed in a Java package based on the java_package option. If the option is omitted, the package declaration is used instead.

For example, if the .proto file contains:

package foo.bar;

Then the resulting Java class will be placed in Java package foo.bar. However, if the .proto file also contains a java_package option, like so:

package foo.bar;
option java_package = "com.example.foo.bar";

Then the class is placed in the com.example.foo.bar package instead. The java_package option is provided because normal .proto package declarations are not expected to start with a backwards domain name.

Messages

If you are designing a new Protobuf schema, see the recommendations for Java proto names.

Given a simple message declaration:

message Foo {}

The Protobuf compiler generates a class called Foo, which implements the Message interface. The class is declared final; no further subclassing is allowed. Foo extends GeneratedMessage, but this should be considered an implementation detail. By default, Foo overrides many methods of GeneratedMessage with specialized versions for maximum speed. However, if the .proto file contains the line:

option optimize_for = CODE_SIZE;

then Foo will override only the minimum set of methods necessary to function and rely on GeneratedMessage’s reflection-based implementations of the rest. This significantly reduces the size of the generated code, but also reduces performance. Alternatively, if the .proto file contains:

option optimize_for = LITE_RUNTIME;

then Foo will include fast implementations of all methods, but will implement the MessageLite interface, which contains a subset of the methods of Message. In particular, it does not support descriptors, nested builders, or reflection. However, in this mode, the generated code only needs to link against libprotobuf-lite.jar instead of libprotobuf.jar. The “lite” library is much smaller than the full library, and is more appropriate for resource-constrained systems such as mobile phones.

The Message interface defines methods that let you check, manipulate, read, or write the entire message. In addition to these methods, the Foo class defines the following static methods:

  • static Foo getDefaultInstance(): Returns the singleton instance of Foo. This instance’s contents are 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.
  • 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().
  • 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().
  • static Parser parser(): Returns an instance of the Parser, which implements various parseFrom() methods.
  • Foo.Builder newBuilder(): Creates a new builder (described below).
  • 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.

Builders

Message objects—such as instances of the Foo class described above—are immutable, just like a Java String. To construct a message object, you need to use a builder. Each message class has its own builder class—so in our Foo example, the Protobuf compiler generates a nested class Foo.Builder which can be used to build a Foo. Foo.Builder implements the Message.Builder interface. It extends the GeneratedMessage.Builder class, but, again, this should be considered an implementation detail. Like Foo, Foo.Builder may rely on generic method implementations in GeneratedMessage.Builder or, when the optimize_for option is used, generated custom code that is much faster. You can get a Foo.Builder by calling the static method Foo.newBuilder().

Foo.Builder does not define any static methods. Its interface is exactly as defined by the Message.Builder interface, with the exception that return types are more specific: methods of Foo.Builder that modify the builder return type Foo.Builder, and build() returns type Foo.

Methods that modify the contents of a builder—including field setters—always return a reference to the builder (i.e. they “return this;”). This allows multiple method calls to be chained together in one line. For example: builder.mergeFrom(obj).setFoo(1).setBar("abc").clearBaz();

Note that builders are not thread-safe, so Java synchronization should be used whenever it is necessary for multiple different threads to be modifying the contents of a single builder.

Sub-Builders

For messages containing sub-messages, the compiler also generates sub-builders. This allows you to repeatedly modify deep-nested sub-messages without rebuilding them. For example:

message Foo {
  int32 val = 1;
  // some other fields.
}

message Bar {
  Foo foo = 1;
  // some other fields.
}

message Baz {
  Bar bar = 1;
  // some other fields.
}

If you have a Baz message already, and want to change the deeply nested val in Foo. Instead of:

baz = baz.toBuilder().setBar(
    baz.getBar().toBuilder().setFoo(