Warning This post was updated to use Java 19 with the latest Quarkus version.
Why Quarkus is a good choice?
Quarkus is one of the best frameworks for Java! First, there was the Wildfly, that as an experiment became a microservices focus project called Wildfly Swarm. Then Wildfly Swarm was renamed to Thorntail. The main purpose of Thorntail was to build a Jakarta EE implementation build for microservices. But there was some pitfall that needed a full rewrite for the code. So this is Quarkus, a light implementation, ready for microservices and it has native support to GraalVM.
So Quarkus is based on lessons learned from previous development. Based on these lessons I believe this will be a better framework, easy to use and fast on execution.
Mangling artifacts is dangerous When you mangle and repackage a user’s artifacts and dependencies, it can many times go awry.
Don’t replace Maven Let Maven (or Gradle) handle the entirety of pulling dependencies. We cannot predict the topology of someone’s repository managers, proxies and network.
Don’t get complicated with uberjars The more complex our uberjar layout is, the harder it is to support Gradle or other non-Maven build systems.
Classpaths are tricky If different codepaths are required for executing from Maven, an IDE, a unit-test, and during production, you will have a bad time.
Don’t insist on uberjars For Linux containers, people want layers that cleanly separate application code from runtime support code.
Testability is important A slow test is a test that is never willingly executed. PRs take forever to validate. Users like to be able to test their own code quickly and iteratively.
Easily extensible means ecosystem If it’s entirely too difficult to extend the platform, the ecosystem will not grow. New integrations should be simple.
Related: Core things should not be any more first-class than community contributions For instance, auto-detection in WildFly Swarm only worked with core fractions; user-provided wouldn’t auto-detect.
Ensure the public-vs-private API guarantees are clear. Intertwingly code (and javadocs) make finding the delineation between public API and private implementations difficult.
Allow BYO components We don’t want to decide all of the implementations, and certainly not versions, of random components we support.
Be a framework, not a platform Frameworks are easier to integrate into an existing app; a platform becomes the target with (generally too many) constraints.
Maintain tests & documentation Ensure the definition of “done” includes both tests and documentation.
Productization complexity The greater divergence between community and product, the more effort is required for productization. Complicating any process to automate productization from community.
BOM complexity Related to productization as well, but of itself having a handful of BOMs made life confusing for us and for users. There were often times where fractions would be “Unstable” or “Experimental” for months with no real reason other than we forgot to update it.
Configure Quarkus
The first question we need to answer on a tutorial is: To build a project using Quarkus, what do you need?
For Quarkus we need:
- Add the dependencies
- Configure the package
- Starting coding
1. Configure the dependencies
As Quarkus is a Jakarta EE, we will use the Jakarta EE annotations on the code. But, for the pom.xml
we should point to Quarkus dependencies because quarkus has native support for GraalVM.
First we need add all dependencies to Quarkus, this can be done using dependencyManagement:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-universe-bom</artifactId>
<version>2.14.1.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
The for that project we will need:
- Create REST API
- Add JSON Support
- Add Reactive Support
For that we will need the following dependencies:
io.quarkus:quarkus-resteasy-reactive-jackson
for creating the REST API
2. Configuring the build
The next step we should configure Quarkus build. As we know, Quarkus creates a fat jar with all dependencies.
To enable the Quarkus builder on Maven, just add the following plugin:
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>2.14.1.Final</version>
<executions>
<execution>
<goals>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
In this example, I’m compiling as Java 11, but I’m using Java 15 to test. It will work for any version of Java newer than 11. If you need to execute it on Java 8, just change the compiler options.
We can make the build just executing:
mvn clean package
This will create a jar
inside the target folder and a quarkus-app
folder. This folder contains the application that can be executed by the quarkus-run.jar
jar inside it.
$ java -jar target/quarkus-app/quarkus-run.jar
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2022-11-18 11:03:25,031 INFO [io.quarkus] (main) microblogging 0.0.1-SNAPSHOT on JVM (powered by Quarkus 2.14.1.Final) started in 8.499s. Listening on: http://0.0.0.0:8080
2022-11-18 11:03:25,072 INFO [io.quarkus] (main) Profile prod activated.
2022-11-18 11:03:25,072 INFO [io.quarkus] (main) Installed features: [cdi, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx]
2022-11-18 11:03:49,906 INFO [io.quarkus] (main) microblogging stopped in 6.942
This is the way we should execute for production environments, for development we can use Quarkus Maven plugin. It already does the deploy of any change on the running server:
mvn quarkus:dev
3. Adding the REST API Endpoint
The latest step for creating an API is creating the code that will handle the requests. Using JAX-RS is easy, just create a class and add the annotations.
The most simple example is:
@Path("/hello")
@ApplicationScoped
public class HelloEndpoint {
@GET
public String sayHello() {
return "Hello World!";
}
}
JAX-RS automatically generate a JSON representation for any object returned by this method, you have just to inform the MIME Type.
@Path("/hello")
@ApplicationScoped
public class HelloEndpoint {
private HelloResponse generateResponse() {
HelloResponse response = new HelloResponse();
response.setCode(new Random().nextInt());
response.setMessage("Hello World!");
return response;
}
@GET
@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
public HelloResponse sayHelloWithJson() {
return generateResponse();
}
}
Quarkus also have support for reactive programming. For JAX-RS, you have just to return a Uni
or a CompletableFuture
.
@Path("/hello")
@ApplicationScoped
public class HelloEndpoint {
private HelloResponse generateResponse() {
HelloResponse response = new HelloResponse();
response.setCode(new Random().nextInt());
response.setMessage("Hello World!");
return response;
}
@GET
@Path("/json/reactive")
@Produces(MediaType.APPLICATION_JSON)
public Uni<HelloResponse> sayHelloWithJsonReactively() {
return Uni.createFrom().item(this::generateResponse);
}
}
Conclusion
With Quarkus you can build quickly a REST API using JAX-RS. As JAX-RS is a Jakarta EE specification, you can migrate your code with few changes to another existing implementation, but Quarkus is the lighter implementation.
Quarkus is a good choice!
You can find all examples on github.com/vepo/quarkus-tutorial