Using Custom Protoc Plugins

It is possible to customize protoc's output with plugins. Protoc plugins are executables that are invoked by protoc. They read code generator requests from stdin and output results to stdout.

Currently, both native and pure Java plugins are supported.

Plugins written in Java (or any other JVM language) have to be resolvable as Maven artifacts. Also, the output directory for generated files is the same as the Java output directory. They are configured by adding a protocPlugins element containing one of more protocPlugin elements to the configuration section.

Native plugins are supported by two dedicated goals: protobuf:compile-custom and protobuf:test-compile-custom.

Using a pure Java protoc plugin

The following example includes uses a single plugin to generate Java code in addition to protoc's regular output.

<plugin>
  <groupId>org.xolstice.maven.plugins</groupId>
  <artifactId>protobuf-maven-plugin</artifactId>
  <version>0.6.1</version>
  <extensions>true</extensions>
  <executions>
    <execution>
      <goals>
          <goal>compile</goal>
      </goals>
      <configuration>
        <protocPlugins>
          <protocPlugin>
            <id>myproto</id>
            <groupId>myproto</groupId>
            <artifactId>myproto-protoc-plugin</artifactId>
            <version>1.2</version>
            <mainClass>myproto.MyProtocPlugin</mainClass>
          </protocPlugin>
        </protocPlugins>
      </configuration>
    </execution>
  </executions>
</plugin>

This will resolve the Maven artifact myproto:myproto-protoc-plugin:1.2 and its dependencies, create a plugin executable on the fly and then invoke protoc with the argument --myproto_out=JAVAOUT where JAVAOUT is same directory used for the --java_out argument.

protocPlugin Options

The following options can be included in the protocPlugin element:

  • id - (required) unique id for this plugin
  • groupId - (required) group id for dependency resolution
  • artifactId - (required) artifact id for dependency resolution
  • version - (required) version specification for dependency resolution, can be either a single version (e.g. 1.2) or a version range (e.g. [1.2,1.3))
  • classifier - (optional) artifact classifier for dependency resolution
  • mainClass - (required) Java main class to execute
  • javaHome - (optional) location of the JDK used for executing the plugin; uses the JDK specified in toolchains.xml or the value of the java.home system property as default
  • winJvmDataModel - (optional; Windows only) data model of the JVM under javaHome. Possible values are '32' or '64'.
  • args - (optional) argument to pass to the main method
  • jvmArgs - (optional) JVM arguments

The location of the java command (on UNIX) or jvm.dll on Windows is determined as follows. First, the javaHome option in protocPlugin is used, if present. Otherwise, the jdkHome location of the jdk toolchain in toolchains.xml is used. If no toolchain has been set up, the JDK that's running Maven is used (the value of the java.home system property).

When running on Windows the plugin will try to determine whether javaHome is pointing to a 32-bit or 64-bit JDK/JRE. If it cannot determine the data model from directories under javaHome it will use the value of the sun.arch.data.model system property in the JVM that is running the plugin code. If that system property does not exist it will default to 32-bit. The value can be overridden by setting the winJvmDataModel option.

Java plugin generation

A Java-based executable is assembled on the fly from the specified artifact and its dependencies and executed by protoc. The way this is done is platform-dependent.

On UNIX, a shell script is created in target/protoc-plugins that builds a classpath from local repository paths of all resolved artifacts and then runs the configured java command.

On Windows, a WinRun4J executable (bundled inside the Maven plugin jar) is copied into target/protoc-plugins and an .ini is generated with the required classpath, jvm.dll location, main class and arguments.

The target/protoc-plugins directory is prepended to the PATH in protoc's runtime environment.