This library was created to generate java data classes for protobuf binary format using java annotation processor mechanism. Currently, the library is in the early stage of development and support only most basic functionalities.
There are few existing solutions, but I wanted to achieve the following:
- Use standard java toolchain. No need for external compilers and additional gradle/maven plugins (in contrary to official protoc)
- Generate code in the pre-compile stage, not in the runtime (in contrary to Protostuff)
- Generate whole java classes, not enhance existing POJOs (in contrary to Protostuff).
I believe that first two points are the big advantage of this library. The last one may be considered a disadvantage in some use cases. But well, if there is a demand for such feature, it can always be added. The current architecture do not forbid adding such functionality.
Generated data classes are java records, which I think fits perfectly in this case. Those are basically data transfer objects with only serialization logic. By definition, they are immutable and provide good equals, hashcode and toString implementations.
You can define your protobuf schema using only java annotations
@Message(
name = "SimpleRecord",
fields = {
@Field(type = "int32", name = "amount", number = 1),
@Field(type = "double", name = "latitude", number = 2),
@Field(type = "double", name = "longitude", number = 3)
}
)
class Main {
public static void main(String[] args) {
// Create record
SimpleRecord r1 = new SimpleRecord(10, 20.0, 30.0);
// You can use builder as well
SimpleRecord r2 = SimpleRecord.builder()
.amount(10)
.latitude(20.0)
.longitude(30.0)
.build();
// Serialize to bytes array
byte[] data = r1.toByteArray();
// Or to output stream
Path file = Paths.get("test.data");
try (OutputStream output = Files.newOutputStream(file)) {
r1.writeTo(output);
}
// Deserialize from bytes array
SimpleRecord r3 = SimpleRecord.parse(data);
// Or from input stream
try (InputStream input = Files.newInputStream(file)) {
SimpleRecord r4 = SimpleRecord.parse(input);
}
// read record fields
System.out.printf("Record [amount=%d, latitude=%f, longitude=%f]%n", r3.amount(), r3.latitude(), r3.longitude());
}
}
There is also a plan to support *.proto
files as a source of protobuf schema, but it is not implemented yet
Library is available in Central Maven Repository
implementation("com.github.pcimcioch:protobuf-api:1.1.0")
annotationProcessor("com.github.pcimcioch:protobuf:1.1.0")
Note that protobuf-api
is implementation
dependency, not compileOnly
.
<dependencies>
<dependency>
<groupId>com.github.pcimcioch</groupId>
<artifactId>protobuf-api</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.github.pcimcioch</groupId>
<artifactId>protobuf</artifactId>
<version>1.1.0</version>
<optional>true</optional>
</dependency>
</dependencies>
Note that protobuf
is optional
dependency, not need to propagate it any further
For full documentation just see examples in the test module
The best solution in terms of the support and feature-completeness is official protobuf library from the Google.
The biggest disadvantage of this solution is that you have to use separate protoc
compiler to create your java
classes.
Moreover, I don't really like the model that is generated by this compiler (although it is highly personal, subjective
opinion).
To easily incorporate it in your build pipeline you can use some 3rd party plugins, like for example protobuf-gradle-plugin
Protostuff is an annotation-based solution to turn existing POJOs into the protobuf serializers / deserializers.
It integrates seamlessly with your java application and allows you to add protobuf serialization logic to the existing POJOs. The biggest disadvantage is that it uses reflection and generates code in the runtime. Also, it requires you to create POJOs to annotate, it does not create whole classes for you (which may be advantage or disadvantage, depending on what you need)
For general Protobuf documentation
see official documentation
This library will support only proto3
specification
Current feature support:
There are few JMH performance tests that compare this solution with protoc. Generally it seems that this solution is faster when reading, comparable when writing and worse when writing heavily nested objects.
As always in such cases, do not relay on this benchmark. If you want to know which solution would be best for your application, prepare your own benchmark covering your exact use case and exact runtime environment.