Skip to main content
The Java Protocol Buffers runtime (version 4.35-dev) provides generated classes that follow Java idioms and integrate with standard Java I/O. An Android-optimized Lite runtime is also available.

Installation

1

Add the runtime dependency

<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>4.35.0</version>
</dependency>
Ensure the runtime version is equal to or newer than the version of protoc you use to generate code.
2

(Optional) Add protobuf-java-util

For JSON formatting, reflection utilities, and well-known type support:
<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java-util</artifactId>
  <version>4.35.0</version>
</dependency>
3

Install protoc

Download the prebuilt protoc binary for your platform from the releases page, or build it from source using Bazel.

Generating code

Run protoc with --java_out to generate Java source files:
protoc --java_out=${OUTPUT_DIR} path/to/your/file.proto
For the addressbook example:
protoc --java_out=src/main/java addressbook.proto
With option java_multiple_files = true set in the .proto file, each message type is generated in its own .java file. Without it, all types are nested inside a single outer class named by java_outer_classname.

Bazel

Bazel has native support for Java protobuf generation:
java_proto_library(
    name = "addressbook_java_proto",
    deps = [":addressbook_proto"],
)

Working with messages

Builder pattern

All generated Java message classes are immutable. To create or modify a message, use its Builder:
import com.example.tutorial.protos.Person;
import com.example.tutorial.protos.Person.PhoneType;

Person person = Person.newBuilder()
    .setId(1234)
    .setName("Jane Doe")
    .setEmail("[email protected]")
    .addPhones(
        Person.PhoneNumber.newBuilder()
            .setNumber("+1-555-0100")
            .setType(PhoneType.MOBILE)
            .build())
    .build();

Serializing and parsing

byte[] bytes = person.toByteArray();

Full example: AddPerson.java

This example reads an address book from disk, prompts for a new person, and writes it back:
import com.example.tutorial.protos.AddressBook;
import com.example.tutorial.protos.Person;
import com.google.protobuf.util.Timestamps;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;

class AddPerson {
  static Person PromptForAddress(BufferedReader stdin,
                                 PrintStream stdout) throws IOException {
    Person.Builder person = Person.newBuilder();

    stdout.print("Enter person ID: ");
    person.setId(Integer.valueOf(stdin.readLine()));

    stdout.print("Enter name: ");
    person.setName(stdin.readLine());

    stdout.print("Enter email address (blank for none): ");
    String email = stdin.readLine();
    if (email.length() > 0) {
      person.setEmail(email);
    }

    while (true) {
      stdout.print("Enter a phone number (or leave blank to finish): ");
      String number = stdin.readLine();
      if (number.length() == 0) break;

      Person.PhoneNumber.Builder phoneNumber =
        Person.PhoneNumber.newBuilder().setNumber(number);

      stdout.print("Is this a mobile, home, or work phone? ");
      String type = stdin.readLine();
      if (type.equals("mobile")) {
        phoneNumber.setType(Person.PhoneType.MOBILE);
      } else if (type.equals("home")) {
        phoneNumber.setType(Person.PhoneType.HOME);
      } else if (type.equals("work")) {
        phoneNumber.setType(Person.PhoneType.WORK);
      } else {
        stdout.println("Unknown phone type.  Using default.");
      }

      person.addPhones(phoneNumber);
      person.setLastUpdated(Timestamps.now());
    }

    return person.build();
  }

  public static void main(String[] args) throws Exception {
    if (args.length != 1) {
      System.err.println("Usage:  AddPerson ADDRESS_BOOK_FILE");
      System.exit(-1);
    }

    AddressBook.Builder addressBook = AddressBook.newBuilder();

    try {
      FileInputStream input = new FileInputStream(args[0]);
      try {
        addressBook.mergeFrom(input);
      } finally {
        try { input.close(); } catch (Throwable ignore) {}
      }
    } catch (FileNotFoundException e) {
      System.out.println(args[0] + ": File not found.  Creating a new file.");
    }

    addressBook.addPeople(
      PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
                       System.out));

    FileOutputStream output = new FileOutputStream(args[0]);
    try {
      addressBook.build().writeTo(output);
    } finally {
      output.close();
    }
  }
}

Lite runtime for Android

For Android apps, the Lite runtime significantly reduces code size and works better with ProGuard/R8 because it avoids Java reflection.
<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-javalite</artifactId>
  <version>4.35.0</version>
</dependency>
Generate Lite-compatible code by adding optimize_for = LITE_RUNTIME to your .proto file, or use the java_lite_proto_library Bazel rule.
The Lite runtime API is not yet stable and may change in minor version releases. Avoid using it in library code that you do not control end-to-end.

Kotlin support

Kotlin protobuf support provides idiomatic Kotlin APIs built on top of the Java runtime. Add both dependencies and generate both Java and Kotlin output:
protoc --java_out=${OUTPUT_DIR} --kotlin_out=${OUTPUT_DIR} path/to/file.proto
<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-kotlin</artifactId>
  <version>4.35.0</version>
</dependency>

Key API reference

Message

All generated classes extend com.google.protobuf.Message. Use .newBuilder() to get a mutable Builder, then call .build() to get an immutable message.

Serialization

toByteArray() / parseFrom(byte[]) for byte arrays. writeTo(OutputStream) / parseFrom(InputStream) for streams. mergeFrom(InputStream) to merge into an existing builder.

JSON

JsonFormat.printer().print(message) and JsonFormat.parser().merge(json, builder) from protobuf-java-util.

Compatibility

Minor version releases are backwards-compatible in both binary and source form. APIs annotated @ExperimentalApi may change at any time.

Build docs developers (and LLMs) love