The implications of JPA always manage to surprise me. Yesterday a colleague of mine made me aware of a warning in IntelliJ. The conversation went like that: “Marcus, in your blog you explained that we should check constraints in the constructor instead of bean validation”. Me: “yeah”. “I wanted to make it right, but when I do it in this entity IntelliJ warns me with
Accessing non-final property name in constructor”. So I dug into it. Fearing my conclusion would change the recommendation that I gave in (k)lean JPA two years ago.
But first, let’s look at an example how an Entity looks like when you follow my recommendations:
The warning is on
name.isNotEmpty(). It states: Accessing non-final> property name in constructor. But - this member is final by default in Kotlin, you correctly state.
Right. I reasoned that we must configure the all-open compiler plugin, so JPA does not silently fetch all relations eager. And this is what I do in all my projects.
So the code the compiler sees actually looks like this:
And that’s why IntelliJ warns that we access a non-final property in the constructor.
Why is the inspector warning us?
We can construct scenarios where the access to inherited properties might not be fully initialized and therefore result in an unexpected value.
Fine, should we remove the all-open plugin?
Is it necessary to have the members open? Yes! We need all members to be open. Check this example:
When we fetch the
Person we see the following logs:
So, even when we specified that the relations should be fetched lazy - Hibernate did not do it. Instead, when we declare all properties
open we see the expected select - just the
At least, this time Hibernate prints a warning when booting issuing that the members must be open.
The only right way to deal with the warning is:
Yes, this is frustrating. But there is no other alternative. At least constructing such an issue which the inspection warns us against is unlikely with entities. We would need to derive values from inherited properties. It’s hard for me to construct such a scenario.
And to close with an important note. This is not an issue with kotlin. You have the same issue with Java. You actually have the issue all the time because all members are non-final by default. You just don’t have an inspection warning you against it - since it would be super annoying ;-)