protobuf-maven-plugin

repository·main·Indexed 41 days ago

https://github.com/ascopes/protobuf-maven-plugin

A modern Maven plugin for protoc integration that automates the discovery of proto sources from project dependencies. It supports multiple language targets including Java, Kotlin JVM, Python, and Ruby, and handles both native binary and JVM-based plugins.

Tokens
22.2K
Snippets
60
Records
79
Agent score
51%

What's inside protobuf-maven-plugin

  1. Overview of Protobuf Maven Plugin capabilities

    main

    The Protobuf Maven Plugin automates the integration of Protobuf compilation into Maven builds. Key features include:

    • Automatic protoc management: The plugin can pull specific versions of protoc directly from Maven Central, removing the need to update the plugin itself just to get a newer compiler version.
    • System protoc fallback: If your operating system is not supported by the official Google protoc releases, you can configure the plugin to use the protoc binary found in your system's PATH.
    • gRPC support: Automatically generates gRPC stubs for services.
    • Multi-language generation: Supports generating both Java and Kotlin source code.
  2. Order multiple protoc plugins

    main

    Plugins can be ordered relative to each other and to built-in generators.

    • The order attribute controls precedence.
    • Default order is 0 (same as descriptors and languages).
    • Use a negative integer to run the plugin earlier (e.g., -999 runs before Java source generation).
    • Use a positive integer to run the plugin later.

    If multiple plugins have the same order, the execution order is undefined but stable on the same system.

    <plugin kind="jvm-maven">
      <!-- Always run before generating Java sources. -->
      <order>-999</order>
    </plugin>
  3. Move proto files into a separate module

    main
    If your project contains a large number of proto files alongside application logic, build speeds will decrease. A best practice for large projects is to move proto files into a dedicated Maven module. This allows you to rebuild the proto module only when definitions change, while the rest of your application simply consumes the generated code as a standard dependency.
  4. How protoc plugin variants work

    main

    To generate outputs like gRPC stubs or support languages like Scala, you can add custom plugins to your build. You must specify the kind attribute for each plugin to tell protobuf-maven-plugin how to resolve and execute it.

    Supported kind values include:

    • binary-maven: For binary plugins hosted in Maven repositories.
    • jvm-maven: For pure-Java plugins.
    • path: For binary executables located on the system $PATH.
    • url: For binary plugins to be fetched from a specific URI.
    <plugins>
      <plugin kind="binary-maven">
        ...
      </plugin>
      <plugin kind="jvm-maven">
        ...
      </plugin>
      <plugin kind="path">
        ...
      </plugin>
      <plugin kind="url">
        ...
      </plugin>
    </plugins>
  5. How digest verification works with URLs

    main

    When using digests for verification, the digest is applied to the final output artifact within the URL, not the outer container.

    For example, in the URL zip:ftp://some-server.net/archives/data.zip!/data/some-file.txt, the digest is compared against the binary content of data/some-file.txt. It is not computed for the data.zip archive itself.

    zip:ftp://some-server.net/archives/data.zip!/data/some-file.txt
  6. How URL protocol nesting works

    main

    The plugin supports stackable and nestable protocols. When evaluating a URL, the innermost fragment is evaluated first, and the result is passed to the next handler in the stack. This allows you to combine fetching, decompression, and archive extraction in a single string.

    Example Workflow: tar:gz:https://some-website.com/protoc-gen-bang.tar.gz!/bin/protoc-gen-bang

    1. Fetches the resource from https://some-website.com/protoc-gen-bang.tar.gz.
    2. Decompresses it using the gz (gzip) protocol.
    3. Treats the result as a tarball and extracts the entry bin/protoc-gen-bang.
    4. Passes the resulting binary to the plugin.
    tar:gz:https://some-website.com/protoc-gen-bang.tar.gz!/bin/protoc-gen-bang
  7. Use incremental compilation for faster builds

    main

    Since version 2.8.0, incremental compilation is enabled by default. The plugin detects if sources or dependencies have changed since the last build; if no changes are detected, protoc is not re-invoked.

    Note: Incremental compilation is automatically disabled if you are requesting the generation of descriptor files. If you require descriptor files, consider moving your proto definitions into a separate Maven module to isolate the build impact.

  8. Generate code to multiple output directories

    main

    To generate code for different target languages into separate directories, define multiple <execution> blocks within the protobuf-maven-plugin configuration. Each execution must have a unique <id> and its own <configuration> block specifying the desired <outputDirectory>.

    When configuring an execution for a specific language, ensure you enable that language (e.g., <pythonEnabled>true</pythonEnabled>) and disable others if necessary (e.g., <javaEnabled>false</javaEnabled>) to prevent redundant generation in the same execution block.

    <plugin>
      <groupId>io.github.ascopes</groupId>
      <artifactId>protobuf-maven-plugin</artifactId>
      
      <executions>
        <!-- Java sources -->
        <execution>
          <id>java</id>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>
            <outputDirectory>${project.basedir}/target/java</outputDirectory>
    
            <protoc kind="binary-maven">
              <version>${protobuf.version}</version>
            </protoc>
          </configuration>
        </execution>
        
        <!-- Python sources -->
        <execution>
          <id>python</id>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>
            <javaEnabled>false</javaEnabled>
            <outputDirectory>${project.basedir}/target/python</outputDirectory>
            <pythonEnabled>true</pythonEnabled>
    
            <protoc kind="binary-maven">
              <version>${protobuf.version}</version>
            </protoc>
          </configuration>
        </execution>
      </executions>
    </plugin>
  9. Handle Protobuf dependencies from Maven artifacts

    main

    The plugin provides first-class support for discovering *.proto files within Maven dependencies. Any dependency that is a valid ZIP, JAR, or file tree will be scanned, and its proto files will be extracted and made visible to protoc relative to their file hierarchy.

    Importing vs. Compiling

    • Importing: By default, the plugin discovers proto files in all project dependencies (transitively) and adds them to the protoc import path. These are not compiled alongside your project; it is expected that these dependencies already bundle the corresponding class files (e.g., protobuf-java).
    • Compiling: If you need to actually compile the proto files from a dependency, you must explicitly list them in the <sourceDependencies> configuration block.
    <!-- Example: Importing a ZIP artifact containing protos -->
    <configuration>
      <sourceDependencies>
        <sourceDependency>
          <groupId>org.example</groupId>
          <artifactId>ticketsystem-ticket-board</artifactId>
          <version>...</version>
          <classifier>zip</classifier>
          <scope>compile</scope>      
        </sourceDependency>
      </sourceDependencies>
    </configuration>
  10. Generate Scala code with ScalaPB

    main

    To enable Scala support, use the ScalaPB plugin. This typically involves using a url kind plugin to fetch the ScalaPB binary from a ZIP archive and disabling Java generation via <javaEnabled>false</javaEnabled> if you only want Scala output. You must also include a Scala compilation Maven plugin (like scala-maven-plugin) in your build.

    <plugin>
      <groupId>io.github.ascopes</groupId>
      <artifactId>protobuf-maven-plugin</artifactId>
    
      <configuration>
        <javaEnabled>false</javaEnabled>
    
        <plugins>
          <plugin kind="url">
            <url>zip:https://github.com/scalapb/ScalaPB/releases/download/v${scalapb.version}/protoc-gen-scala-${scalapb.version}-linux-x86_64.zip!/protoc-gen-scala</url>
            <options>flat_package,grpc,scala3_sources</options>
          </plugin>
        </plugins>
    
        <protoc kind="binary-maven">
          <version>${protobuf.version}</version>
        </protoc>
      </configuration>
    
      <executions>
        <execution>
          <goals>
            <goal>generate</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    
    <plugin>
      <groupId>net.alchim31.maven</groupId>
      <artifactId>scala-maven-plugin</artifactId>
      <configuration>
        <failOnMultipleScalaVersions>true</failOnMultipleScalaVersions>
      </configuration>
    </plugin>