We are also able to give JOOQ our domain model and let it automatically figure out the mapping from the query into the domain model. JOOQ can do automatically match this based on existing JPA annotations in the domain model, the “best-matching constructor” or a custom mapper you provide yourself.
In our project we only used the metadata constants, while JOOQ has more to offer. JOOQ also generates DAO’s for instance. We investigated implementing the generated DAO’s in our project, but they included default methods that we considered not useful. For instance, a method was generated to look up experiments by (alphabetic) range of hypothesis. It seems this ‘select by range’ is generated for all fields and creates clutter.
Besides, the generated DAO code does not seem to take indexes into account. Most of the queries would lead to a full table scan if they were used, which can heavily impact performance. We see room for improvement here: JOOQ could use the indexes as an indicator of whether there is any use case for the code and leave a more concise DAO. This is one of the reasons we focussed our efforts on using the metadata constants.
Our conclusion about JOOQ:
- JOOQ’s documentation is elaborate and makes the framework easy to use. Especially if you have an existing database schema or plan on using a database migration tool like Flyway.
- The metadata constants can be a nice type-safe query implementation, based on your existing database. Because of this we were able to implement JOOQ with minimal boilerplate code regarding mappings to the data access layer.
- JOOQ is actively maintained with monthly releases and is the most used ORM framework after Hibernate within bol.com.
- One additional note is that JOOQ has multiple paid versions, that offer a wider range of supported database dialects and more features. Our database type, Postgres, among other common ones are supported in the open-source version. Popular databases like Oracle and SQL Server are only supported in the paid versions.
Noteworthy mention: Krush
The extra added boilerplate in mapping between the domain model and the table model with Exposed and Ktorm encouraged us to look for an alternative, onto which we encountered Krush.
Krush is based on Exposed and claims to be “a lightweight persistence layer for Kotlin based on Exposed SQL DSL.”. It removes the need for boilerplate mappings by adding back JPA annotations to the domain model, which we are used to from Hibernate.
Unfortunately, there is no usage of this framework within bol.com and on GitHub the community also seems too small to consider for usage in production. Because of this, we concluded that we would not go to the extent of testing its behaviour. Instead, we will give Krush a close look from time to time to see how it develops.
Noteworthy mention: Spring JDBC
You might not need all the complexity that Hibernate/JPA has to offer. Switching to a different ORM framework altogether can be heavy as well. What if there would just be a simpler alternative in the ecosystem you are already using? One such alternative is available in all Spring projects: Spring JDBC!
Spring JDBC will offer you a more low-level approach, based on JDBC directly. This can be a good approach for smaller projects that want to write native queries.
Joining forces in the bol.com hackathon to investigate Hibernate alternatives in Kotlin was fun and we learned a lot about the available alternatives out there. Our biggest learning is that there are four major ways of approaching the ORM world:
- Database schema first, the approach that JOOQ takes.
- SQL DSL first, the approach that Exposed and KTORM take.
- JPA annotations first, the approach that Hibernate and Krush take.
- Low level, the approach that Spring JDBC takes.
All these approaches come with their own set of advantages and disadvantages. For our use case JOOQ could be an alternative to Hibernate in our Kotlin projects. JOOQ would allow us to switch ORM frameworks with minimal changes and maximum type-safety, while keeping boilerplate at a minimum. The community and usage also seem good enough to adopt the framework for usage within a production environment.
It is important to note that doing a migration from one ORM framework to another is a heavy process that needs dedicated time to make it work, including performance tests. Hibernate can be a valid ORM framework choice in a project. We hope that you are now more aware of some of the other frameworks you can choose from and how they work.
1 During the hackathon the project team also reserved a small amount of time to investigate alternatives for Hibernate Envers. Using a different ORM framework then Hibernate can pose a challenge when you still want to have such out of the box auditing available, as Hibernate Envers can only be used in combination with Hibernate itself. The conclusion of the small investigation was that Javers promised to be a suitable alternative, although this framework seems only maintained by one person. Alternatively, you could use a more low-level approach by using database triggers that audit and log changes.
2 A while ago Sander spent hours trying to debug problems that were related to using data classes with Hibernate, which in the end led him to the listed article and repository. An example of such a problem is that the application tried to delete an object from the database, but through Hibernates magic under the hood the object was recreated after the deletion in the same transaction, resulting in no object being deleted. Using the best practices from the listed article led to consistent results.