I'm writing a web app using Kotlin + Ninja Framework, which bundles JPA/Hibernate and Guice Persist together. Lots and lots of annotation and bytecode synthesis magic is going on behind the scenes. My app was originally written in Java and I used the J2K tool to convert the code.
I discovered through a lot of debugging that when I converted my data access object to Kotlin, it was of course made final by default, and this broke things such that database writes just silently disappeared. No exceptions or errors were printed. Writes just … didn’t work.
Eventually I tracked down the problem by converting my DAO back to Java, eliminating every difference betwen the Java and Kotlin I could spot and then examining the bytecode by hand. Of course the code looked identical at the source level.
I’ve filed a bug with Guice Persist on the assumption that this is where the bug lies (the bug being: it should throw an exception that tells you what to fix). I also filed a bug to request that IntelliJ notice the presence of @Inject and suggests that the class be declared open, as a static analysis hint. Until then, if anyone else is trying the same thing - watch out!
Another few gotchas:
- Entity classes cannot have the [data] annotation, because that generates a final copy() method EVEN if the class is marked open. If there are any final methods at all, the magic seems to fail.
- If you define an id field as Long, things will just not work again. Because ... it's expecting a Long object, and although it looks like what you get of course kotlin converts it into a primitive. You can force it by making the field nullable.
- You can annotate fields in the constructors but you have to remember to use square brackets
A simple entity:
entity open class Promise(
[Id] [GeneratedValue] open var id: Long? = null,
open var name: String? = null,
[Email] open var email: String? = null,
[Min(value = 0)] open var amount: Int = 0,
open var publicName: Boolean = false