Quarkus: CRUD using Hibernate ORM and Panache

Reading Time: 3 minutes

In this blog, we will be performing basic CRUD operations in a database so nothing new here right? Well you’ve already read the title I believe so I have already spoiled it for you. We will be using Hibernate ORM and Panache to further simplify and reduce the boilerplate code. We will also see how easy it is to create a simple CRUD application using Quarkus. For those of you who are new to Quarkus, here is a quick start guide for you: QuickStart with Quarkus!. For now, just assume it to be similar to spring-boot and you already have knowledge about JPA and Java enterprise annotations. Enough of the intro now let’s start with our application.

Setting up Quarkus project

To start with the project let’s first visit Quarkus Starter page. This page, you might find similar to the Spring Starter page. Create your skeleton project template from here. Add the following basic dependencies:

  • quarkus-resteasy
  • quarkus-resteasy-jackson
  • quarkus-jdbc-h2
  • quarkus-hibernate-orm-panache
  • lombok

I am also attaching the dependency list from my POM that I used:

<dependencies>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-jdbc-h2</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-hibernate-orm-panache</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-vertx</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-undertow</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

Once, you have finished setting up the project, click on “generate your application”. This will download the zipped version of your project. Import the project to your preferred IDE. Once imported, make sure your project compiles correctly. If you face any issue with dependencies try to refresh maven sources. Once your project build is successful, let’s proceed to the next step.

Database Configuraion

In this project, we will be using an H2 database for performing our CRUD operations. Add the following configurations to your src/main/resources/application.properties

quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:import.sql'
quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
quarkus.hibernate-orm.log.sql=true

Next, let’s define the import.sql which will create our DB.

create table students (
       id bigint auto_increment,
       first_name varchar(255),
       last_name varchar(255),
       primary key (id)
    );

INSERT INTO students (first_name, last_name) VALUES ('first', 'person');
INSERT INTO students (first_name, last_name) VALUES ('second', 'person');
INSERT INTO students (first_name, last_name) VALUES ('third', 'person');

This will create a student table and add three entries to it every time you start the application. At this point, you can try starting the application using ./mvnw quarkus:dev

Now let’s move on to the next step.

CRUD implementation

Let’s start with defining our entity class. Here, we will be using Panache to define our entity class. It should look something like this:

package org.knoldus.Application.entity;

import javax.persistence.*;

import io.quarkus.hibernate.orm.panache.PanacheEntityBase;

@Entity
@Table(name = "students")
public class StudentEntity extends PanacheEntityBase {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;

    @Column(name="first_name")
    public String first_name;

    @Column(name="last_name")
    public String last_name;
}

We will be able to access our database using this Entity class. Next, let’s create a service class that will contain the logic for our CRUD implementation. For, that let’s first create a student model to be used in the service class.

package org.knoldus.Application.model;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Student {
    private Long id;
    private String first_name;
    private String last_name;

    public Student(Long id, String first_name, String last_name) {
        this.id = id;
        this.first_name = first_name;
        this.last_name = last_name;
    }
}

Let’s use this model to implement our service class logic:

package org.knoldus.Application.service;

import org.knoldus.Application.entity.StudentEntity;
import org.knoldus.Application.model.Student;

import java.util.List;
import java.util.stream.Collectors;

import javax.enterprise.context.ApplicationScoped;
import javax.transaction.Transactional;
import javax.ws.rs.core.Response;

@ApplicationScoped
public class StudentService {
    public List<Student> get() {
        List<StudentEntity> listAll = StudentEntity.findAll().list();
        return listAll.stream().map(ie -> {
            return new Student(ie.id, ie.first_name, ie.last_name);
        }).collect(Collectors.toList());
    }

    @Transactional
    public StudentEntity create(Student student) {
        StudentEntity studentEntity = new StudentEntity();
        studentEntity.first_name = student.getFirst_name();
        studentEntity.last_name = student.getLast_name();
        studentEntity.persist();
        return studentEntity;
    }

    @Transactional
    public StudentEntity update(Student Student) {
        StudentEntity entity = StudentEntity.findById(Student.getId());
        entity.first_name = Student.getFirst_name();
        entity.last_name = Student.getLast_name();
        return entity;
    }

    @Transactional
    public void delete(Long id) {
        StudentEntity.deleteById(id);
    }
    
}

This service class will perform the CRUD operations on StudentEntity. Lastly, we will have to define four endpoints to call each of these methods to perform this logic. We will define these endpoints in our controller class. Let’s create that:

package org.knoldus.Application.controller;

import org.knoldus.Application.entity.StudentEntity;
import org.knoldus.Application.model.Student;
import org.knoldus.Application.service.StudentService;

import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;

@Path("/student")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class StudentController {

@Inject
StudentService studentService;

@GET
public List<Student> get() { return studentService.get();}
@POST
public StudentEntity create(Student student){
StudentEntity studentEntity = studentService.create(student);
return studentEntity;
}

@PUT
public StudentEntity update(Student student){
StudentEntity studentEntity = studentService.update(student);
return studentEntity;
}
@DELETE
@Path("{id}")
public void delete(@PathParam("id") Long id){
studentService.delete(id);
}

}

Finally, our application is ready. Let’s test and see for ourselves. First, let’s run the app using:

./mvnw quarkus:dev

Now, Open up Postman to hit these endpoints and check if they work as expected. The URL should be:

http://localhost:8080/student

GET will fetch all student data from the database.
POST will create the student provided in the request body.

Sample POST body:

{
    "first_name": "created",
    "last_name": "student"
}

PUT will update a given entry provided in the request body.

Sample PUT body:

{
    "id": "4",
    "first_name": "edited",
    "last_name": "student"
}

DELETE should have the id along with the endpoint(http://localhost:8080/student/4). It will delete the entry in that particular id.

That’s all folks. That’s how easy it is to create a CRUD implementation using Quarkus.

For reference, you can also use my project present in Knoldus TechHub.

For more such interesting blogs on Quarkus and other various technologies please visit Knoldus Blogs.


Written by 

Agnibhas Chattopadhyay is a Software Consultant at Knoldus Inc. He is very passionate about Technology and Basketball. Experienced in languages like C, C++, Java, Python and frameworks like Spring/Springboot, Apache Kafka and CI/CD tools like Jenkins, Docker. He loves sharing knowledge by writing easy to understand tech blogs.