Quarkus 3.4 - Container-first Java Stack: Install with OpenJDK 21 and Create REST API
Tags: quarkus, microservices, kubernetes, java
Published: 2023-10-16 13:49:15

## Summary

[Quarkus](https://quarkus.io/) is one of [Java](https://dev.java/) frameworks for microservices development and cloud-native deployment. It is developed as container-first stack, is designed to get along with [Kubernetes](https://kubernetes.io/) and can be integrated with [GraalVM](https://www.graalvm.org/) or [HotSpot](https://openjdk.org/groups/hotspot/) virtual machines (VM).

This post shows how to install Quarkus with [OpenJDK](https://openjdk.org/) [21](https://jdk.java.net/21/) on [Devuan](https://www.devuan.org/) [5](https://www.devuan.org/os/announce/daedalus-release-announce-2023-08-14) and create an example project to serve JSON REST APIs.

### Why Quarkus ?

Java was not ready for the cloud-computing era once. It's because Java and its ecosystem were developed primarily for services which were expected to be always active or at least at most time. Once their servers and services were started, they kept memory consumed after some initiation time. Their services were expected not to be stopped or destroyed once started.

In contrast, services in the cloud remarkably depend on virtualization. VMs are frequently created and destroyed in cloud environment.
Thus cloud development and deployment, driven by container VM and kube pods etc., require fast start up to machines.
After many contributions by many, improvement and new encounters with GraalVM etc., Java lit the way to solve the problem at last.

Backed up by such progress, Quarkus has these good points:

- Fast boot time
- Low memory consumption

### Environment

- OS: Devuan 5 Daedalus
  - based on [Debian](https://www.debian.org/) [12 bookworm](https://www.debian.org/releases/bookworm/)
- App Engine: OpenJDK 21
- Project Build and Management: Apache [Maven](https://maven.apache.org/) [3](https://maven.apache.org/docs/3.0/release-notes.html) (3.9.5), [Gradle](https://gradle.org/) [8](https://docs.gradle.org/8.0/release-notes.html) (8.3)
- Java Stack: Quarkus [3](https://quarkus.io/blog/quarkus-3-0-final-released/) (3.4.3)

## Tutorial

Suppose you have OpenJDK 21 and Maven which are ready with environment variables `PATH` and `JAVA_HOME` set.

With Devuan used, my past posts to install [Java 21](http://localhost:1313/en/blog/2023/10/14/java-21-on-devuan-5-debian-12-install-manually/index.html) and [Maven](http://localhost:1313/en/blog/2023/10/15/maven-on-java-21-and-devuan-5-debian-12-install-manually/index.html) will help.

### Starting point 💫

My environment was as below:

```console
$ java --version
openjdk 21 2023-09-19
OpenJDK Runtime Environment (build 21+35-2513)
OpenJDK 64-Bit Server VM (build 21+35-2513, mixed mode, sharing)

$ mvn --version
Apache Maven 3.9.5 (57804ffe001d7215b5e7bcb531cf83df38f93546)
Maven home: /(...)/apache-maven-3.9.5
Java version: 21, vendor: Oracle Corporation, runtime: /(...)/jdk-21
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.1.0-13-amd64", arch: "amd64", family: "unix"
```

### Create a Quarkus project 🦯

Maven helps to create a project as below:

```console
$ mvn io.quarkus.platform:quarkus-maven-plugin:3.4.3:create \
    -Dextensions='resteasy-reactive-jackson' \
    -DnoCode \
    -DprojectGroupId=com.quarkusrestjsonexample \
    -DprojectArtifactId=quarkus-rest-json-example \
    -DbuildTool=gradle
```

The last `-DbuildTool=gradle` is optional. I prefer Gradle build.

The result was as below:

```console
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- quarkus:3.4.3:create (default-cli) @ standalone-pom ---
[INFO] -----------
[INFO] selected extensions: 
- io.quarkus:quarkus-resteasy-reactive-jackson

[INFO] 
applying codestarts...
[INFO] 📚 java
🔨 gradle
📦 quarkus
📝 config-properties
🔧 dockerfiles
🔧 gradle-wrapper
[INFO] 
-----------
[SUCCESS] ✅  quarkus project has been successfully generated in:
--> /(...)/quarkus-rest-json-example
-----------
[INFO] 
[INFO] ========================================================================================
[INFO] Your new application has been created in /(...)/quarkus-rest-json-example
[INFO] Navigate into this directory and launch your application with mvn quarkus:dev
[INFO] Your application will be accessible on http://localhost:8080
[INFO] ========================================================================================
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.209 s
[INFO] Finished at: 2023-10-15T20:38:05+09:00
[INFO] ------------------------------------------------------------------------
```

### Check build dependencies 🔍

Let's go inside the project:

```console
$ cd rest-json-quickstart
```

You can see `implementation 'io.quarkus:quarkus-resteasy-reactive-jackson'` in `dependencies`:

```console
$ grep -a5 'dependencies {' build.gradle
repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
    implementation 'io.quarkus:quarkus-resteasy-reactive-jackson'
    implementation 'io.quarkus:quarkus-arc'
    testImplementation 'io.quarkus:quarkus-junit5'
}
```

OK.

### Create `.java` files in `src` ✍

There are no `.java` files in `src` by default:

```console
$ ls src/main/java/
```

Here we will create two files in `src/main/java`: `Fruit.java` and `FruitResource.java` as bean and resource.

```console
$ nvim src/main/java/{Fruit.java,FruitResource.java}
```

Write as below in `Fruit.java`:

```java
package com.quarkusrestjsonexample;

public class Fruit {

    public String name;
    public String description;

    public Fruit() {
    }

    public Fruit(String name, String description) {
        this.name = name;
        this.description = description;
    }
}
```

When you use [NeoVim](https://neovim.io/)/[Vim](https://www.vim.org/), you should type `:next` after `:w` (save) in order to switch files.

Then write as below in `FruitResource.java`:

```java
package com.quarkusrestjsonexample;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Set;

import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;

@Path("/fruits")
public class FruitResource {

    private Set<Fruit> fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));

    public FruitResource() {
        fruits.add(new Fruit("Apple", "Winter fruit"));
        fruits.add(new Fruit("Pineapple", "Tropical fruit"));
    }

    @GET
    public Set<Fruit> list() {
        return fruits;
    }

    @POST
    public Set<Fruit> add(Fruit fruit) {
        fruits.add(fruit);
        return fruits;
    }

    @DELETE
    public Set<Fruit> delete(Fruit fruit) {
        fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name));
        return fruits;
    }
}
```

Type `:wq` to close NeoVim/Vim.

### Run service 🚀

Gradle helps to build it and start service as below:

```console
$ ./gradlew --console=plain quarkusDev
```

Then your server will start:

```console
Starting a Gradle Daemon (subsequent builds will be faster)
(...)
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2023-10-15 20:49:36,188 INFO  [io.quarkus] (Quarkus Main Thread) quarkus-rest-json-example 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.4.3) started in 1.242s. Listening on: http://localhost:8080
2023-10-15 20:49:36,190 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2023-10-15 20:49:36,191 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx]
```

Yay 🙌

## Conclusion

According to the Gradle output above, access to `http://localhost:8080` with your web browser.
You will see:

![quarkus-01](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9wfx9nuq65a1uilogmhg.png)

Why 404 ? It's because there is no definition about `@Path("/")`, the root path, in `FruitResource.java`. It's OK now, for it can be extended easily.

Then go to `/fruits` and you will see 😉

![quarkus-02](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/img5vmyk6u19w7ojfa34.png)

Our Quarkus Web API service is running in good health.

### Acknowledgements

- [QUARKUS - Writing JSON REST Services](https://quarkus.io/guides/rest-json) by [Red Hat](https://www.redhat.com/)