This tutorial is based on: Quarkus - Simplified Hibernate ORM WITH PANACHE

H2 Database Installation

For this tutorial you actually don’t need to download H2. But it’s nice to have so you can inspect your database.

  • Download the “Last Stable” version from H2 website
  • Extract the file
  • Go to h2 directory
  • Run: java -jar bin/h2-1.4.199.jar (ps: replace with appropriate version)
  • It will open the H2 Console on the browser
  • Change JDBC URL to jdbc:h2:~/panache-h2
  • Click in Connect

Let’s create our table

    create table Person (
       id bigint not null,
        birth date,
        name varchar(255),
        status integer,
        primary key (id)
    )

After you run the command above, disconnect and close H2 Console.

Creating the Maven project

mvn io.quarkus:quarkus-maven-plugin:1.7.0.CR1:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=quarkus-panache-h2 \
    -DclassName="org.acme.hibernate.orm.panache.PersonResource" \
    -Dpath="/people" \
    -Dextensions="resteasy-jsonb,hibernate-orm-panache,jdbc-h2"
cd quarkus-panache-h2

Edit src/main/resources/application.properties

# Configuration file
# key = value

# configure your datasource
quarkus.datasource.db-kind = h2
quarkus.datasource.username = sa
# quarkus.datasource.password = 
quarkus.datasource.jdbc.url = jdbc:h2:~/panache-h2
quarkus.hibernate-orm.log.sql=true

Let’s create our classes

It’s just two entities and one resource.

Status.java

package org.acme.hibernate.orm.panache;

public enum Status {
    Alive,
    Dead,
}

Person.java

package org.acme.hibernate.orm.panache;

import java.time.LocalDate;
import java.util.List;
import javax.persistence.Entity;
import io.quarkus.hibernate.orm.panache.PanacheEntity;

@Entity
public class Person extends PanacheEntity {
    public String name;
    public LocalDate birth;
    public Status status;

    public static Person findByName(String name){
        return find("name", name).firstResult();
    }

    public static List<Person> findAlive(){
        return list("status", Status.Alive);
    }

    public static void deleteStefs(){
        delete("name", "Stef");
    }
}

PanacheEntity.java already has the ID field and it extends PanacheEntityBase.java

PersonResource.java

package org.acme.hibernate.orm.panache;

import java.util.List;

import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/people")
public class PersonResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/plaintext")
    public List<Person> listAll() {
        return Person.listAll();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Person> listAllJson() {
        return Person.listAll();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Transactional
    public Response create(Person person) {
        person.persist();
        
        return Response.ok(person).status(Response.Status.CREATED).build();
    }
}

Let’s use Swagger so we can test our APIs

  • Add the following dependency to pom.xml:
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-smallrye-openapi</artifactId>
    </dependency>
    
  • Add swagger-ui to application.properties
# Let's use Swagger so we can test our APIs
quarkus.swagger-ui.always-include=true
{
  "birth": "2020-08-02",
  "name": "Bob",
  "status": "Alive"
}
  • Call the GET method to see if they were created.

!!! Important: if you pass the ID field to persist:

{
  "id": 1,
  "birth": "2020-08-02",
  "name": "Bob",
  "status": "Alive"
}

… you’ll get the error:

Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: org.acme.hibernate.orm.panache.Person

I think the error occurs because the id is set but no Person.find was used, so the entity is not attached. It’s just a guess … =)

Now let’s update our entity

  • Add to PersonResource.java
    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Transactional
    public Response update(Person person) {
        Person oldPerson = Person.findById(person.id);
        if (oldPerson == null) 
            return Response.ok(false).status(Response.Status.BAD_REQUEST).build();
        oldPerson.name = person.name;
        oldPerson.birth = person.birth;
        oldPerson.status = person.status;
        oldPerson.persist();
        return Response.ok(true).status(Response.Status.OK).build();
    }
    
  • Reload Swagger UI page and execute the PUT method:
    • Now you have to pass the ID!
    • Update Bob’s name to John
	{
	  "id": 1,
	  "birth": "2020-08-02",
	  "name": "John",
	  "status": "Alive"
	}
	
- Call the GET method again and check if the update worked.

That’s it!

And if you didn’t notice, you didn’t even need to restart Quarkus!

This is thanks to the amazing hot-reload capability that Quarkus provides! :man_dancing: :cowboy_hat_face: :sunglasses: