Dependencies

Like any other Java project in Maven, your Protobuf project may need to depend on other dependencies located in a Maven repository or some other location. This has first-class support within this plugin without you needing to do anything special.

A simple example

Any Maven dependencies in your project that are a valid ZIP or JAR archive or file tree will be scanned during execution to discover any *.proto files internally. All proto files will be extracted and made visible to protoc relative to their file hierarchy.

For example, suppose you are writing a ticketing system, and you are working on the user profiles functionality. You may have the following project structure:

┣━ pom.xml  (org.example/ticketsystem-users-parent)
┗━ ticketsystem-user-protos/
    ┣━ pom.xml  (org.example/ticketsystem-user-protos)
    ┗━ src/
        ┗━ main/
            ┗━ protobuf/
                ┗━ org/
                    ┗━ example/
                        ┗━ ticketsystem/
                            ┗━ users/
                                ┣━ avatar.proto
                                ┣━ profile.proto
                                ┣━ team.proto
                                ┗━ user.proto      

You may have a set of message definitions that depends on proto files from other projects. In our case, let's say our team.proto depends on a ticket_board.proto in a totally different Maven project:

// org/example/ticketsystem/users/team.proto

syntax = "proto3";

package org.example.ticketsystem.users;

option java_multiple_files = true;
option java_package = "org.example.ticketsystem.users";

import "org/example/ticketsystem/board/ticket_board.proto";
import "org/example/ticketsystem/users/avatar.proto";
import "org/example/ticketsystem/users/user.proto";

message Team {
  org.example.ticketsystem.users.Avatar icon = 1;
  string name = 2;
  org.example.ticketsystem.users.User owner = 3;
  org.example.ticketsystem.board.TicketBoard ticket_board = 4;
}

Luckily for us, the ticket_board.proto is published in our Maven repository in a ZIP file with the following hierarchy:

┣━ pom.xml  (org.example/ticketsystem-users-parent)
┗━ ticket_board_protos.zip
    ┣━ META_INF/
    ┃   ┗━ .../
    ┗━ org/
        ┗━ example/
            ┗━ ticketsystem/
                ┗━ board/
                    ┗━ ticket_board.proto       

We can add a dependency on this in our pom.xml, and the protobuf-maven-plugin will automatically detect it and discover the proto files inside it, enabling our project to build successfully:

<project>
  ...
  
  <dependencies>
    <dependency>
      <groupId>org.example</groupId>
      <artifactId>ticketsystem-ticket-board</artifactId>
      <version>...</version>
      <classifier>zip</classifier>
      <scope>compile</scope>      
    </dependency>
  </dependencies>
</project>

Maven Dependencies

By default, the plugin will discover all *.proto files in all dependencies of the current Maven project. This occurs transitively, and all are added to the protoc import path.

The idea here is that the behaviour for imports should almost exactly mimic how Java dependencies work and how they are resolved on the classpath.

It is important to note that by default, only dependencies with the compile, provided, system and test (only for test executions) scopes will be inspected.

If you wish to exclude certain transitive dependencies, you can use the existing Maven exclusion mechanism.

<dependency>
  <groupId>org.example</groupId>
  <artifactId>ticketsystem-ticket-board</artifactId>
  <version>...</version>
  <classifier>zip</classifier>
  <scope>compile</scope>
  
  <excludes>
    <exclude>
      <groupId>org.example</groupId>
      <artifactId>ticketsystem-beta-user-protos</artifactId>
    </exclude>
  </excludes>
</dependency>

This will also respect Maven dependency management.

Advanced configuration

In addition to scanning Maven dependencies, the plugin also has several advanced settings to enable you to control the dependencies that are resolved from within the plugin itself.

Disabling resolution of Maven project dependencies

If you wish to disable discovery of *.proto sources from Maven project dependencies, you can disable this in the plugin configuration:

<plugin>
  <groupId>io.github.ascopes</groupId>
  <artifactId>protobuf-maven-plugin</artifactId>
  
  <configuration>
    <ignoreProjectDependencies>true</ignoreProjectDependencies>
  </configuration>
</plugin>

If you do this, only dependencies explicitly configured in the plugin configuration will be considered.

Adding additional import paths from the local file system

If you wish to make *.proto files from the local file system visible to protoc, you can add their directory roots to the plugin configuration:

<plugin>
  <groupId>io.github.ascopes</groupId>
  <artifactId>protobuf-maven-plugin</artifactId>
  
  <configuration>
    <importPaths>
      <importPath>/path/to/protos/root</importPath>
      ...
    </importPaths>
  </configuration>
</plugin>

In this example, /path/to/protos/root will be recursively searched for *.proto sources and added to the import path.

You can add as many of these as you like to your project.

Adding Maven artifact dependencies within the plugin configuration

If you wish to keep your protobuf dependencies out of your main project configuration, you can configure them within the plugin configuration itself. Ideally you should use the Maven project dependency configuration for this, but regardless, this feature is provided in case you have any unique use cases for it.

<plugin>
  <groupId>io.github.ascopes</groupId>
  <artifactId>protobuf-maven-plugin</artifactId>

  <configuration>
    <includeDependencies>
      <includeDependency>
        <groupId>org.example</groupId>
        <artifactId>ticketsystem-ticket-board</artifactId>
        <version>...</version>
        <classifier>zip</classifier>
        <scope>compile</scope>
      
        <exclusions>
          <exclusion>
            <groupId>org.example</groupId>
            <artifactId>ticketsystem-beta-user-protos</artifactId>
          </exclusion>
        </exclusions>
      </includeDependency>
    </includeDependencies>
  </configuration>
</plugin>

Compiling dependencies

If you wish to also compile your dependencies, you can specify them in the sourceDependencies and sourceDirectories configuration parameters, depending on whether they are Maven artifacts or paths on the local file system:

<plugin>
  <groupId>io.github.ascopes</groupId>
  <artifactId>protobuf-maven-plugin</artifactId>
  
  <configuration>
    <sourceDependencies>
      <sourceDependency>
        <groupId>org.example.foobar</groupId>
        <artifactId>core-protos</artifactId>
        <version>1.2.3</version>
        <type>zip</type>
      </sourceDependency>
    </sourceDependencies>
    
    <sourceDirectories>
      <!-- Keep the default path -->
      <sourceDirectory>${project.basedir}/src/protobuf</sourceDirectory>

      <!-- Add something else from the local system -->
      <sourceDirectory>/path/to/something/else/to/include</sourceDirectory>
    </sourceDirectories>
  </configuration>
</plugin>

Dependency management

The protobuf-maven-plugin will respect any dependencyManagement blocks in the current or parent project, allowing you to infer versions from a parent POM across numerous projects in your team.

This is already valid if you use the dependencies block within your pom.xml, but will also apply to importDependencies blocks as well.

<project>
  ...
  
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>4.30.0</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <plugin>
    <groupId>io.github.ascopes</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
  
    <configuration>
      ...
      
      <includeDependencies>
        <includeDependency>
          <groupId>com.google.protobuf</groupId>
          <artifactId>protobuf-java</artifactId>
          <!-- The version here is inferred from <dependencyManagement/>! -->
        </includeDependency>
      </includeDependencies>
    </configuration>
  </plugin>
</project>