In May 2019, I was present in Devoxx UK event where I saw a presentation of the new Java framework from Red Hat called Quarkus, presented by Sanne Grinovero. I got interested in it, mostly because I work all day with Spring environment, and it is important to learn new technologies and see solutions from different perspectives.

So I decided to create a simple API using Quarkus. My goal in this article is to describe my development journey with the framework, what I learned, and show how software can be developed with a different tool.

Application Characteristics

To develop the API I used:

Java 11

Maven

Lombok

Quarkus 0.20.0 (together with Quarkus Hibernate Panache)

PostgreSQL database and H2 database (test scope)

Docker and Docker Compose.

Writing code

I created a tech store solution. To keep the projects simple, I used only one model, together with Lombok. Follow the Quarkus model:

@AllArgsConstructor

@NoArgsConstructor

@Data

@Entity

@Builder

public class Product extends PanacheEntity {



private String name;

private String description;

private double price;

}

As we can see, in Quarkus we extend PanacheEntity. This abstract class represents an entity with a generated Long ID. Because of that, we don't need to declare an ID attribute in the model. Besides, PanacheEntity extends PanacheEntityBase, which generates all useful database methods, like find, delete, persist, etc.

You don't need to implement a repository class in Quarkus. As shown in the official documentation, you can directly use the model class to execute database commands:

if(product.isPersistent()) product.delete();

In my project, I decided to create a class just to simplify visualization.

To initialize the database with default values I declared a bean with @ApplicationScoped, and I used the StartupEvent to be able to run my method during startup time. It's important to annotate this method with @Transactional so Quarkus can open and close transactions.

@ApplicationScoped

public class AppLifecycleBean {



private static final Logger LOGGER = LoggerFactory.getLogger("Listener bean");



@Transactional

void onStart(@Observes StartupEvent event) {

LOGGER.info("Application starting...");

createDB();

}



private void createDB() {

Stream.of(new Product("Mouse", "Really good mouse", 20),

new Product("Notebook", "Great notebook", 1000),

new Product("Keyboard", "Great keyboard", 300),

new Product("Headphones", "Great headphones", 60),

new Product( "Touchscreen", "Great screen", 500))

.forEach(product -> product.persist());

}

}

You can also just add SQL statements in import.sql file, according to the official documentation.

In the REST endpoints implementation, Since Quarkus uses JAX-RS I annotated the class with @Produces and @Consumes instead of annotating each method.

@Path("/products")

@Produces(APPLICATION_JSON)

@Consumes(APPLICATION_JSON)

public class StoreController {



@Inject

private ProductRepo productRepo;



@GET

public List<Product> getProducts() {

return productRepo.getProducts();

}



@GET

@Path("/{id}")

public Response getProductById(@PathParam("id") long id) {

if(productRepo.getProductById(id).isPresent()) return Response.ok(productRepo.getProductById(id).get()).build();

else return Response.status(NOT_FOUND).build();

}



@POST

public Response addProduct(Product newProduct) {

Product p = productRepo.addProduct(newProduct);

return Response.ok(p).build();

}



@PUT

@Path("/{id}")

public Response updateProduct(@PathParam("id") final long id, Product product) {

productRepo.updateProduct(id, product);

return Response.ok(product).build();

}



@DELETE

@Path("/{id}")

public Response deleteProduct(@PathParam("id") final long id) {

productRepo.deleteProduct(id);

return Response.noContent().build();

}

}

To finish the development, I used Docker together with Docker Compose to orchestrate the PostgreSQL container with my application. Follow below the Dockerfile:

FROM fabric8/java-centos-openjdk11-jre ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Xmx256m"

ENV AB_ENABLED=jmx_exporter COPY target/lib/* /deployments/lib/

COPY target/*-runner.jar /deployments/app.jar ENTRYPOINT [ "/deployments/run-java.sh" ]

As we can see, the target/lib folder is fully copied to the container. In Quarkus documentation is quoted: Be aware that it’s not an über-jar as the dependencies are copied into the target/lib directory.

Now the docker-compose.yml file:

version: '3.1'



services:

quarkus:

build:

context: .

dockerfile: Dockerfile

depends_on:

- postgres

ports:

- 8080:8080



postgres:

image: postgres:latest

environment:

- POSTGRES_PASSWORD=test

- POSTGRES_USER=test

- POSTGRES_DB=testdb

ports:

- "5432:5432"

My experience

During all this development I learned that Quarkus is a new open-source project, and it moves fast. I started developing with Quarkus 0.17.0, and now it’s in version 0.20.0. I could contribute to the project by opening an issue in the repository: https://github.com/quarkusio/quarkus/issues/2961.

Quarkus looks and feels like Java EE, as we could see in the REST endpoints annotations and the CDI events @Observes annotation. The extension model allows integration with third-party code. You can use the guides on the official website to start a new project and check the quickstarts projects in the Github if you have some difficulty.

You can use Quarkus to compile to native images with GraalVM, then you don't need a JRE to run your Java application. If you don't know GraalVM, I recommend you to take a look in the GraalVM official documentation and how you can build a native executable using both solutions together.

As we can see in the Sanne's presentation in Devoxx and in this article about lightweight cloud-native Java applications from Oleg Šelajev, some of the benefits of using GraalVM are faster startup and less runtime memory requirements.

Conclusion

It’s easy and fast to create solutions using Quarkus. My recommendation is and always will be to learn more. So go there and test the new Quarkus, compare it with your already done projects, check how it feels to code with it.

You can download the project from my Github: https://github.com/andreybevilacqua/techstore. Follow the steps in the Readme.md files to execute the application.