TL;DR – This post explains how to compile Protocol Buffers schemas into
Java sources in Maven. Over the course of time, there appeared plugins like
protoc-jar-maven-plugin.
Nevertheless, the steps below still present a value to understand the
necessary plumbing and some best practices (e.g., shading) that are not
covered by the plugins.

Java build systems have always been a second class citizen for Protocol
Buffers. As is the case for
many other Java serialization frameworks (e.g., Cap’n
Proto,
FlatBuffers), Protocol Buffers does
not provide a native Java compiler which you can inject into Maven
dependencies and invoke a plugin to compile .proto files into .java
sources. Hence, programmers needed to have protoc (Proto Buffers Compiler)
binary on their development machine and call this platform-dependent binary
during Maven build. This totally violates the environment independent build of
a project. Fortunately, Google releases platform-specific protoc binaries in
the form of Maven artifacts.

We can add these artifacts as a compile-time dependency to our Maven project
and invoke the platform-dependent binary to compile .proto sources.

Detecting Operating System

protoc Maven artifact is provided in various platform-specific
classifications: linux-x86_32, linux-x86_64, osx-x86_32, osx-x86_64,
windows-x86_32, windows-x86_64. In order to pick the right artifact, we
will employ os.detected.classifier property exposed by os-maven-plugin:

Shading Protocol Buffers Package

Say you are done with your project, which includes protobuf-java version
3.0.0-beta-1 as a dependency. What if there is another package that is
included as a direct or transitive Maven dependency and injects
protobuf-java version 2.5.0? Then you are doomed; you will get a package
version conflict. In order to avoid this problem, you can leverage
maven-shade-plugin to relocatecom.google.protobuf package contents to a
private package within your project:

This will relocate the contents of com.google.protobuf package to
${project.groupId}.${project.artifactId}.shaded.protobuf and make the
classes accessible under this namespace. That is, instead of using

importcom.google.protobuf.*;

in your project, you should use the new relocated package name:

importgroupId.artifactId.shaded.protobuf.*;

(Note that you need to replace groupId and artifactId literals in the Java
code.)

Conclusion

In this post, I tried to summarize the necessary set of steps to compile
Protocol Buffers schema into Java classes using plain Maven magic. This is
important to get a platform-independent build for a project.

The absence of a proper Maven plugin to handle all these steps for us causes
quite a bit of pom.xml pollution. Nevertheless, (de)serializers for the
messaging medium are generally distributed in a separate artifact, hence this
will probably end up being the entire content of your pom.xml.