Java’s JPA for Rails Fans

I’ve been thinking about ORMs lately.

I like Rails, it’s super quick to get up and running, the convention over configuration idea was brilliantly executed and has been endlessly copied. I believe that Rails forever changed the way that we write software.

I also like Java’s JPA (Java Persistence API)[1]. I hope to show those of you familiar with Rails and ActiveRecord why the JPA way of doing things is worth a look.

I’ve never seen a direct comparison between ActiveRecord and Java’s JPA. So I feel it would be interesting to start there.

In rails we have our models:

class User < ActiveRecord::Base has_and_belongs_to_many :todos def markAllTodosComplete @todos.each { |todo| todo.complete } end end class Todo < ActiveRecord::Base def share(user) user.todos << user end def complete self.is_done = true end end

In Java things look pretty similar [2]:

@Entity @Data public class User implements Serializable { @Id private int id; private String email; @ManyToMany private Set<Todo> todos = new HashSet<Todo>(); public markAllTodosComplete() { for (Todo todo : this.getTodos()) { todo.complete(); } } } @Entity @Data public class Todo implements Serializable { @Id private int id; private String description; private boolean isDone; public void complete() { this.isDone = true; } public void share(User user) { user.getTodos().add(user); } }

They are actually very similar, if you were to swap out ActiveRecord for DataMapper, they’d be even closer. For anyone who stopped using Java in the days of EJB2.0 and insidious xml, this might be quite refreshing.

However, I feel that JPA has a clear advantage over the Rails way. JPA defines annotations to define their persistence units to be managed whereas Rails uses inheritance.

This is a really powerful feature. The models do not know they can be persisted, it’s not their responsibility. They do not know about the join table for a relation, they just have a field of type Set. The models can create an inheritance structure that makes sense for the domain instead of being forced onto an enormous superclass. This is what Uncle Bob is talking about in this short video.

The models are bootstrapped into the persistence layer with annotations instead of chained to it with inheritance. With ActiveRecord it takes experience, discipline, and a realization that things can be better. Corey Haines gave a thirty minute talk complaining about how slow Rails unit tests are and how he uses a simple strategy to make them nigh instantaneous. The tl;dr of the talk is to separate your business logic into a mixin you then include in your models. The model takes care of persistence, you leave that to ActiveRecord, and your unit tests worry about the business logic.

When you use JPA this is the default. Unit tests run quickly because they do not need to spin up a container, you deal with plain old Java objects. You can swap out the JPA implementation without changing a single model because the different frameworks have agreed on this API and because the annotations are merely seams on top of the code where the containers can place their hooks.

JPA enables all of this but similar designs in the dynamic language frameworks are rare. I am not aware of any other than PHP’s Doctrine. I wrote about Rails here, but Django and all of the other frameworks that force your models to inherit from a god class are asking you to tightly couple your code to their implementation.

So what am I missing here, why have so many communities ignored the JPA pattern? Why shouldn’t we use something like annotations to bootstrap our models?

[1]: I’m talking about the JPA (the standard) as if it is an ORM, but feel free to use Hibernate (an implementation of the standard) in its place.