Note: If you want to stick with JPA only, this post might not be helpful.
Another Note: updated for Hibernate 5
I have been working with the Spring framework and java for the majority of my professional career, so when I need to start working on a new project involving them, the choices are pretty much always clear. Persistence pretty much always means using Hibernate.
For the past year and a half, I have been learning Scala (and Clojure, and Scheme, but that’s another story). And 6-8 months ago, I started getting paid for working in Scala. Now, one of the first problems that I ran into was which frameworks to use. With the web frameworks, the choice was between the three leading frameworks, Play, Lift and Scalatra. I was fascinated with Scalatra, but choosing Play Framework seemed like a better choice since it seemed to have better docs, more books and a lot of momentum. Plus, it was backed by Typesafe.
Then, I needed to choose a reasonably good persistence framework. That’s where I was stuck. I am still kinda stuck. Even though I decided to use Hibernate, I have never been satisfied. Hibernate begins to feel a bit clunky when you have to deal with
Option types, scala collections or immutability. I am very much inclined to use JOOQ or Slick. However, I don’t want to give up the convenience of Hibernate altogether. I guess I’ll have to come up with a way to combine Hibernate with one of these two1 without adding too much boilterplate or increasing the cognitive load. That is still a work in progress. Sticking with Hibernate alone was an extremely hard and frustrating decision. I wanted something more “functional” in nature, without the associated boilerplate.
With that out of the way, I think Hibernate is going to stick around for a while2. This post is an attempt to share a few things that I am doing to make Hibernate work reasonably well with Scala.
Dealing with Option[X] types
If you use
AccessType.FIELD for non-option types, hibernate picks them up without any fuss (unless you are using scala collections, of course). However, Hibernate doesn’t know how to deal with
Option types yet. And there is no generic, one-shot way to tell hibernate how to do so.
First (frustrating) approach
The easiest thing to do is using
AccessType.PROPERTY to do the following:
You end up having to write getter/setter pairs for each property that uses the
Option type. To prevent your API users from accidentally using these accessors, you make them
private (Hibernate uses reflection to access them). To be extra careful, you may even declare them as
Another, similar approach is:
Things are looking a little better now. This is a bit more scala-like. You use field-access and have a private field that hibernate can deal with. Use your own methods to wrap/unwrap
Option. If you don’t like the generated column names, override the default
NamingStrategy. This is much less verbose than the previous method.
A partial solution to target scalar types
There is a very easy way to make hibernate work with optional
scalars. You can implement the JPA
AttributeConverter with the
@Converter annotation to convert between your scala
types and the their database representations. It’s pretty
straightforward, so I am not providing a code sample. The
Converter annotation comes with an
attribute and when it is set to
true, the conversion is supposed to
be applied automatically to the target types.
A partial solution using UserTypes (scalar types only)
You can easily define
UserType implementations for all your scalar types.
This class is just either wrapping the scalar values inside
Option or unwrapping them from it. Once you have this, defining custom types is extremely easy.
Once the custom types are defined, use them with the
Type to annotate your fields.
StandardBasicTypes class defines several other scalar tyeps, so you can use as many as you like to define your own
Option wrapper types. Plus, if you don’t want to put in full paths in the
Type annotation every time you use them, you can give your custom types names using
@TypeDef annotations and use those names instead. Either way, you still need to use the
Type annotation everywhere3.
The best way (that works with all types)
Even if the
AttributeConverter and the related annotations worked, they still can’t deal with the composite types. You can try using the
CompositeUserType; Good luck and have fun. However, what if I told you there is a better, and much less frustrating solution? Well, there is. This one involves extending
PojoEntityTuplizer. Don’t worry though, it really isn’t as bad as it sounds. In fact, it is quite easy.
If you have worked long enough with Hibernate, you might be aware that it provides all kinds of pluggability. One of those pluggable thing is how hibernate will access the individual properties of a class. You can provide a custom strategy for accessing the properties. If you have been using JPA’s
@Access or Hibernate’s
@AccessType annotations, you have been doing that already. I am just going to take it bit further.
Define a PropertyAccessor that works with scala methods
PropertyAccessor is supposed to return a
Getter and a
Setter implementations. Which are exactly what they sound like. They are an abstraction over how those properties of a class are accessed. Your implementation will be given the class-name and the property-name that hibernate needs to access, and you return instances that allow hibernate to do that. The methods are very appropriately named
When you declare a
var in scala, the scala compiler actually creates a field by that name and creates the getter and setter. The getter has the same name as the property, whereas the setter is named like
propertyName_=. Since java identifers cannot have an equal sign in them, internally, this setter is represented as
So, once you have these two pieces of information, all you need to do get the
java.lang.Method instance that represent the getter and the setter for the given property-name; and that is easy, right. one word: reflection. In my code, I am using the scala reflection api, but the Java API would work just as well.
Getter has two responsibilites:
- Get the return-type of property (the getter method)
- fetch the value of the property from the given instance.
Setter has only one responsibility:
- Set the given value on the given object.
Do you see it now! Well, here are the three facts
- You are given the class-name and the property-name
- When hibernate needs the value of a property, it asks your [
Getter], passing it the target object.
- When hibernate needs to set the value of a property, it asks your [
Setter], passing it the target object and the value to set.
All done. This is it. When Hibernate asks you to set the value, wrap in an
Option. When it asks you to fetch a value, and if you see that it an
Option, unwrap it before returning.
The implementation is pretty simple. Just copy over the code from
BasicPropertyAccessor and convert it to Scala. Just for the completeness’ sake, I am including my implementation of the PropertyAccessor. It has warts. I know it can be improved, and I am working on it, but I am eager to share this.
This class needs access to the play framework’s Application object. It’s needed for getting java Class objects. If you are not using play, replace this with appropriate code. If you are using play, see this later sections.
Telling Hibernate to use our PropertyAccessor
An easy way to make Hibernate use our
PropertyAccessors is to use Hibernate’s
AccessType4 annotation and specify the class-name of your
PropertyAccessor as its value. Unfortunately, there is a bug in Hibernate that makes it ignore our custom property-accessors5. What happens internally is that if your property-access strategy name doesn’t match one of “field” or “property”, it is defaulted to one of them. It’s implemented as an enum and there is nothing anyone can do about it. No pluggability anywhere around.
Hibernate also provides an annotation called
@AttributeAccessor, which is supposed to replace their, now deprecated,
@AccessType annotation. However, at the moment of writing this, this annotation doesn’t work at all. There are no references to that annotation in the entire hibernate source code (version 4.3.6).
After wading through a bunch of Hibernate code, I finally found a way to work around that. Hibernate provides another pluggable feature called EntityTuplizer where you can customize the way an entity or a compoent is tuplized. There is also a default implementation called PojoEntityTuplizer that is used for POJOs. In that class, there is a pair of methods called
buildPropertySetter. These methods are used for building the Getter and Setter implementations for all properties of a pojo. We already have a class that does this for us. All we need to do is hook it in. The aforementioned methods are passed instances of
Property. These instances have a field named “propertyAccessorName”. The value of this field is a string representing our property-access strategy. Yeah, the same strategy that we would have used with the
AccessType annotation. So now:
- We extend
- override the
- when those two methods are called with a
Propertyinstance, we set its
propertyAccessorNamefield to the name of our custom property-accessor class
There is another little snag: the class that overrides
PojoEntityTuplizer must be written in Java. Since the entity-tuplizers need to have two very specific constructors. If those constructors are not present, Hibernate doesn’t accept our tuplizer. In scala, there is no way to call multiple super-class constructors. So, we write a bit of Java.
Once we have that in place, give this class to Hibernate while building the session-factory.
Dealing with Embeddables
Even though you are setting your own property-access stragety for all the properties of all your classes, it still doesn’t work with
Embeddable types. That is, if your embeddable components themselves contain
Option fields. For that, you need to use another knob. This one is called
ComponentTuplizer. Specifically, you need to extend the in-build
PojoComponentTuplizer and basically do the same thing that we did earlier with entity-tuplizer: Override the relevant methods to specify our own property-access strategy.
This has ony one required constructor, so you don’t need to write Java. Okay, so how do you hook this in? Turns out that like entities, there is no global way to plug-in our own component-tuplizer. We need to do it on each individual property.
The broken approach with @Tuplizer
If your embeddable itself is optional, then you need to specify its type explicitly using
@Target. Extremely annoying.
And no, putting
@Tuplizer on the embeddable class itself does not work. That is fairly annoying if you need to use the same embeddable in multiple places; especially because the docs for the annotation say:
Define a tuplizer for an entity or a component.
Even after doing all that, hibernate keeps refusing to behave correctly. A combination of
@Embeddable elements with nested embeddables and option types doesn’t work with our custom property-access strategy. This is a bug in hibernate6. I was so frustrated by this titime, I decided to pull out the big guns.
Using AspectJ to inject our property-access strategy
Yeah baby, I am going to mess with the bytecodes. Submitting patches to hibernate code and waiting for the issues to be resolved was not an option. I didn’t know how long the entire process would take. Some of the issues that I linked in this post have been open for more than 2 years. Also, some of things I wanted to do weren’t even bugs. They might not even be accepted by the hibernate community7. So, yeah, I am going to use aspects with scala8.
Still here? Okay. In the entire hibernate source code, there is only one place where the
PojoComponentTuplizer is being used. I wrapped some code around that to replace it with my
CustomPojoComponentTuplizer described previouly. It was surprisingly simple.
Take a look at the source code of
ComponentTuplizerFactory and you will understand what is happening here. I am just replacing the default component-tuplizer with my own. This is done via load time weaving of aspects. Compile time weaving was not really an option since I needed to weave into already-compiled, third-party classes.
I am aware that the solution with aspects might break when the new version of Hibernate comes out. It won’t be that big of a problem and they might have fixed some of the issues by then.
Are we there yet? I am getting annoyed.
That’s it. We are done. And if this sounds a bit hacky, that’s because it is. And I am okay with that. One of the advantages of working with open-source frameworks is that you can look under the hood and rearrage the wiring if needed. Of course, even though I am fairly familiar with Hibernate source code, I’ve never had so many WTF moments as I had while working on this. The code around the tuplizers, property-accessors and session-factory building is in a flux right now. There are several comments including the words “yucky” in that source code. So, I guess they know it too.
A few minor annoyances
This solution works really well. However there are still a few things you need to keep in mind:
You still need to provide explicit type info
Whenever you are using the option types, you need to provide explicit type info. That’s because hibernate will try to verify the mappings for properties before it starts dealing with tuplizers. Type info can be provided using one of the following.
@Typewith optional scalars
@Targetwith optional embeddables
targetEntityattribute with the
Load time weaving in Play dev mode
Getting aspects to work with play framework in the development mode is a bit of a pain in the ass. The kind of aspects I needed to use could only be done via load time weaving. Which, as the name suggests, is related to class-loading. In dev-mode, Play has multiple classloaders to allow dynamic reloading of source code. So, the whole load-time weaving with third-party classes gets messed up. Note that this problem only occurs in development mode. Class loading in play is pretty simple in the production mode. I will be writing a short companion post about it soon.
All of this exercise is required because Hibernate wasn’t designed to work with Scala. However, it doesn’t help that some of the things that Hibernate provides do not work. Like the custom strategy values for
@AccessType, or the
@AttributeAccessor annotation. However, I am hoping that the latter will start working soon. Once it starts working, this entire post can be reduced to a quarter of its current size.
And I don’t have much against Hibernate. Even with all the hate that ORMs get, Hibernate does its job quite well. I think it’s an extremely powerful and highly customizable tool. Of course, if you are just sticking to JPA-only features, you are missing out on a vast array of functionality and knobs that Hibernate provides. Yeah, yeah, I know, you might want to switch your persistence provider in the future. I, on the other hand, don’t see that happening very frequenly. ↩
It used to work, but the Hibernate guys are trying to make the session-factory and configuration related classes more streamlined. And this bug was probably a side-effect of that. I can see several TODO comments in the Hibernate code which indicate that this too is something they are working on. However, this could have been a low-priority issue, because, up until now, rarely anybody needed to provide custom property-accessors. ↩
Although, I am going to try that. One of the things I want to do is open up more hooks for customization. ↩
If you think aspects are evil, and against functional programming principles, you might be right. However, there are certain scenarios where using aspects does make sense. See this post for an interesting summary of when it is okay to use aspects. ↩