Kotlin-jpa compiler plugin
The kotlin-jpa compiler plugin configures Kotlin projects for the Java Persistence API (JPA). JPA has two requirements that conflict with Kotlin's defaults:
A zero-argument constructor. JPA instantiates entities through reflection (a process called hydration), which requires a zero-argument constructor. Kotlin classes don't declare one by default.
Non-final classes. JPA providers create proxy subclasses of your entities to support lazy loading (for example, for
@ManyToOneand@OneToOneassociations). Kotlin classes and their members arefinalby default, which prevents this. If entities aren'topen, lazy loading won't work.
The kotlin-jpa plugin addresses both. It's a preconfigured wrapper that applies:
The
no-argplugin to generate a zero-argument constructor for JPA-annotated classes.The
all-openplugin to make JPA-annotated classes and their membersopen.
The generated constructor is annotated with @Deprecated at the HIDDEN level, so you can call it from Java but not from Kotlin. JPA can call it through reflection.
Supported JPA annotations
JPA annotations exist in two package namespaces: the older javax.persistence (Java EE) and the newer jakarta.persistence (since Jakarta EE 9, used by Spring Boot 3.x and later). The kotlin-jpa plugin recognizes both namespaces and specifies the following annotations automatically for the underlying no-arg and all-open plugins:
javax.persistence.Entityandjakarta.persistence.Entityjavax.persistence.Embeddableandjakarta.persistence.Embeddablejavax.persistence.MappedSuperclassandjakarta.persistence.MappedSuperclass
Use the annotations from the namespace that matches your framework version. You don't need to configure the plugin for either namespace: both are enabled by default.
Apply the plugin
Gradle
Add the kotlin-jpa plugin in the plugins {} block of your build.gradle(.kts) file:
Maven
In Maven, support for the kotlin-jpa plugin is provided by the kotlin-maven-noarg plugin. Add it to your pom.xml file:
Use the kotlin-jpa plugin
When the plugin is applied, classes annotated with common JPA annotations become open and get a zero-argument constructor at compile time. You can write entities as regular classes without adding the open keyword or declaring a zero-argument constructor manually.
The following example uses the jakarta.persistence namespace. If your framework still uses Java EE, import the same annotations from javax.persistence instead and the plugin handles both:
Best practices for JPA entities
Applying the plugin makes entities open and gives them a zero-argument constructor, but a few Kotlin idioms still conflict with how JPA providers manage entities. Follow these guidelines to avoid common issues:
Use a regular class, not a
data class. Data classes favor immutablevalproperties, and deriveequals(),hashCode(), andtoString()from all properties. For entities, this breaks proxies, andtoString()orequals()can trigger extra queries on lazy associations. Model entities as regular classes (the plugin makes themopen) and reserve data classes for DTOs and query results.Declare mapped properties as
var. JPA sets fields when hydrating an entity, so mapped properties must be mutable.Make generated identifiers nullable and mutable. A
@GeneratedValueidentifier isnulluntil the entity is persisted, so declare it asvar id: Long? = null.Base
equals()andhashCode()only on the identifier and type, not on all properties. This keeps them stable across the entity lifecycle and avoids loading lazy fields.
For a detailed discussion of these pitfalls, see the How to avoid common pitfalls with JPA and Kotlin blog post.
Cover classes without JPA annotations
The kotlin-jpa plugin configures only supported JPA annotations. To generate a zero-argument constructor or make classes open for types that aren't annotated with a JPA annotation, declare your own annotation and register it with the underlying no-arg and all-open plugins:
Declare your own annotation:
package com.example annotation class OpenNoArgAnnotationIn your build file, register the annotation with the underlying plugins:
In your
build.gradle.ktsfile, register the annotation in thenoArg {}andallOpen {}blocks that are available through thekotlin-jpaplugin:plugins { kotlin("jvm") version "2.4.21" kotlin("plugin.jpa") version "2.4.21" } noArg { annotation("com.example.OpenNoArgAnnotation") } allOpen { annotation("com.example.OpenNoArgAnnotation") }In your
build.gradlefile, register the annotation in thenoArg {}andallOpen {}blocks that are available through thekotlin-jpaplugin:plugins { id "org.jetbrains.kotlin.jvm" version "2.4.21" id "org.jetbrains.kotlin.plugin.jpa" version "2.4.21" } noArg { annotation("com.example.OpenNoArgAnnotation") } allOpen { annotation("com.example.OpenNoArgAnnotation") }In your
pom.xmlfile, add theno-arg:annotationandall-open:annotationoptions to thekotlin-maven-pluginconfiguration:<properties> <kotlin.version>2.4.21</kotlin.version> </properties> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>${kotlin.version}</version> <configuration> <compilerPlugins> <plugin>jpa</plugin> </compilerPlugins> <pluginOptions> <!-- Add multiple lines for multiple annotations --> <option>no-arg:annotation=com.example.OpenNoArgAnnotation</option> <option>all-open:annotation=com.example.OpenNoArgAnnotation</option> </pluginOptions> </configuration> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-noarg</artifactId> <version>${kotlin.version}</version> </dependency> </dependencies> </plugin>Mark the classes that don't have a JPA annotation:
package com.example import jakarta.persistence.Entity import jakarta.persistence.GeneratedValue import jakarta.persistence.Id // Automatically covered by the kotlin-jpa plugin @Entity class Message( var text: String, ) { @Id @GeneratedValue var id: Long? = null } // The custom annotation makes the class open // and generates a zero-argument constructor @OpenNoArgAnnotation class MessageMetadata( var author: String, )
What's next?
Read the blog post on how to avoid common entity-mapping issues.
For Spring applications that require classes to be
open, use thekotlin-springplugin, which configures theall-openplugin with Spring annotations such as@Component,@Transactional, and@Configuration.Create your first Spring Boot application using the Get started with Spring Boot and Kotlin tutorial.