Using Hibernate with Scala - with less pain
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 private[this]
.
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 autoApply
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.
The 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 PropertyAccessor
and 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
A 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 getGetter
and getSetter
.
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 propertyName_$eq
.
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.
A Getter
has two responsibilites:
- Get the return-type of property (the getter method)
- fetch the value of the property from the given instance.
A 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 AccessType
4 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 buildPropertyGetter
and 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
PojoEntityTuplizer
- override the
buildPropertyGetter
andbuildPropertySetter
- when those two methods are called with a
Property
instance, we set itspropertyAccessorName
field 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
Use the @Tuplizer
annotation on each @Embeddable
property.
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 @ElementCollection
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 buildBaseMapping()
in 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.
@Type
with optional scalars@Target
with optional embeddables- Specify
targetEntity
attribute with the@OneToX
and@ManyToX
annotations.
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.
Conclusion
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.
Footnotes
-
I am leaning more towards JOOQ at this point. The whole API seems really cool. ↩
-
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. ↩
-
Although the
Type
has a field calleddefaultForType
, it won’t be very useful since it can’t work with generic types due to java’s erasure. The type-erasure keeps getting in the way, all the time. ↩ -
It’s deprecated in favor of the
@Access
, I know. However, the Hibernate docs still point out that it is still useful if you want to provide a custom property-access strategy. ↩ -
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. ↩
-
Some relevant discussion at this link, and this stack-overflow answer ↩
-
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. ↩
comments
comments powered by Disqus