Protobuf2Hibernate is meant to allow you to directly persist Protobuf generated messages with Hibernate.
This is still in early development. There are still some things that don’t work propertly, like:
cascading associated Message entities.cascading associated Messages as composite elementspersisting protobuf enumssaving part of the object as a bulkcount queries
Bear with me! Or better: help out.
As you know, Hibernate has some requirements about the form of the persisted objects. For example it needs an accessible empty constructor and access to the fields of the object, usually through getters and setters.
From this point of view, Protobuf Message classes make poor candidates for Hibernate persistence. For starters, Messages are meant to be immutable which means they don’t have a public, empty constructor, their fields are final and they don’t even have setters. In order to create a Message you need to use a Message.Builder, but Hibernate doesn’t know how to do this. There are other, more subtle things, but all important if you want your persistence layer not to crash when you expect the least. For example, you can’t set a Protobuf field to NULL, but Hibernate will sometimes try to do this.
You’re stuck mapping your Message object first to a POJO which is then mapped to Hibernate. But this is highly inconvenient. Usually you need to write manual transformers, pollute your DAOs and when you change a field in the Protobuf message not only that you need to change the mapping to Hibernate but you also have to change the POJO and all the transformers as well. On a complex project this can easily lead to a 10,000+ lines of boilerplate code.
Protobuf2Hibernate strives to make the persistence of Message as easy as possible by tapping the extensions mechanisms provided by Hibernate. However these are not enough to do the whole job and still leaving the impression that you are working with POJOs. To solve this Protobuf2Hibernate proposes a few tiny tricks which you can use with minimum effort.
You will begin by mapping the object for Hibernate. Because the Message classes are generated by the Protobuf compiler it’s best to use .hbm.xml files to do this. You could still modify the generated class to add annotations but as soon as you would recompile the .proto files they would get overridden.
The only things you should know are:
- You’ll need to map the Message.Builder object, not the Message itself. This is in order for Hibernate to be able to inject value into the fields when retrieving it from the database, or when saving a new object (generated id). Don’t worry, this is the only place where you’ll see the Builder. You’ll be working with Messages all the way.
- Use the special tuplizer
org.codeandmagic.protobuf2hibernate.ProtobufTuplizer
. This will teach Hibernate things like how to instantiate a Message and how get and set the values without using the getters and setters with reflection, but rather use Protobuf’s mechanism. - Repeated fields should be mapped as bag or list. You can however write a custom collection type to convert it to whatever mapping you want to use.
- Optional fields should me marked as nullable.
All you need to do is:
- Use a
org.codeandmagic.protobuf2hibernate.ProtobufTransformerSession
instead of the standard Hibernate session, to do the interaction. This wraps around the current Hibernate session and transforms Message.Builders to Messages when extracting them from the database and Messages to Message.Builders when you send them to the database. This is what allows you to load, save, query or create criterias using the Message class rather than the Builder class. Of course, you could just skip this step and work with Builders yourself, but that’s extra (messy) work for you and there’s no point in getting your hands dirty.
Of course. Head to the source code and look into the org.codeandmagic.protobuf2hibernate.sample
package. You’ll find
a the Cat message and a sample mapping, dao and a simple spring-hibernate setup to get you started.
Sure. If you find bugs or situations that are not covered, or you simply want to improve something, send a request or patch to cristian[dot]vrabie[at]gmail[dot]com. Who knows, you might even get on the commiters list :)