I would to build an immutable domain model, and data classes are perfect for that.
JPA specifies that all entities should provide a non arg empty constructor for reflection.
Currently, on Kotlin data classes, there’s two ways:
Provide default values for all argument in constructor.
Provide a secondary non arg constructor, calling the primary constructor passing imaginary values.
In my opinion, the number 1 solution isn’t a good design to prevent inconsistent object state.
The solution number two is an inelegant hack.
The possible solution:
I think, that a good solution would be an additional modifier annotation, to build a data class able to reflection, generating an empty constructor on JVM, initializing all properties with the same principle of lateinit. This will not compromise the nullability.
Looks like you’re contradicting yourself. A data class with a default no-arg constructor that does not set any initial values to any properties is anything but immutable. And there is absolutely no way to prevent inconsistent object state if we generate such a constructor.
Using JPA, I can build immutable entities with data classes (using only val properties), see this:
This works very fine! See my entire demo on github.
Look that, although immutable and instantiated by a secondary private non arg constructor (calling the primary, providing imaginary values), JPA makes a magic trick and delivers me a beautiful entity with all correct values.
Even though, id is a val, JPA will save the correct value id on data base.
Sounds crazy but, this entity is immutable to me, is immutable to compiler, but isn’t immutable to JPA. (It’s a desired behavior.)
I’m assuming that JPA will never deliver me an entity inconsistent (i.e. with the default values provided by me), always reflecting all entity properties values to the correct ones.
My propose is:
A modifier annotation generates an additional non arg constructor only in bytecode .class
This constructor only can be called by reflection.
When this constructor is called, they instantiate an object with all properties no initialized. (Kotlin lateinit principle). JPA don’t care about this.
In this moment, if any property is accessed, it should throw a special exception that clearly identifies the property being accessed and the fact that it hasn’t been initialized. Like lateinit.We could say that in this particular moment, the object is in limbo.
Who called this constructor (by reflection), either JPA or whatever, should be responsible to provide a value through reflection to every property before delivers the object. JPA already did this.
I just want to suppress the necessity of write a secondary private non arg constructor passing imaginary arguments to primary.
There is no possibility to enforce that a constructor can only be called by reflection. If the constructor is in the .class file, then it will be visible to Java code, and Java code will be able to call it.