Mapping JPA entities with Kotlin 
Tags: development, jpa, kotlin
Published: 2017-11-10 00:00:00

---
title: Mapping JPA entities with Kotlin
published: true
description: 
tags: Development, JPA, Kotlin
date: 2017-11-10
---

[1]: https://kotlinlang.org/
[2]: https://www.jetbrains.com/
[3]: https://kotlinlang.org/docs/reference/data-classes.html#data-classes
[4]: https://kotlinlang.org/docs/reference/compiler-plugins.html#no-arg-compiler-plugin
[5]: https://kotlinlang.org/docs/reference/compiler-plugins.html#jpa-support

[Kotlin][1] is a very interesting programming language created by [JetBrains][2] that runs on the JVM. One of its features is [data classes][3], which are classes whose main purpose is to hold data. One might think that data classes are perfect to map database entities, and they are actually very good, but you will to think a little more in order to use them correctly with JPA.

Data classes automatically implement `toString()`, `equals()` and `hashCode()` based on the properties defined in the primary constructor. Because of this, you need to think about what properties should be used to tell whether two objects are equal or not.

There is one caveat when using data classes with JPA: data classes require a primary constructor with at least one parameter and JPA requires a constructor without arguments. To help with this, Kotlin has the [no-arg compiler plugin][4] that generates a zero-argument constructor that can only be called using reflection. Kotlin also provides the [jpa plugin][5] that wrapps the `no-arg` plugin configured for JPA.

Let's take the following schema of a task list application:

```sql
CREATE TABLE IF NOT EXISTS "task_list" (
    "id" SERIAL PRIMARY KEY,
    "name" VARCHAR(200) NOT NULL
);

CREATE TABLE IF NOT EXISTS "task" (
    "id" SERIAL PRIMARY KEY,
    "task_list_id" INTEGER NOT NULL,
    "name" VARCHAR(200) NOT NULL,
    "description" TEXT,
    "due_date" DATE,
    "done" BOOLEAN DEFAULT FALSE,

    FOREIGN KEY ("task_list_id") REFERENCES "task_list" ("id")
);
```

For this schema, we can see that we will need two entities: `TaskList` and `Task`. First let's map the `TaskList`:

```kotlin
package com.example.domain

import javax.persistence.*

@Entity
data class TaskList(
    @Id @GeneratedValue
    val id: Int = 0,
    val name: String
) {
    @OneToMany(mappedBy = "taskList")
    val tasks: MutableSet<Task> = HashSet()
}
```

The `id` and `name` properties are defined in the primary constructor, but `tasks` is defined in the class body. This way, only `id` and `name` are used for `equals()`, `hashCode()` and `toString()`. Since `tasks` maps a relationship, it is better to left it out of the primary constructor.

Now to the `Task`:

```kotlin
package com.example.demo.domain

import java.time.LocalDate
import javax.persistence.*

@Entity
data class Task(
    @Id @GeneratedValue
    val id: Int = 0,
    val name: String,
    val description: String? = null,
    val dueDate: LocalDate? = null,
    val done: Boolean = false
) {
    @ManyToOne
    lateinit var taskList: TaskList

    constructor(name: String, taskList: TaskList) : this(name = name) {
        this.taskList = taskList
    }
}
```

Same way with `TaskList`, but now we have the inverse relationship with `Task`. We define the attribute `taskList` as `lateinit` for two reasons: first, because it will be lazy loaded; and second, so we do not need to initialize it right away, but we assign it on the secondary constructor.

If we put all the attributes in the primary constructor, simply calling `println(task)` would cause our application to crash with a infinite recursion because `Task::toString()` would call `TaskList::toString()` that would call `Task::toString()` and so on.