From JPA to Objectify
Spoiler: moving to Objectify is a good move, and apart from some differences between
JPA and Objectify, the transition went smoothly.
When I first created the application, I opted to use the GAE JPA API to stay in my comfort zone. Using too many new technologies in an application is a recipe for disaster, and for a seasoned JEE-developer GAE is challenging enough as it is.
As it turns out, using JPA to access the Google DataStore is not fun. JPA was developed as an abstraction over relational databases, and the DataStore is anything but relational. As a result, many JPA features just won’t work on AppEngine. Furthermore, some DataStore features that actually make the store performant are not available through JPA.
I was not happy.
Another problem with JPA is that it does a lot of processing on start-up to improve performance down the road. This works great for enterprise applications, but not for Google AppEngine where instances are brought up and down almost constantly.
So, this left me with a number of alternatives: JDO, Objectify, Slim3 and of course the native DataStore API. The internet told me that JDO shows the same startup delays as JPA; Slim3 also replaces SpringMVC which I am happy to use, and the native DataStore API is one bridge too native.
So I started out migrating from JPA to Objectify. As it turns out, this was surprisingly easy. The first step was to include Objectify in my Maven project. Since I wanted to keep using Spring, I also included the Objectify Spring extension for ease of use.
I then updated the annotations (where necessary) to only use the annotations supported by Objectify. In my case, this involved:
@Unindexedon entity level and
@Indexedon fields where required
@Cachedannotations on every entity because… why not?
I then removed my
persistence.xml and removed all JPA references from my Spring application context.
The next step was to rewrite my queries. ZooWizard is still a small application, and all the queries were abstracted into DAO’s. All in all, this took me about an hour. My development environment and Selenium tests showed that everything worked as it should.
I was becoming quite happy.
@Embedded in JPA vs
@Embedded in Objectify
Deploying my application to GAE showed a different story. The application refused to load any of my
@Embedded fields. My Google skills did not help and once again, I was not happy.
As it turns out, JPA maps
@Embedded fields differently from Objectify. Have a look at this JPA example:
In this example, JPA by default stores the “city” field in a column called “city”. Now have a look at this Objectify example:
Objectify stores the
city field as
address.city. Quite a difference. As it turns out, qualifying
names cannot by turned off using Objectify’s schema migration tools. So, I ended up with the following workaround:
@PostLoad method ensured that entities previously stored using JPA were still loaded correctly using Objectify.
Given the fact that ZooWizard still contains a small number of entities, I did not mind too much, but for large
applications this might be a showstopper.
I then proceeded loading and saving each entity using my Admin GUI. For large migrations, I would have opted for Task queues.
The last step was to remove everything I no longer needed:
- Objectify does not need the DataNucleus enhancement, improving my build speed;
- Many Spring/JPA libraries could be removed from my build. Some examples:
The move from JPA to Objectify was a good move. The Objectify API maps very well on the native DataStore API and forces you to think in AppEngine terms. As a happy aside, the size of my WAR file has been reduced by ~2Mb and startup time on my development environment has been reduced by 20%.
Do the wave
Follow the path
Choosing your target
the humble beginnings