I have an @Embeddable with two fields, both of which on the object model are defined non-nullable (a String and an OffsetDateTime). In the database I added two nullable columns for this because I want the Embeddable itself to be optional (nullable). This seems to work as expected.
Now, I am trying to force an error by setting the String column in the database to null and would expect Kotlin to raise a NullPointerException when the object is loaded from the database. Interestingly enough this does not happen. When the entity is translated to a DTO (both fields are also defined as non-nullable), the NullPointerException is thrown but a little too late in my mind.
Watching this in the debugger I can see that the String field in the entity is indeed null, even though Kotlin's null safety feature should prohibit this.
What am I missing?
Reflection in Java is the culprit in the case you are noticing. It still surprised me to see this. I've been working in Kotlin server-side for a while with spring and JPA unfortunately displays this behavior.
I have a project on GitHub that contains code that I have created to observe this phenomenon. In this module Car Parts Kotlin, I have created a very simple REST controller, service and data layers and I am explicitly saying in the domain that
Partonly accepts a non-nullablename:So
idcan be null andnamecannot. Before I start the test services, I'm inserting a row in thePARTStable with null for the value ofname. This is the content ofdata.sql:The whole example isn't really important to have a look at. Let's just focus on what is important. For this question let's focus on the example for the tests on
CarPartsKotlinLauncherKotlinTest. In the beginning of the tests I'm calling the scripts necessary to create and insert data into our database:Then I also make something during runtime, this time a java class where I create an instance with
idandnamewith null values:Finally I create a test to test all of this:
What this test does, long story short, is to check that the name we get from the database is null, even though, with a non-nullable property, that should never be possible. The same goes for the value we create during runtime with Java reflection.
At the end, what we get in the console, in between, is something like this:
And I agree, this is all really bizarre. And the JPA should support Kotlin and recognize the non-nullable types. Unfortunately the Spring Framework is more prepared to work with Java and the JDK does not understand non-nullable types unless we use annotations like
@NotNulland things like that, but we still need Spring for that to work. Interoperability still has this problem unfortunately even though when Kotlin uses Java classes, some of the@NotNullannotations work even without Spring. There isn't much more to understand than that. I do hope that the Spring Framework standardizes this so that we don't get these kind of surprises while coding. The argument for that to be done as soon as possible is only IMO, that by allowing a null to be assigned to a Kotlin non-nullable type, people may take advantage of a rare situation where you can effectively read this kind of data any way from the database. This can lead to things like postponing data migration tasks, creating business logic wrongly around it and even creating non reliable tests.