42

I'm experimenting with Protocol Buffers in an existing, fairly vanilla Maven 2 project. Currently, I invoke a shell script every time I need to update my generated sources. This is obviously a hassle, as I would like the sources to be generated automatically before each build. Hopefully without resorting to shameful hackery.

So, my question is two-fold:

  1. Long shot: is there a "Protocol Buffers plugin" for Maven 2 that can achieve the above in an automagic way? There's a branch on Google Code whose author appears to have taken a shot at implementing such a plugin. Unfortunately, it hasn't passed code review or been merged into protobuf trunk. The status of that plugin is thus unknown.

  2. Probably more realistic: lacking an actual plugin, how else might I go about invoking protoc from my Maven 2 build? I suppose I may be able to wire up my existing shell script into an antrun invocation or something similar.

Personal experiences are most appreciated.

Max A.
  • 4,842
  • 6
  • 29
  • 27
  • This is 7 year old question, that mostly has outdated answers (except one). Newer questions are linked. E.g. http://stackoverflow.com/questions/40426366/automatically-generate-java-from-proto-with-maven-m2e-in-eclipse-ide and http://stackoverflow.com/questions/40575671/automatically-re-generated-source-update-on-edit-in-eclipse-with-maven-m2e – Paul Verest Nov 16 '16 at 05:54

9 Answers9

44

You'll find some information about the plugin available in the Protocol Buffers repository in the Protocol Buffers Compiler Maven Plug-In thread on the Protocol Buffers discussion group. My understanding is that it's usable but lacking tests. I'd give it a try.

Or you could just use the antrun plugin (snipet pasted from the thread mentioned above):

 <build>
   <plugins>
     <plugin>
       <artifactId>maven-antrun-plugin</artifactId>
       <executions>
         <execution>
           <id>generate-sources</id>
           <phase>generate-sources</phase>
           <configuration>
             <tasks>
               <mkdir dir="target/generated-sources"/>
               <exec executable="protoc">
                 <arg value="--java_out=target/generated-sources"/>
                 <arg value="src/main/protobuf/test.proto"/>
               </exec>
             </tasks>
             <sourceRoot>target/generated-sources</sourceRoot>
           </configuration>
           <goals>
             <goal>run</goal>
           </goals>
         </execution>
       </executions>
     </plugin>
   </plugins>
 </build>

 <dependencies>
   <dependency>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-java</artifactId>
     <version>2.0.3</version>
   </dependency>
 </dependencies>
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • 1
    I've found this answer satisfying, including for use with protobuf plugins which do not seem to be supported by the maven plugin. However, I'd recommend not using sourceRoot which is deprecated per http://maven.apache.org/plugins/maven-antrun-plugin/run-mojo.html#sourceRoot and rely on build-helper-maven-plugin instead (see http://mojo.codehaus.org/build-helper-maven-plugin/usage.html). This was necessary to make my protocol project and others that depend on it behave correctly in m2eclipse. – Thomas Dufour Sep 03 '10 at 10:29
  • @Thomas could you create a pastie.org with the pom needed for not using sourceRoot? – TJR Nov 18 '10 at 15:54
  • 4
    You also probably want to add failonerror to the tag so that your build stops if there's an error in your proto file. I.e. ``. – George Hawkins Apr 29 '11 at 10:01
  • The newest version is 2.5.0. To work with the current version of protoc you have to use 2.5.0 – morpheus05 Jan 16 '14 at 08:28
  • I am fairly new to maven, thus this question may be a bit pointless but, if I have a lot of `.proto` files, do I have to add them one by one into this script, as you did with `test.proto`? Like if I have two proto files, I shall write it like this, right? ` ` –  Jun 24 '16 at 08:16
  • It does not work for me, and produces the following: `[exec] /home/usr/workspace_runtime_x/x.messages/proto/ros/RosTime.proto: File does not reside within any path specified using --proto_path (or -I). You must specify a --proto_path which encompasses this file. Note that the proto_path must be an exact prefix of the .proto file names -- protoc is too dumb to figure out when two paths (e.g. absolute and relative) are equivalent (it's harder than you think) ` – Schütze Aug 04 '16 at 08:36
23

The accepted answer encouraged me to get the Google-provided plugin to work. I merged the branch mentioned in my question into a checkout of 2.2.0 source code, built and installed/deployed the plugin, and was able to use it in my project as follows:

  <build>
    <plugins>
      <plugin>
        <groupId>com.google.protobuf.tools</groupId>
        <artifactId>maven-protoc-plugin</artifactId>
        <version>0.0.1</version>
        <executions>
          <execution>
            <id>generate-sources</id>
            <goals>
              <goal>compile</goal>
            </goals>
            <phase>generate-sources</phase>
            <configuration>
              <protoSourceRoot>${basedir}/src/main/protobuf/</protoSourceRoot>
              <includes>
                <param>**/*.proto</param>
              </includes>
            </configuration>
          </execution>
        </executions>
        <configuration>
          <protocExecutable>/usr/local/bin/protoc</protocExecutable>
        </configuration>
      </plugin>
    </plugins>
  </build>

Note that I changed the plugin's version to 0.0.1 (no -SNAPSHOT) in order to make it go into my non-snapshot thirdparty Nexus repository. YMMV. The takeaway is that this plugin will be usable once it's no longer necessary to jump through hoops in order to get it going.

Community
  • 1
  • 1
Max A.
  • 4,842
  • 6
  • 29
  • 27
  • 9
    Please make this plugin available in Maven Central. Also, is there a way to programmatically invoke protoc instead of looking for an executable? It is a pain to generate protoc on many platforms including Mac OS X. – inder Apr 20 '11 at 17:28
21

The accepted solution does not scale for multiple proto files. I had to come up with my own:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <executions>
                <execution>
                    <id>compile-protoc</id>
                    <phase>generate-sources</phase>
                    <configuration>
                        <tasks>
                            <mkdir dir="${generated.sourceDirectory}" />
                            <path id="proto.path">
                                <fileset dir="src/main/proto">
                                    <include name="**/*.proto" />
                                </fileset>
                            </path>
                            <pathconvert pathsep=" " property="proto.files" refid="proto.path" />
                            <exec executable="protoc" failonerror="true">
                                <arg value="--java_out=${generated.sourceDirectory}" />
                                <arg value="-I${project.basedir}/src/main/proto" />
                                <arg line="${proto.files}" />
                            </exec>
                        </tasks>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
</build>
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
jsravn
  • 371
  • 2
  • 5
  • how to specify the location of protoc.exe file. my build fails because it is unable to locate protoc. Is protoc supplied by the PB 2.4.1 dependency added to the pon.xml ? – Rajat Gupta Oct 02 '11 at 18:29
  • No, protoc is the protocol buffer compiler and needs to be installed to the machine the build is running on and included in that machine's path. Refer to https://code.google.com/apis/protocolbuffers/docs/proto.html#generating (specifically the section on generating your classes) for more information – chrisbunney Dec 07 '11 at 12:30
10

There's also great plugin by Igor Petruk named protobuf-maven-plugin. It's in central repo now and plays nicely with eclipse (m2e-1.1 is recommended).

Anthony O.
  • 22,041
  • 18
  • 107
  • 163
morgwai
  • 2,513
  • 4
  • 25
  • 31
  • 1
    The documentation for Igor's plugin is [here](http://igor-petruk.github.com/protobuf-maven-plugin/usage.html). If you put your `.proto` files in `src/main/protobuf`, you'll get the output in `target/generated-sources/protobuf`. You'll still need `protoc` on your `PATH` for this to work. – Brad Feb 27 '12 at 21:18
4

I just updated the maven plugin to work with 2.2.0 -- the updated pom are attached to the code review bug.

Here are the instructions to build the plugin yourself:

svn co http://protobuf.googlecode.com/svn/branches/maven-plugin/tools/maven-plugin
cd maven-plugin
wget -O pom.xml 'http://protobuf.googlecode.com/issues/attachment?aid=8860476605163151855&name=pom.xml'
mvn install

You can then use the maven config above.

mrm
  • 5,001
  • 2
  • 32
  • 30
4

There is a maven plugin for protobuf. https://www.xolstice.org/protobuf-maven-plugin/usage.html

The minimal config

 <plugin>
    <groupId>org.xolstice.maven.plugins</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
    <version>0.5.0</version>
    <configuration>
      <protocExecutable>/usr/local/bin/protoc</protocExecutable>
    </configuration>
    <executions>
      <execution>
        <goals>
          <goal>compile</goal>
          <goal>test-compile</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
vr3C
  • 1,734
  • 19
  • 16
4

I just tried a less official but very recent (v 0.1.7) fork from https://github.com/dtrott/maven-protoc-plugin and it worked very well, courtesy of David Trott. I tested it with a couple of Maven modules one of which contained DTO-style messages and the other a service depending on them. I borrowed the plugin configuration MaxA posted on Oct 16 '09, I had protoc on my PATH and I added

<temporaryProtoFileDirectory>${basedir}/target/temp</temporaryProtoFileDirectory>

right after

<protocExecutable>protoc</protocExecutable>.

What is really nice is that all I had to do is to declare a normal dependency from the service module on the DTO module. The plugin was able to resolve proto files dependencies by finding the proto files packaged with the DTO module, extracting them to a temporary directory and using while generating code for the service. And it was smart enough not to package a second copy of the generated DTO classes with the service module.

ndolgov
  • 131
  • 1
  • 3
0

I think that using antrun to invoke non-Maven steps is the generally accepted solution.

You could also try the maven-exec-plugin.

matt b
  • 138,234
  • 66
  • 282
  • 345
  • I have two problems with using `antrun`: (1) Its stated purpose is to ease migration from or integration with Ant. I'm attempting to achieve neither. Thus using it in this case would almost seem like misuse. (2) I'm really just trying to spawn an external OS process. Pulling in all of Ant just for that is, IMHO, overkill. `maven-exec-plugin` sounds like a leaner and more appropriate choice in this case. – Max A. Oct 16 '09 at 14:58
  • I agree it's overkill but at times it can offer an easy way to do un-Maven things. – matt b Oct 16 '09 at 15:49
  • The funny part is that the Google folks use Maven to build the Java piece of protobuf, so there's absolutely nothing "un-Maven" about wanting to use a Maven plugin to compile my .proto sources. I'm sure this process will become easier once they have gotten their act together. All that remains really is to get this plugin into either Google's repository or central. – Max A. Oct 16 '09 at 15:58
0

I forked of the plugin from David Trott and have it compiling multiple languages which makes it a lot more useful. See the github project here and a tutorial on integrating it with a maven build here.

Usman Ismail
  • 17,999
  • 14
  • 83
  • 165