Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin with JPA/Hibernate: no lazy-loading without `open`?

Most Kotlin JPA example code looks like this

class Person(val name: String, val age: Int) { /* ... */ }

or even

data class Person(val name: String="", val age: Int=0) { /* ... */ }

Now, the Hibernate User Guide, and I think also several other ORMs, state that they usually want to create proxies or otherwise extend the model class, but to allow that in Kotlin the class has to be explicitly defined open. This is currently impossible with data classes and I assume, judging from my own experience, that most people don't think about it when writing JPA entities in Kotlin.

So, to come to my question (this is stackoverflow after all), is it enough to do

 open class Person(val name: String, val age: Int) { /* ... */ }

or would we actually have to do

 open class Person(open val name: String, open val age: Int) { /* ... */ }

to not needlessly hinder the ORM at doing its job properly?
If it really is harmful, we should probably propose to add a warning to IntelliJ IDEA, that if a class is has an @Entity annotation, it should be defined open.

like image 426
johnp Avatar asked Jun 09 '16 18:06

johnp


People also ask

How does lazy loading work in JPA?

LAZY it is interpreted as a hint to the JPA provider that the loading of that field may be delayed until it is accessed for the first time: the property value in case of a @Basic annotation, the reference in case of a @ManyToOne or a @OneToOne annotation, or.

Does JPA entity need constructor?

Rules for JPA Entities 1. The entity class must have a no-arg constructor. The entity class may have other constructors as well. The no-arg constructor must be public or protected.

What is Enable_lazy_load_no_trans?

enable_lazy_load_no_trans configuration parameter in the persistence. xml file to true. This parameter tells Hibernate to open a temporary Session when no active Session is available to initialize the lazily fetched association.

What is lazy loading in Spring JPA?

With a LAZY type dependency, only data of the wanted object is loaded: author's data is not retrieved. With Spring Data JPA, every relationship between 2 domain objects owns one of these data loading types. By default, the method will be determined by the relationship type.


1 Answers

The tutorial you provided specifies:

The entity class must have a public or protected no-argument constructor ... Interface may not be designated as an entity ... The entity class must not be final. No methods or persistent instance variables of the entity class may be final.

Kotlin classes follow the JavaBeans convention for setters/getters.

If your ORM has requirements as the above, then you indeed have to specify open on the class and its methods:

open class Person(open val name: String = "", 
                  open val age: Int = 0)

The default values for all of the constructor parameters allow Kotlin to generate an additional empty constructor. Alternatively you can provide it as a secondary constructor:

open class Person(open val name: String, open val age: Int) {
    constructor() : this("", 0)
}

Note that open val creates a private final field and an open getter. If that's not enough, use annotations like @JvmField open val name.

ORMs like the on you use have additional friction with Kotlin code because of the questionable design patterns they use (like making everything non-final).

A good option is to use a Kotlin-specific ORM. For example Exposed is supported by JetBrains and used for some of its products, which speaks for itself. Another option is Ebean which officially supports Kotlin (thanks @johnp)

like image 192
voddan Avatar answered Oct 11 '22 14:10

voddan