Issue
As JPA requires, @Entity
classes should have a default (non-arg) constructor to instantiate the objects when retrieving them from the database.
In Kotlin, properties are very convenient to declare within the primary constructor, as in the following example:
class Person(val name: String, val age: Int) { /* ... */ }
But when the non-arg constructor is declared as a secondary one it requires values for the primary constructor to be passed, so some valid values are needed for them, like here:
@Entity
class Person(val name: String, val age: Int) {
private constructor(): this("", 0)
}
In case when the properties have some more complex type than just String
and Int
and they're non-nullable, it looks totally bad to provide the values for them, especially when there's much code in primary constructor and init
blocks and when the parameters are actively used -- when they're to be reassigned through reflection most of the code is going to be executed again.
Moreover, val
-properties cannot be reassigned after the constructor executes, so immutability is also lost.
So the question is: how can Kotlin code be adapted to work with JPA without code duplication, choosing "magic" initial values and loss of immutability?
P.S. Is it true that Hibernate aside of JPA can construct objects with no default constructor?
Solution
As of Kotlin 1.0.6, the kotlin-noarg
compiler plugin generates synthetic default construtors for classes that have been annotated with selected annotations.
If you use gradle, applying the kotlin-jpa
plugin is enough to generate default constructors for classes annotated with @Entity
:
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
}
}
apply plugin: "kotlin-jpa"
For Maven:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>jpa</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
Answered By - Ingo Kegel
Answer Checked By - Timothy Miller (JavaFixing Admin)