The short answer is no.
A class needs to have a constructor and if we do not declare a constructor, then the compiler generates a default constructor. A class in Kotlin can have at most one primary constructor, and one or more secondary constructors.
All persistent classes must have a default constructor (which can be non-public) so that Hibernate can instantiate them using Constructor. newInstance() . It is recommended that you have a default constructor with at least package visibility for runtime proxy generation in Hibernate.
In Kotlin, a class can have a primary constructor and one or more additional secondary constructors.
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>
just provide default values for all arguments, Kotlin will make default constructor for you.
@Entity
data class Person(val name: String="", val age: Int=0)
see the NOTE
box below the following section:
https://kotlinlang.org/docs/reference/classes.html#secondary-constructors
@D3xter has a good answer for one model, the other is a newer feature in Kotlin called lateinit
:
class Entity() {
constructor(name: String, age: Date): this() {
this.name = name
this.birthdate = age
}
lateinit var name: String
lateinit var birthdate: Date
}
You would use this when you are sure something will fill in the values at construction time or very soon after (and before first use of the instance).
You will note I changed age
to birthdate
because you cannot use primitive values with lateinit
and they also for the moment must be var
(restriction might be released in the future).
So not a perfect answer for immutability, same problem as the other answer in that regard. The solution for that is plugins to libraries that can handle understanding the Kotlin constructor and mapping properties to constructor parameters, instead of requiring a default constructor. The Kotlin module for Jackson does this, so it is clearly possible.
See also: https://stackoverflow.com/a/34624907/3679676 for exploration of similar options.
Adding the JPA plugin in gradle worked for me:
plugins {
id("org.springframework.boot") version "2.3.4.RELEASE"
id("io.spring.dependency-management") version "1.0.10.RELEASE"
kotlin("jvm") version "1.3.72"
kotlin("plugin.spring") version "1.3.72"
kotlin("plugin.jpa") version "1.3.72"
}
@Entity data class Person(/*@Id @GeneratedValue var id: Long? = null,*/
var name: String? = null,
var age: Int? = null)
Initial values are requires if you want reuse constructor for different fields, kotlin doesn't allowed nulls. So whenever you planning omit field, use this form in constructor: var field: Type? = defaultValue
jpa required no argument constructor:
val entity = Person() // Person(name=null, age=null)
there is no code duplication. If you need construct entity and only setup age, use this form:
val entity = Person(age = 33) // Person(name=null, age=33)
there is no magic (just read documentation)
I'm a nub myself but seems you have to explicit initializer and fallback to null value like this
@Entity
class Person(val name: String? = null, val age: Int? = null)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With