views:

1904

answers:

5

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.

A: 

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
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.
I agree it's overkill but at times it can offer an easy way to do un-Maven things.
matt b
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.
+8  A: 

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>
Pascal Thivent
Absolutely riveting discussion, thanks for that link.
Max A.
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
+4  A: 

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.

Max A.
Thanks for the feedback.
Pascal Thivent
+1  A: 

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&amp;name=pom.xml'
mvn install

You can then use the maven config above.

mrm
A: 

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>
jsravn

related questions