CRUD using Spring Boot, Kotlin and JPA

In this tutorial, we will explore how to update data in a table using Spring Boot, Kotlin, and the Java Persistence API (JPA). We will build a simple example that demonstrates the process step by step. By the end of this tutorial, you will have a clear understanding of how to update data in a table using these technologies.

Prerequisites

To follow along with this tutorial, you should have the following:

  • Basic knowledge of Kotlin
  • Basic knowledge of Spring Boot
  • JDK 1.8 or higher installed
  • Spring Boot 2.0 or higher
  • A relational database (e.g. PostgreSQL) with a table that you want to update

Setting up the Project

Let’s start by setting up a new Spring Boot project with Kotlin and JPA. Follow the steps below:

  1. Open Spring Initializr and select Kotlin as your language
  2. Select the following dependencies: Spring Web, Spring Data JPA, PostgresQL Driver
  3. Generate the project
  4. Open the application.properties file and configure the database connection settings according to your setup. For example:


    Replace the jdbc:postgresql://localhost:5432/mydatabase with your database URL, and provide the correct username and password.
spring.datasource.url=jdbc:postgresql://localhost:5432/mydatabase
spring.datasource.username=username
spring.datasource.password=password

Creating the Entity

In this tutorial, we will assume that you have an existing table called users in your database that you want to update. Let’s create a corresponding entity class in Kotlin.

Step 1: Create a new Kotlin class called Library:

import jakarta.persistence.*

@Entity
class Library {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null
    var name: String? = null
    var email: String? = null
    var website: String? = null
    var address: String? = null
}

The User class is annotated with @Entity to indicate that it is a JPA entity. The @Table annotation specifies the table name in the database.

Step 2: Define the properties of the User class. In this example, we have id, name, email, website and address fields. The id field is annotated with @Id and @GeneratedValue to indicate it as the primary key and to generate its value automatically.

Creating the Repository

Next, we need to create a repository interface that extends the JpaRepository interface provided by Spring Data JPA. This interface will provide the necessary methods to perform database operations on the Library entity.

Step 1: Create a new Kotlin interface called LibraryRepository:

import org.springframework.data.jpa.repository.JpaRepository

@Repository
interface LibraryRepository : JpaRepository<Library, Long>

The UserRepository interface extends JpaRepository and specifies the User entity class and the type of the primary key (Long in this case).

Updating Data in the Table

With the entity and repository in place, we can now update data in the library table.

Step 1: In your application code, inject an instance of the LibraryRepository into a service or controller class where you want to update the data. For example:

import org.springframework.stereotype.Service

@Service
class LibraryService(
    private val libraryRepository: LibraryRepository
) {
    fun create(library: Library): Library {
        return libraryRepository.save(library)
    }

    fun findOneOrThrow(id: Long): Library {
        return libraryRepository.findById(id).orElseThrow { NoSuchElementException("No Library found with id $id") }
    }

    fun update(id: Long, library: Library): Library {
        val libraryToUpdate = findOneOrThrow(id)

        libraryToUpdate.website = library.website
        libraryToUpdate.address = library.address
        libraryToUpdate.email = library.email
        libraryToUpdate.name = library.name

        return libraryRepository.save(libraryToUpdate)
    }

    fun delete(id: Long) {
        libraryRepository.deleteById(id)
    }
}

In this service we have functions for creating, updating and deleting a Library, as well as get one by id.

Now all that we are missing is a Controller that can handle requests coming in and the DTOs (Data Transfer Object) to send data.

Let’s create a file called LibraryDtos.kt:

class LibraryParam {
    var name: String? = null
    var email: String? = null
    var website: String? = null
    var address: String? = null

    fun toEntity(): Library {
        val entity = Library()
        entity.name = this.name
        entity.email = this.email
        entity.website = this.website
        entity.address = this.address
        return entity
    }
}

class LibraryResponse() {
    var id: Long? = null
    var name: String? = null
    var email: String? = null
    var website: String? = null
    var address: String? = null

    constructor(library: Library): this() {
        this.id = library.id
        this.name = library.name
        this.email = library.email
        this.website = library.website
        this.address = library.address
    }
}

And then the LibraryController.kt:

import org.springframework.stereotype.Service

import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("library")
class LibraryController(
    private val libraryService: LibraryService
) {

    @PostMapping
    fun create(@RequestBody param: LibraryParam): LibraryResponse {
        return LibraryResponse(libraryService.create(param.toEntity()))
    }

    @GetMapping("{id}")
    fun get(@PathVariable id: Long): LibraryResponse {
        return LibraryResponse(libraryService.findOneOrThrow(id))
    }

    @PutMapping("{id}")
    fun update(@PathVariable id: Long, @RequestBody param: LibraryParam): LibraryResponse {
        return LibraryResponse(libraryService.update(id, param.toEntity()))
    }

    @DeleteMapping("{id}")
    fun delete(@PathVariable id: Long) {
        libraryService.delete(id)
    }
}

And that’s it. You now have an API that serves CRUD endpoint for maintaining library records in a database. You can try the endpoints yourself:
Create: POST localhost:8080/library
Read: GET localhost:8080/library/<id>
Update: PUT localhost:8080/library/<id>
Delete: DELETE localhost:8080/library/<id>

About the Author

You may also like these