Creating your first Micronaut Graal application

Learn how to create a Hello World Micronaut Graal application.

Authors: Iván López, Sergio del Amo

Micronaut Version: 1.1.2

1 Getting Started

In this guide we are going to create a Micronaut application with Graal support.

1.1 What you will need

To complete this guide, you will need the following:

  • Some time on your hands

  • A decent text editor or IDE

  • JDK 1.8 or greater installed with JAVA_HOME configured appropriately

1.2 Solution

We recommend you to follow the instructions in the next sections and create the app step by step. However, you can go right to the completed example.

or

Then, cd into the complete folder which you will find in the root project of the downloaded/cloned project.

2 Writing the App

Create an app using the Micronaut Command Line Interface.

mn create-app example.micronaut.complete --features=graal-native-image

The previous command creates a micronaut app with the default package example.micronaut in a folder named complete and with support for Graal.

If you are using Java or Kotlin and IntelliJ IDEA make sure you have enabled annotation processing.

annotationprocessorsintellij

3 Service

Create a POJO Conference.java:

src/main/java/example/micronaut/Conference.java
package example.micronaut;

import io.micronaut.core.annotation.Introspected;

@Introspected (1)
public class Conference {

    private String name;

    public Conference(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
1 Annotate the class with @Introspected to generate BeanIntrospection metadata at compilation time. This information is use the render the POJO as json using Jackon without using reflection.

Create a Service:

src/main/java/example/micronaut/ConferenceService.java
package example.micronaut;

import javax.inject.Singleton;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

@Singleton (1)
public class ConferenceService {

    private static final List<Conference> CONFERENCES = Arrays.asList(
            new Conference("Greach"),
            new Conference("GR8Conf EU"),
            new Conference("Micronaut Summit"),
            new Conference("Devoxx Belgium"),
            new Conference("Oracle Code One"),
            new Conference("CommitConf"),
            new Conference("Codemotion Madrid")
    );

    public Conference randomConf() { (2)
        return CONFERENCES.get(new Random().nextInt(CONFERENCES.size()));
    }
}
1 Use javax.inject.Singleton to designate a class a a singleton.
2 Return a random conference.

4 Controller

Create a Controller with a method that returns a Conference. Micronaut will convert it automatically to JSON in the response:

src/main/java/example/micronaut/ConferenceController.java
package example.micronaut;

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller("/conferences") (1)
public class ConferenceController {

    private final ConferenceService conferenceService;

    public ConferenceController(ConferenceService conferenceService) { (2)
        this.conferenceService = conferenceService;
    }

    @Get("/random") (3)
    public Conference randomConf() { (4)
        return conferenceService.randomConf();
    }
}
1 The class is defined as a controller with the @Controller annotation mapped to the path /conferences.
2 Constructor injection
3 The @Get annotation is used to map the index method to all requests that use an HTTP GET
4 Return a Conference.

5 Adding Graal support

GraalVM is a new universal virtual machine from Oracle that supports a polyglot runtime environment and the ability to compile Java applications down to native machine code.

Any Micronaut application can be run using the GraalVM JVM, however special support has been added to Micronaut to support running Micronaut applications using GraalVM’s native-image tool.

Use of GraalVM’s native-image tool is only supported in Java or Kotlin projects. Groovy relies heavily on reflection which is only partially supported by GraalVM.

5.1 Creating Graal native image

When we created the application we used the graal-native-image feature. This feature adds three important items:

1.- svm and graal dependencies in build.gradle:

build.gradle
compileOnly "com.oracle.substratevm:svm"
annotationProcessor "io.micronaut:micronaut-graal" (1)
1 Annotation processor to generate the reflect information at compile time.

2.- A Dockerfile which can be used to construct the native image executing docker-build.sh

3.- A native-image.properties file in resources/META-INF/native-image/example.micronaut/complete-application directory with Graal’s native-image configuration. This file can be used to fine tune the native-image generation.

native-image.properties
Args = -H:IncludeResources=logback.xml|application.yml \
       -H:Name=micronaut-graal-app \
       -H:Class=example.micronaut.Application

Creating native image inside Docker

With this approach you only need to build the fatjar and then use Docker to build the native image.

Building Graal native image
$ ./gradlew assemble
$ ./docker-build.sh

The previous command will create the image micronaut-graal-app:latest. To execute it:

Executing the native image
$ docker run -p 8080:8080 micronaut-graal-app
10:29:46.845 [main] INFO  io.micronaut.runtime.Micronaut - Startup completed in 12ms. Server Running: http://localhost:8080

We can see that the application starts in only 12ms.

Creating native image outside Docker

To build your native image without using Docker you need to install GraalVM SDK via the Getting Started instructions or using SDKman:

Installing GraalVM 19.0.0 with SDKman
$ sdk install java 19.0.0-grl
$ sdk use java 19.0.0-grl

The native-image tool was extracted from the base GraalVM distribution. Currently it is available as an early adopter plugin. To install it, run:

Installing native-image tool
$ gu install native-image (1)
1 You only need to do that the first time to install the native-image tool.
Building Graal native image
$ sdk use java 19.0.0-grl
$ ./gradlew assemble
$ native-image --no-server -cp build/libs/complete-*.jar (1)
1 Starting in Micronaut 1.1.0 it is really simple to create the native image.

The previous commmand will create a native executable called micronaut-graal-app.

Sending a request

Start the application either using Docker or the native executable. You can run a few cURL requests to test the application:

complete $ time curl localhost:8080/conferences/random
{"name":"Greach"}
real    0m0.016s
user    0m0.005s
sys     0m0.004s

complete $ time curl localhost:8080/conferences/random
{"name":"GR8Conf EU"}
real    0m0.014s
user    0m0.005s
sys     0m0.004s

6 Next steps

Read more about Graal Support inside Micronaut.