Micronaut Gradle plugin Version 3.7.0 1. What’s new Note Documentation for the 2.x branch can be found here. The 3.0.0 version of the plugin integrates with the official GraalVM plugin which introduces some breaking changes: the nativeImage task is now replaced with nativeCompile native image configuration happens in the graalvmNative DSL block The GraalVM SDK being used depends on how you configure toolchains Please refer to the native image section for more help: the toolchain selection mechanism might be surprising to you. 2. The Gradle plugins A Gradle Plugin which makes development of Micronaut application and libraries a breeze. This project currently consists of different plugins: the https://plugins.gradle.org/plugin/io.micronaut.applicationio.micronaut.application plugin is aimed at building Micronaut applications. It automatically integrates with GraalVM by applying the io.micronaut.graalvm plugin transparently. the https://plugins.gradle.org/plugin/io.micronaut.libraryio.micronaut.library plugin is aimed at building Micronaut libraries. the https://plugins.gradle.org/plugin/io.micronaut.graalvmio.micronaut.graalvm plugin integrates with the official GraalVM Native Build Tools plugin and configures it for Micronaut applications. the https://plugins.gradle.org/plugin/io.micronaut.aotio.micronaut.aot plugin integrates with Micronaut AOT to produce optimized binaries. 2.1. Individual plugins In addition to the library and application plugins described in the following documentation, you can apply one of the following plugins to your project. For example, the minimal plugins can be used to reduce the number of tasks, for example if you don’t need Docker or GraalVM support: Plugin id Description Also applies https://plugins.gradle.org/plugin/io.micronaut.minimal.libraryio.micronaut.minimal.library Allows building Micronaut libraries, without GraalVM support java-library https://plugins.gradle.org/plugin/io.micronaut.minimal.applicationio.micronaut.minimal.application Allows building Micronaut applications, without GraalVM nor Docker support application https://plugins.gradle.org/plugin/io.micronaut.graalvmio.micronaut.graalvm Adds support for building native images https://plugins.gradle.org/plugin/io.micronaut.dockerio.micronaut.docker Adds support for building Docker images https://plugins.gradle.org/plugin/io.micronaut.aotio.micronaut.aot Adds support for Micronaut AOT https://plugins.gradle.org/plugin/io.micronaut.libraryio.micronaut.library A typical Micronaut Library, with support for GraalVM https://plugins.gradle.org/plugin/io.micronaut.minimal.libraryio.micronaut.minimal.library, https://plugins.gradle.org/plugin/io.micronaut.graalvmio.micronaut.graalvm, AptEclipsePlugin https://plugins.gradle.org/plugin/io.micronaut.applicationio.micronaut.application A typical Micronaut Application, with support for GraalVM and Docker https://plugins.gradle.org/plugin/io.micronaut.minimal.applicationio.micronaut.minimal.application, https://plugins.gradle.org/plugin/io.micronaut.graalvmio.micronaut.graalvm, https://plugins.gradle.org/plugin/io.micronaut.dockerio.micronaut.docker, AptEclipsePlugin https://plugins.gradle.org/plugin/io.micronaut.test-resourcesio.micronaut.test-resources Provides automatic test resources provisioning on a single project https://plugins.gradle.org/plugin/io.micronaut.test-resources-consumerio.micronaut.test-resources-consumer Provides ability to use test resources of other projects of multiproject builds Using the io.micronaut.application plugin: GroovyKotlin plugins { id ‘io.micronaut.application’ version ‘3.7.0’ } Copy to Clipboard is therefore equivalent to applying those plugins individually: GroovyKotlin plugins { id ‘io.micronaut.minimal.application’ version ‘3.7.0’ id ‘io.micronaut.docker’ version ‘3.7.0’ id ‘io.micronaut.graalvm’ version ‘3.7.0’ } apply plugin: com.diffplug.gradle.eclipse.apt.AptEclipsePlugin Copy to Clipboard io.micronaut.minimal.application, io.micronaut.graalvm and io.micronaut.docker plugins (as well as the Eclipse annotation processing support plugin). 3. Quick Start Template projects are available via Micronaut Launch for each language. To get started you can use the Micronaut CLI: $ mn create-app demo –lang java $ mn create-app demo –lang groovy $ mn create-app demo –lang kotlin Or if you don’t have it installed via curl: # for Java $ curl https://launch.micronaut.io/demo.zip?lang=java -o demo.zip && unzip demo.zip -d demo && cd demo # for Groovy $ curl https://launch.micronaut.io/demo.zip?lang=groovy -o demo.zip && unzip demo.zip -d demo && cd demo # for Kotlin $ curl https://launch.micronaut.io/demo.zip?lang=kotlin -o demo.zip && unzip demo.zip -d demo && cd demo 4. Micronaut Library Plugin Applying the plugin GroovyKotlin plugins { id ‘io.micronaut.library’ version ‘3.7.0’ } Copy to Clipboard The Micronaut library plugin applies the following modifications to the build: Applies the Micronaut Bill of Materials (BOM) Applies the java-library plugin Configures annotation processing for the current language (Groovy, Java or Kotlin) The micronaut DSL can be used to configure how this behaves. The minimum requirement is to set the Micronaut version to use. This can be done by setting micronautVersion in gradle.properties or as follows in build.gradle(.kts): Selecting the Micronaut version GroovyKotlin micronaut { version “3.5.1” } Copy to Clipboard Complete example with the default settings: Micronaut configuration options GroovyKotlin micronaut { version “3.5.1” processing { // Sets whether incremental annotation processing is enabled incremental true // Sets the module name. // This should be the same as the artifactId in the POM module project.name // Sets the group. // This should be th same as the groupId in the POM group project.group // Sets the Java package names containing any custom Micronaut // meta annotations (new annotations annotated with say @Around). // Generally used only for advanced cases such as defining new AOP // advice. If omitted however, incremental annotation processing // will not work correctly annotations “com.example.*” // additional sourceSets can be configured here to apply the BOM // and annotation processors to source sets other than ‘main’ sourceSets( sourceSets.main ) } } Copy to Clipboard Note The Micronaut Library plugin also supports Groovy and Kotlin sources. 4.1. Kotlin Support For Kotlin, the Kotlin jvm and kapt plugins must be configured: Configuring Kotlin support GroovyKotlin plugins { id “org.jetbrains.kotlin.jvm” version “1.6.21” id “org.jetbrains.kotlin.kapt” version “1.6.21” id “io.micronaut.library” version “3.7.0” } Copy to Clipboard 4.2. Minimal Build With the io.micronaut.library plugin applied a minimal build to get started writing a library for Micronaut that written in Java and is tested with JUnit 5 looks like: A minimal build file GroovyKotlin plugins { id ‘io.micronaut.library’ version ‘3.7.0’ } version “0.1” group “com.example” repositories { mavenCentral() } micronaut { version = “3.5.1” } dependencies { testImplementation(“io.micronaut.test:micronaut-test-junit5”) testRuntimeOnly(“org.junit.jupiter:junit-jupiter-engine”) } Copy to Clipboard 5. Micronaut Application Plugin Applying the Micronaut Application plugin GroovyKotlin plugins { id “io.micronaut.application” version “3.7.0” } Copy to Clipboard The Micronaut application plugin extends the Micronaut Library plugin and adds the following customizations: Instead of the java-library plugin the plugin applies the Gradle application plugin Applies the io.micronaut.graalvm plugin Correctly configures Gradle for continuous build The following additional tasks are provided by this plugin: buildLayers - Builds application layers for use in a Docker container dockerfile - Builds a Docker File for a Micronaut application dockerBuild - Builds a Docker Image using the Docker Gradle plugin dockerfileNative - Builds a Docker File for for GraalVM Native Image dockerBuildNative - Builds a Native Docker Image using GraalVM Native Image dockerBuildCrac - Builds a docker Image containing a CRaC enabled JDK and a pre-warmed, checkpointed application. nativeCompile - Builds a GraalVM Native Image testNativeImage (since 1.1.0) - Builds a GraalVM Native Image, starts the native server and runs tests against the server dockerPush - Pushes a Docker Image to configured container registry dockerPushNative - Pushes a Docker Image built with GraalVM Native Image to configured container registry dockerPushCrac - Pushes a Docker Image built with a CRaC enabled JDK and a pre-warmed, checkpointed application to configured container registry To run an application with continuous build use the run task with the -t parameter: $ ./gradlew run -t 5.1. Minimal Build With the io.micronaut.application plugin applied a minimal build to get started with a Micronaut server application that is written in Java and tested with JUnit 5 looks like: GroovyKotlin plugins { id ‘io.micronaut.application’ version ‘3.7.0’ } version “0.1” group “com.example” repositories { mavenCentral() } micronaut { version = “3.5.1” } dependencies { implementation(“io.micronaut:micronaut-http-server-netty”) runtimeOnly(“ch.qos.logback:logback-classic”) testImplementation(“io.micronaut.test:micronaut-test-junit5”) testRuntimeOnly(“org.junit.jupiter:junit-jupiter-engine”) } application { mainClass = “example.Application” } Copy to Clipboard 5.2. Kotlin Support The most simple Kotlin build using a build.gradle(.kts) file looks like: GroovyKotlin plugins { id “org.jetbrains.kotlin.jvm” version “1.6.21” id “org.jetbrains.kotlin.kapt” version “1.6.21” id “org.jetbrains.kotlin.plugin.allopen” version “1.6.21” id “io.micronaut.application” version “3.7.0” } version “0.1” group “com.example” repositories { mavenCentral() } micronaut { version = “3.5.1” } dependencies { implementation “io.micronaut:micronaut-http-server-netty” implementation “org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21” implementation “org.jetbrains.kotlin:kotlin-reflect:1.6.21”) runtimeOnly “ch.qos.logback:logback-classic”) testImplementation(“io.micronaut.test:micronaut-test-junit5”) testRuntimeOnly(“org.junit.jupiter:junit-jupiter-engine”) } application { mainClass = “example.ApplicationKt” } Copy to Clipboard 5.3. GraalVM Native Image Since version 3.0.0, the Micronaut plugins rely on the official GraalVM plugin to build native images. Those plugins make use of the Gradle toolchains support, which means that the SDK which is used to build the native is decorrelated from the JVM which is used to launch Gradle itself. Said differently, you can run Gradle with OpenJDK, while still building native images using the GraalVM SDK. The Micronaut Gradle plugin will automatically configure the toolchains support for you, but there are a few things that you should be aware of: running Gradle with a GraalVM SDK doesn’t necessarily imply that Gradle will use the same SDK to build native images Gradle will try to locate a compatible GraalVM toolchain to build images. You can tweak what GraalVM version to use by following the official documentation. Important While the toolchain selection will properly select a GraalVM SDK which matches your language version requirements, it will not let you pick a particular GraalVM version (say, prefer 21.3 over 21.1). If your application depends on a specific GraalVM version, you will have to disable automatic detection like explained below. If you have several GraalVM installations available, or that you want to disable the automatic toolchain recognition, we recommend that you do the following: setup an environment variable named GRAALVM_HOME pointing to your GraalVM installation edit your gradle.properties file to add the following options: # Disable Gradle automatic download of Java SDKs org.gradle.java.installations.auto-download=false # Disable auto-detection of Java installations org.gradle.java.installations.auto-detect=false # Setup explicitly that the Java version to use # should be the one from the JAVA_HOME environment variable org.gradle.java.installations.fromEnv=JAVA_HOME Alternatively you can pass those options from the command line: ./gradlew -Porg.gradle.java.installations.auto-download=false -Porg.gradle.java.installations.auto-detect=false -Porg.gradle.java.installations.fromEnv=JAVA_HOME build You can build a native image by running the following task: $ ./gradlew nativeCompile And you can run it by calling the following task: $ ./gradlew nativeRun You can tweak the native image options by configuring the graalvmNative extension as explained in the plugin documentation. For example you can add options to the main image by doing: GroovyKotlin graalvmNative { binaries { main { buildArgs.add("-H:-DeleteLocalSymbols") buildArgs.add("-H:+PreserveFramePointer") } } } Copy to Clipboard Important If you update an existing Micronaut application that contains the file src/main/resources/META-INF/native-image/xxxxx/native-image.properties, please make sure to delete the properties -H:Name and -H:Class from the file because they are managed automatically by the plugin. 5.3.1. Build “mostly static” native images Since GraalVM 21.0 it is possible to create “mostly static” native images that can run in a distroless docker image. You only need to configure the appropriate baseImage and the plugin will automatically configure GraalVM: GroovyKotlin tasks.named(‘dockerfileNative’) { baseImage(‘gcr.io/distroless/cc-debian10’) } Copy to Clipboard In case you want to use another base image you need to set the appropriate GraalVM flag: GroovyKotlin tasks.named(‘dockerfileNative’) { baseImage(…) args(’-H:+StaticExecutableWithDynamicLibC’) } Copy to Clipboard 5.4. Testing Native Images Note This feature is independent from the official GraalVM testing support, which actually runs a test suite within a native image. Micronaut native test support launches a JVM test suite against a native image server. Since 1.1.x of the plugin, you can also use the testNativeImage task to start the Micronaut native server and run tests against it. Important This feature only works in combination with micronaut-test-core versions 2.2.1 or above. Make sure your test classpath includes at least this version of Micronaut Test. Using this task will replace the regular embedded server used for tests with the natively built executable: ./gradlew testNativeImage It is important to note that there are some limitations to this approach in that the native server is no longer “embedded” in the test. This has the following implications: It is not possible to mock components using @MockBean or replace beans using @Replaces since the native server starts in a separate process and beans injected into or defined by the test are no longer shared with the application under test since it is running in a separate process. The native server starts with the test environment active, however the classpath of the application is the runtime classpath not the test classpath. This has the implication that certain testing features (like for example Testcontainers’ usage of JDBC URLs to start containers) won’t work and you have to explicitly start any test containers in the test itself. If you wish to split your native image tests from your regular tests you can create an additional source set for integration tests and the plugin will add an additional task suffixed with *NativeImage to run the native image tests, for example: gradle integrationTestNativeImage. 5.5. Docker Support 5.5.1. Building docker images The Micronaut plugin includes integration with the Gradle Docker plugin allowing you to easily build applications and native images using Docker containers. Applications are built as layered JARs using the buildLayers task ensuring optimized Docker images for Java applications. To build a regular Java application into a Docker container that is ready to be deployed and exposes ports 8080 you can simply do: $ ./gradlew dockerBuild The default uses an openjdk:17-alpine base image, however you can easily switch the base image to use by using the baseImage property of the dockerfile task: GroovyKotlin tasks.named(“dockerfile”) { baseImage = “oracle/graalvm-ce:22.3.0-java11” } Copy to Clipboard The above examples switches to use GraalVM CE 22.3.0 as a base image. To build the application into a Native Image you can run: $ ./gradlew dockerBuildNative Note that for this to work you must build the application with the same GraalVM SDK as used to build the image. To build a docker image containing a CRaC enabled JDK and a pre-warmed, checkpointed application, you can run: $ ./gradlew dockerBuildCrac To push the container to the currently configured container registry you can use either dockerPush, dockerPushNative for the native image, or dockerPushCrac for CRaC image: $ ./gradlew dockerPush To configure the image names to push you can use the images setting of the dockerBuild task. For example the following configures dockerPush to use Oracle Container Registry: GroovyKotlin tasks.named(“dockerBuild”) { images = [“eu-frankfurt-1.ocir.io/xyzzyz/repo/my-image:$project.version”] } tasks.named(“dockerBuildNative”) { images = [“eu-frankfurt-1.ocir.io/xyzzyz/repo/my-image-native:$project.version”] } tasks.named(“dockerBuildCrac”) { images = [“eu-frankfurt-1.ocir.io/xyzzyz/repo/my-image-crac:$project.version”] } Copy to Clipboard Notice that you can supply two different image names to push to for the JVM version and the native version of the application. 5.5.2. Customized docker files If you wish to customize the docker builds that are used, the easiest way is to run ./gradlew dockerfile (or dockerfileNative for the native version) and copy the generated Dockerfile from build/docker to your root directory and modify as required. If you wish to customize the JVM arguments or native image arguments then it is possible to do so with the args method of the dockerfile and dockerfileNative tasks: GroovyKotlin tasks.named(“dockerfile”) { args("-Xmx128m") } tasks.named(“dockerfileNative”) { args("-Xmx64m") } Copy to Clipboard The above configuration uses a max heap setting of 128m for Java and 64m for native image for the application. 5.5.3. Adding additional instructions To add additional docker instructions to the generated Dockerfile, such as adding a HEALTHCHECK, you can do the following. The additional instructions will be added at the end of the Dockerfile just before the ENTRYPOINT. GroovyKotlin tasks.named(“dockerfile”) { args("-Xmx128m") instruction “““HEALTHCHECK CMD curl -s localhost:8090/health | grep ‘“status”:“UP”’ "”” } tasks.named(“dockerfileNative”) { args("-Xmx64m”) instruction “““HEALTHCHECK CMD curl -s localhost:8090/health | grep ‘“status”:“UP”’””” } Copy to Clipboard You can also add any of the other instructions/commands that the docker plugin supports, see the Dockerfile task documentation. 5.5.4. Duplicates on classpath In some projects, it may happen that different transitive dependencies have the same file name. In this case, the task which builds the layers will fail with a duplicate error. You can workaround this issue by configuring the duplicates strategy on the task: GroovyKotlin tasks.withType { duplicatesStrategy = DuplicatesStrategy.INCLUDE } Copy to Clipboard 5.6. Micronaut Runtimes A higher level concept of “runtimes” is included in the Micronaut Gradle plugin which essentially allows the plugin to decide which server runtime to include in the dependencies of the application when building the application. For example consider this minimal build: GroovyKotlin plugins { id ‘io.micronaut.application’ version ‘3.7.0’ } version “0.1” group “com.example” repositories { mavenCentral() } micronaut { version = “3.5.1” runtime “netty” } dependencies { runtimeOnly(“ch.qos.logback:logback-classic”) } application { mainClass = “example.Application” } Copy to Clipboard Here the only dependency declared is on the logging framework to use however runtime is to netty resulting in an application that can be built and run. If you wish to take the same and build or run it with a different runtime you can pass the micronaut.runtime property for the build. For example: ./gradlew run -Pmicronaut.runtime=google_function The above example run the application as a Google Cloud Function. The available runtimes are: netty - A Netty server runtime jetty - A Jetty server runtime tomcat - A Tomcat server runtime undertow - An Undertow server runtime lambda - Allows building the application into an AWS Lambda oracle_function - A Project.fn runtime for deploying Oracle Functions google_function - A runtime for deploying Google Functions. azure_function - A runtime for deploying Azure Functions The advantage of allowing your dependencies to be dictated by the runtime is that you can potentially take the same application and deploy it to any of the above runtimes without changes. 5.6.1. Deploying to AWS Lambda as GraalVM native image If you are interested in deploying your Micronaut application to AWS Lambda using GraalVM you only need to set the runtime to lambda and execute ./gradlew buildNativeLambda. This task will generate a GraalVM native image inside a Docker container and then it will create the file build/libs/your-app.zip file ready to be deployed to AWS Lambda using a custom runtime. See more information in Micronaut AWS documentation. The plugin will detect the host operating system architecture (based on the os.arch Java system property) and will install the corresponding GraalVM binary distribution inside the Docker image. This means that when running packaging from an X86_64 (Intel/AMD) machine, the produced native image will be an amd64 binary, whilst on an ARM host (such as the new Mac M1) it will be an aarch64 binary. To override this automatic selection, you can configure the graalArch property in a dockerfileNative configuration block in your build: dockerfileNative { graalArch.set(“amd64”) } 5.7. Packaging the application By default the plugin doesn’t create a runnable fatjar when running ./gradlew assemble. There are a couple of options: 5.7.1. Layered application The plugin creates a “layered” application in build/docker/main/layers and from that directory you can run java -jar myapp.jar. It works because that directory contains a lib directory with all the libraries and a resources directory with the configuration. Keep in mind that copying the only .jar file to another directory won’t work. 5.7.2. Add Shadow plugin You can add Gradle Shadow plugin so when running ./gradlew assemble a runnable fatjar is created in build/libs directory. GroovyKotlin plugins { … id “com.github.johnrengelman.shadow” version “7.1.2” … } Copy to Clipboard 6. Micronaut GraalVM Plugin The Micronaut GraalVM plugin is applied automatically by the Micronaut application plugin (see below) and it provides tasks to generate a GraalVM native image and also creates the GraalVM resource-config.json automatically with all the resources from the application. This plugin can be applied separately if you use the application plugin without the io.micronaut.application plugin (but we strongly recommend to switch to the io.micronaut.application plugin in this case). 7. Micronaut AOT Plugin Warning The Micronaut AOT module is in experimental stages. Use at your own risk! The io.micronaut.aot plugin provides integration with Micronaut AOT. Micronaut AOT is a module which aims at pre-computing a number of things at build time in order to provide faster startup times and smaller binaries. At the moment, the plugin supports optimizing Micronaut applications only (Micronaut libraries or functions will be supported in a future release). It is capable of generating a number of things: an optimized jar, which is a jar corresponding to the regular application jar, except that it contains some optimizations computed at build time. It may contain, for example, additional classes, or even have different resources. an optimized fat jar, which is the same as the previous one, except that it also embeds all transitive dependencies and is a standalone executable. an optimized native binary which is a GraalVM image compiled with Micronaut AOT optimizations an optimized docker image which is a Docker image containing the optimized application an optimized native docker image which is a Docker image containing the optimized application compiled as a native image Important Micronaut AOT is a deployment optimization: it adds to build time, in order to make the final application faster to start, or the native images smaller. Therefore, if you use the AOT tasks during development, your feedback cycle will be slower (but the application will start faster). It is a good idea, however, to check the result of the optimization locally, similarly to what you’d do for a native image. 7.1. Configuration The io.micronaut.aot plugin is an extension to the io.micronaut.application plugin. GroovyKotlin plugins { … id “io.micronaut.application” version “3.7.0” id “io.micronaut.aot” version “3.7.0” … } Copy to Clipboard This will add an aot DSL block to the micronaut extension, which can be used to enable optimizations: GroovyKotlin micronaut { … aot { // optional, override the Micronaut AOT version version = “1.0.1” // optimizations configuration optimizeServiceLoading = true convertYamlToJava = true precomputeOperations = true cacheEnvironment = true netty { enabled = true } } } Copy to Clipboard In addition, you can use the aotPlugins configuration to declare additional AOT modules to be used: GroovyKotlin dependencies { aotPlugins ‘io.micronaut.security:micronaut-security-aot:1.0.0’ } Copy to Clipboard Because Micronaut AOT is an extensible optimization engine, not all optimizations are known beforehand by the plugin, which means that not all of them may be accessible via the DSL. For this reason, it is possible to provide a Micronaut AOT configuration file instead: GroovyKotlin micronaut { … aot { configFile = file(“gradle/micronaut-aot.properties”) } } Copy to Clipboard Note You can provide both a configuration file and aot DSL optimizations. The configuration will be merged, by reading the file first, then using the DSL options. If you want to know about all possible optimizations, you can run the createAotSampleConfigurationFiles which will generate a couple of sample files: The build/generated/aot/samples/jit/jit.properties will contain the optimizations which are relevant to an application running in the regular Java virtual machine, for example: # Checks of existence of some types at build time instead of runtime known.missing.types.enabled = true # A list of types that the AOT analyzer needs to check for existence (comma separated) known.missing.types.list = javax.inject.Inject,io.micronaut.SomeType # Replaces logback.xml with a pure Java configuration (NOT YET IMPLEMENTED!) logback.xml.to.java.enabled = true # Precomputes Micronaut configuration property keys from the current environment variables precompute.environment.properties.enabled = true # Scans reactive types at build time instead of runtime scan.reactive.types.enabled = true # Caches environment property values: environment properties will be deemed immutable after application startup. cached.environment.enabled = true # Scans for service types ahead-of-time, avoiding classpath scanning at startup serviceloading.jit.enabled = true # The list of service types to be scanned (comma separated) service.types = io.micronaut.Service1,io.micronaut.Service2 # A list of implementation types which shouldn’t be included in the final application (comma separated) serviceloading.rejected.impls = com.Misc,org.Bar # Converts YAML configuration files to Java configuration yaml.to.java.config.enabled = true # Precomputes property sources at build time sealed.property.source.enabled = true Another file, build/generated/aot/samples/native/native.properties will contain the same, but with the options which are relevant to an application compiled to a native image: # Generates GraalVM configuration files required to load the AOT optimizations graalvm.config.enabled = true # The list of service types to be scanned (comma separated) service.types = io.micronaut.Service1,io.micronaut.Service2 # Checks of existence of some types at build time instead of runtime known.missing.types.enabled = true # A list of types that the AOT analyzer needs to check for existence (comma separated) known.missing.types.list = javax.inject.Inject,io.micronaut.SomeType # Replaces logback.xml with a pure Java configuration (NOT YET IMPLEMENTED!) logback.xml.to.java.enabled = true # Precomputes Micronaut configuration property keys from the current environment variables precompute.environment.properties.enabled = true # Scans reactive types at build time instead of runtime scan.reactive.types.enabled = true # Caches environment property values: environment properties will be deemed immutable after application startup. cached.environment.enabled = true # Scans for service types ahead-of-time, avoiding classpath scanning at startup serviceloading.native.enabled = true # The list of service types to be scanned (comma separated) service.types = io.micronaut.Service1,io.micronaut.Service2 # A list of implementation types which shouldn’t be included in the final application (comma separated) serviceloading.rejected.impls = com.Misc,org.Bar # Converts YAML configuration files to Java configuration yaml.to.java.config.enabled = true # Precomputes property sources at build time sealed.property.source.enabled = true For native images, it is important to always have the graalvm.config.enabled option set to true, otherwise the AOT optimizations will not be loaded. The plugin takes care of setting this flag to true for you. It is important to understand that Micronaut AOT works at build time. Therefore, some optimizations like conversion of YAML files to Java configuration will effectively disable the ability to change the configuration at runtime. 7.2. Running an optimized application The plugin provides a couple of tasks aimed at running an optimized application. The first one, optimizedJar, will simply run the AOT compiler and produce an “optimized” jar. If you want to run the application with the resulting jar, you will need to call the optimizedRun task instead, which will create the jar and then start the application. If you also have the distribution plugin applied, the optimized jar will be used to create optimized distributions, in which case you can call the optimizedDistZip task to create a distribution zip, the optimizedDistTar to create an optimized distribution tar file, or installOptimizedDist to install the optimized application to the build/install directory. 7.3. Running an optimized fat jar The plugin supports building an optimized fat jar. You will need to apply the shadow plugin to enable this feature: GroovyKotlin plugins { … id “com.github.johnrengelman.shadow” version “7.1.2” … } Copy to Clipboard Then you can generate the fat jar by calling: ./gradlew optimizedJitJarAll. The task will generate a fat jar in the build/libs directory, that you can run using: java -jar build/libs/myapp-0.1-all-optimized.jar 7.4. Building and running an optimized native application The plugin creates a new native binary called optimized. The GraalVM plugin will then automatically create a couple of tasks for you: the nativeOptimizedCompile task will compile a native image with the AOT optimizations the nativeOptimizedRun task will run the optimized native image (you can call this task directly, it will precompile the native image before) 7.5. Building an optimized Docker image It is also possible to build an optimized application and package it into a Docker image. For this, you need to call ./gradlew optimizedDockerBuild. It will produce a docker image that you can start using docker run. Alternatively, you can call ./gradlew optimizedDockerPush to push the generated image to your docker registry. All configuration options which apply to the standard docker image are also available to the optimized Docker images. 7.6. Building an optimized native Docker image This task also produces a Docker image, but it will build a native image containing the optimized application within a container, in order to produce a Docker image which runs the optimized application natively. The 2 tasks which are available for this are: optimizedDockerBuildNative to build the optimized native Docker image optimizedDockerPushNative to push the optimized native Docker image 8. Automatic test resources provisioning The Micronaut Gradle plugin integrates with Micronaut Test Resources to automatically provision test resources. In particular, it makes use of Testcontainers to automatically provide resources like databases or other external services like Kafka or RabbitMQ. Test resources are handled by a “test resources service” which is a server accepting requests for test resources, which lifecycle is handled by the Gradle plugin. A test resources request is, to simplify, a request to resolve a missing configuration property. For example, if the kafka.bootstrap-servers property isn’t set, Micronaut will query the test resources service for the value of this property. This will trigger the creaton of a a Kafka test container, and the service will answer with the URI to the bootstrap server. Note The test resources service makes use of Class Data Sharing on Java 17+ in order to make startup faster. In general, this shouldn’t be a problem but there may be cases where the test resources service fails to load because of a bug in the JDK. Should this happen to you, you can disable class data sharing explicitly using this configuration:GroovyKotlintasks.withType(StartTestResourcesService).configureEach {useClassDataSharing = false}Copy to Clipboard 8.1. The test resources plugin The easiest way to add test resources support is to apply the io.micronaut.test-resources plugin: GroovyKotlin plugins { id “io.micronaut.application” version “3.5.1” id “io.micronaut.test-resources” version “3.5.1” … } Copy to Clipboard Adding this plugin will be sufficient for most use cases. This will let Gradle automatically start containers, for example, when a particular property is not present in your configuration and that you run tests (./gradlew test) or the application in development mode (./gradlew run or ./gradlew -t run). For example, if the datasources.default.url configuration property is missing, and that your configuration contains: datasources: default: dialect: MYSQL Then a MySQL database will automatically be started and available for use in your tests: the url, username and password configuration properties will automatically be injected to your application. Please refer to the Micronaut Test Resources documentation for a list of all supported modules and their configuration options. 8.2. Configuring the test resources plugin In addition, the plugin will add a testResources extension to the micronaut configuration block, providing a number of options: GroovyKotlin micronaut { testResources { enabled = true // true by default version = “1.0.0” // override Micronaut Test Resources version explicitPort = 15471 // by default, uses a random port inferClasspath = true // true by default additionalModules.add(JDBC_MYSQL) // empty by default clientTimeout = 60 // in seconds, maximum time to wait for resources to be available, 60s by default sharedServer = true // false by default sharedServerNamespace = ‘custom’ // unset by default } } Copy to Clipboard the version property will let you override the default version of Micronaut Test Resources that the plugin uses. the enabled property can let you disable test resources provisioning (for example depending on the environment). by default, a test resources server will be started. This server uses a randomly available port, but you can override this by setting the explicitPort property instead. by default, the plugin will automatically determine which modules to add to the test resources support, by inspecting the dependencies declared in the project. For example, if you use both micronaut-data-jdbc and mysql-connector-java, it will automatically add support for MySQL provisioning. Under some circumstances, you might want to disable this behavior by setting the inferClasspath property to false. the additionalModules property can be used to explicitly declare test resources modules to be loaded. This is useful if inference failed to detect a module, or if you want to use a standalone test resources service. if set to true, then the test server which is used by the project can be shared between independent builds (e.g different Git repositories): this can be useful in conjunction with a a standalone test resources service, where for example a producer is used in one project, and a consumer is defined in another, but both need to use the same messaging server. if set, the sharedServerNamespace property will let you declare that the shared test resources service but be executed in a particular namespace. This can be useful if you need multiple shared servers (the default assumes a single shared server) Note The additionalModules property can be used to declare Micronaut Test Resources modules. However, it might be necessary to add more libraries on the test resources classpath. For example, you may need to add additional JDBC drivers. For this, you can use the testResourcesService configuration:dependencies {// declare an additional dependency on test resources classpathtestResourcesService “my:jdbc-driver:1.0”} 8.3. Standalone test resources service The io.micronaut.test-resources plugin works particularly well in single-module projects, or in multi-projects where test resources are not shared between modules. However, in some cases, you may want to reuse test containers for multiple projects of the same multi-project build, in order to save startup times for example. For this purpose, the io.micronaut.test-resources plugin can be applied on a project independently of the application or library plugins. For example, imagine a multi-project build which consists of : a Kafka consumer a Kafka producer functional tests integrating both If each project applies the io.micronaut.test-resources plugin independently, then each project will use its own test server, independently of the others. However, you might want to run the consumer in one terminal, and the producer in another, and still want them to talk to the same Kafka cluster. For this you have a couple options: you can use a shared test server, by setting the sharedServer property to true in the testResources extension. you can define a distinct project which role is to handle the test resources lifecycle The first solution comes with a major drawback: shared servers are shared by all projects in the multi-project build, but also between projects of the same build. However the configuration of the server will depend on the first one started. To avoid this problem it is recommended to declare a distinct project to handle test resources. Here, we’re going to add a project called shared-testresources which is going to be a test resources provider: GroovyKotlin // shared-testresources/build.gradle plugins { id “io.micronaut.test-resources” version “3.5.1” // (1) } micronaut { testResources { additionalModules.add(KAFKA) // (2) } } Copy to Clipboard use test-resources as a standalone plugin declare that it will provide Kafka containers Then each consumer of test resources need to apply the io.micronaut.test-resources-consumer plugin instead: GroovyKotlin plugins { id “io.micronaut.application” version “3.5.1” id “io.micronaut.test-resources-consumer” version “3.5.1” // (1) } dependencies { testResourcesService project(’:shared-testresources’) // (2) } Copy to Clipboard Use the test resources consumer plugin instead Declare that it consumes test resources provided by the :testresources project Now Gradle will automatically start test resources when one of the project needs them, and reuse them in all consumer projects. 8.4. Test resources lifecycle Test resources are handled by a service which is, by default, started at the beginning of a build, and stopped at the end. For example, if you invoke: ./gradlew test Then the test resources service will be started before tests are executed, then tests will share the resources provided by the service. Any test resource started during the test will be stopped when the build finishes. In continuous mode, the test resources are shared between builds. For example, if you run: ./gradlew -t test (run test in continuous mode) Then the test resources will be spawned during the first execution of tests. If you make any change to sources (production or test) and save the files, Gradle will rebuild the project and run the tests using the same test resources. This behavior can be extremely useful to save time since typically Docker containers would only be spawned once. If you interrupt the continuous build, the test resources will be stopped. Keeping test resources alive We have seen that running in continous mode allows keeping test resources alive as long as a continous build runs. However, what if you want to start the test resources service in the background, and keep it alive for multiple, independent builds (different invocations on the command line for example) ? You can achieve this behavior by running the startTestResourcesService command: ./gradlew startTestResourcesService This command must be the only command executed: it will start a test resources service in the background, which will be shared between builds. Therefore, it’s your responsibility to stop the service when you are done by running: ./gradlew stopTestResourcesService Warning When keeping a test resources service alive, you must understand that any change to the test resources configuration will be ignored until you stop the service. Implementing your own test resources resolver Micronaut Test Resources provides integration with a lot of databases and services, and also supports a fully declarative way to spawn test containers. However, there are cases where you might need to implement your own test resources resolver. The plugin makes it extremely straightforward: it declares an additional source set called testResources. You therefore write your test resources directly in src/testResources/java for example, and the test resource will be automatically made available. For example, let’s write a test resource which provides the value of the greeting.message property. First, let’s create the src/testResources/java/demo/GreetingTestResource.java file: src/testResources/java/demo/GreetingTestResource.java package demo; import io.micronaut.testresources.core.TestResourcesResolver; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import org.apache.commons.lang3.StringUtils; public class GreetingTestResource implements TestResourcesResolver { public static final String PROPERTY = “greeting.message”; @Override public List getResolvableProperties(Map