← Blog

Micronaut Framework 3 Upgrade Reference

These historical upgrade notes were migrated from the Micronaut Upgrade Guide archive.

Micronaut Framework 3.9.0

3.9.0 Breaking Changes

Since Micronaut Framework 3.9.0, CORS allowed-origins configuration does not support regular expressions to prevent accidentally exposing your API. You can use allowed-origins-regex, if you wish to support a regular expression.

Micronaut Framework 3.8.7

3.8.7 Breaking Changes

Micronaut Framework 3.8.7 updates to SnakeYAML 2.0 which addresses CVE-2022-1471. Many organizations' policies forbid their teams to use Micronaut Framework if the framework depends on a vulnerable dependency, even if the framework is unaffected. Micronaut Framework is not affected by CVE-2022-1471. Micronaut Framework uses SnakeYAML to load configuration in Micronaut applications. There is only one instance of SnakeYAML instantiation which uses the Safe Constructor. Using SnakeYaml’s SafeConstructor which is the recommended way to prevent this issue:

We recommend using SnakeYaml’s SafeConsturctor when parsing untrusted content to restrict deserialization.

Micronaut Framework 3.8.0

What’s new with 3.8.0

Key features:

  • GraalVM 22.3 Support

  • With Micronaut 3.8.0, you can use @RequestBean annotations with Records. Before 3.8.0, you could use a POJO as a controller method parameter and annotate the parameter with @RequestBean to bind any Bindable value (e.g., HttpRequest, @PathVariable, @QueryValue or @Header fields).

  • If you enable CORS from any origin while running your app in localhost (e.g., test or development), since 3.8.0, the CorsFilter returns 403 for non-localhost origins to protect you against drive-by localhost attacks.

Please read the Micronaut Framework 3.8.0 announcement blog post. You will find a detailed overview of what’s new in Micronaut 3.8.0.

Micronaut Framework 3.7.0

What’s new with 3.7.0

Several improvements:

  • If you want complete control of where your application loads configuration from, for example, due to security restrictions, you can disable the default PropertySourceLoader implementations by calling ApplicationContextBuilder::enableDefaultPropertySources(false) when starting your application.

  • Better java.time conversion for YAML configuration

  • Client SSL inner configuration is Bootstrap context compatible.

  • UriBuilder methods queryParam and replaceQueryParam ignore null values.

  • It is possible to stop the Netty server without stopping the Application context.

  • You can declare beans at runtime using interfaces.

  • You can mark static methods as @Executable.

  • A big HTTP client refactor.

Spring integration improvements

  • Micronaut Spring contains improvements for developers who want to use Micronaut modules with a Spring application or consume Spring libraries from a Micronaut application.

New modules:

Please read the Micronaut Framework 3.7.0 announcement blog post. You will find a detailed overview of what’s new in Micronaut 3.7.0.

Micronaut Framework 3.6.0

What’s new with 3.6.0

Key features:

Please read the Micronaut Framework 3.6.0 announcement blog post. You will find a detailed overview of what’s new in Micronaut 3.6.0.

Micronaut Core features:

Don’t apply a @Filter for services

It is possible to exclude services from an HTTP Client Filter with the member excludeServiceId of @Filter.

@Filter(patterns = '/**', excludeServiceId = 'authClient')
public class AppHttpClientFilter implements HttpClientFilter {

Netty runtime

This version upgrades Netty from 4.1.77 to 4.1.79. Moreover, it contains improvements to the API to configure the Netty Client Pipeline and to configure the Netty Server Pipeline.

Improvements to HttpClientException

If present a serviceId field is populated in the HttpClientException and shown in the exception message.

Modules Upgrades

  • Micronaut AWS 3.5.3 to 3.7.0

  • Micronaut Azure 3.2.3 to 3.3.0

  • Micronaut Cache 3.4.1 to 3.5.0

  • Micronaut Cassandra 4.0.0 to 5.1.1

  • Micronaut Coherence 3.4.1 to 3.5.1

  • Micronaut Data 3.4.3 to 3.7.2

  • Micronaut Elasticsearch 4.2.0 to 4.3.0

  • Micronaut Email 1.2.3 to 1.3.1

  • Micronaut Flyway 5.3.0 to 5.4.0

  • Micronaut GCP 4.2.1 to 4.4.0

  • Micronaut GraphQL 3.0.0 to 3.1.0

  • Micronaut Groovy 3.1.0 to 3.2.0

  • Micronaut JaxRS 3.3.0 to 3.4.0

  • Micronaut JMX 3.0.0 to 3.1.0

  • Micronaut Kafka 4.3.1 to 4.4.0

  • Micronaut Micrometer 4.3.0 to 4.4.0

  • Micronaut Microstream 1.0.0-M1 to 1.0.0

  • Micronaut Liquibase 5.3.0 to 5.4.1

  • Micronaut Mongo 4.2.0 to 4.4.0

  • Micronaut Neo4J 5.0.0 to 5.1.0

  • Micronaut Nats 3.0.0 to 3.1.0

  • Micronaut OpenAPI 4.2.2 to 4.4.3

  • Micronaut Picocli 4.2.1 to 4.3.0

  • Micronaut Problem 2.3.1 to 2.4.0

  • Micronaut RabbitMQ 3.1.0 to 3.3.0

  • Micronaut R2DBC 3.0.0 to 3.0.1

  • Micronaut Reactor 2.2.3 to 2.3.1

  • Micronaut Redis 5.2.0 to 5.3.0

  • Micronaut RxJava3 2.2.1 to 2.3.0

  • Micronaut Serialization 1.1.1 to 1.3.0

  • Micronaut Servlet 3.2.3 to 3.3.0

  • Micronaut Spring 4.1.1 to 4.2.1

  • Micronaut SQL 4.4.1 to 4.6.3

  • Micronaut Test 3.3.1 to 3.4.0

  • Micronaut TOML 1.0.0 to 1.1.1

  • Micronaut Tracing 4.1.1 to 4.2.1

  • Micronaut Views 3.4.0 to 3.5.0

  • Micronaut Jackson XML 3.0.1 to 3.1.0

Micronaut Framework 3.5.0

What’s new with 3.5.0

GraalVM 22.1.0

Micronaut framework 3.5 supports GraalVM 22.1.0.

Incremental Compilation for Gradle Builds

Micronaut framework 3.5 supports fully incremental compilation, including GraalVM metadata for Gradle Builds.

Micronaut Data

  • Postgres enums for JDBC.

  • Pagination for reactive repositories and specifications.

  • Pagination for async, coroutines repositories, and specifications.

Turbo Integration

Micronaut Views adds integration with Turbo

New Module - Micronaut Microstream

Micronaut Microstream eases working with MicroStream, a native Java object graph storage engine.

@Scheduled with Time Zones

Optionally, you can specify a time zone when using the @Scheduled annotation.

@Scheduled(cron = '1/33 0/1 * 1/1 * ?', zoneId = "America/Chicago")
void runCron() {
...
..

Support validation groups with @Validated

You can enforce a subset of constraints using validation groups using groups on the @Validated.

Advanced Listener Configuration

Micronaut framework 3.5.0 offers more flexibility in configuring the HTTP Server. Instead of configuring a single port, you can specify each listener manually.

EPHEMERAL FACTORIES

A Factory has the default scope @Singleton, and it is destroyed with the context. Since Micronaut framework v3.5.0, you can dispose of the factory after producing a bean by annotating your factory class with @Prototype and @Factory

Module upgrades

Several modules publish a BOM (Bill of Materials) or use a Gradle Version Catalogs:

Schema Migration Modules

Micronaut Framework 3.4.0

What’s new with 3.4.0

Localized Message Source

You can now inject LocalizedMessageSource, a @RequestScope bean, in your controllers to resolve localized messages for the current HTTP Request. It works in combination with Micronaut Locale Resolution capabilities.

Referencing bean properties in @Requires.

@Requires(bean=Config.class, beanProperty="foo", value="John")

Micronaut Data MongoDB

Micronaut AOT and Maven

Micronaut AOT is now fully supported for Maven users. Enabling AOT is as simple as passing -Dmicronaut.aot.enabled when running, testing, or packaging your application.

For more details, check the Micronaut Maven Plugin documentation.

Micronaut TOML

Micronaut TOML allows you to write your application configuration with TOML in addition to Properties, YAML, Groovy or Config4k.

Micronaut Security

Micronaut Security 3.4.1 responds with an error when an authenticated user visits a sensitive endpoint. This forces the developer to define how they want their application to behave in that scenario. Read the release notes and the documentation to learn more.

BOM Modules

Several projects include a BOM (Bills of Materials) module:

Other Module Upgrades

Micronaut Framework 3.3.0

What’s new with 3.3.0

GraalVM 22.0.0.2

Micronaut now supports the latest GraalVM 22.0.0.2 release.

Environment Endpoint

A new API api:management.endpoint.env.EnvironmentEndpointFilter[] has been created to allow applications to customize which keys should have their values masked and which keys should not have their values masked. See the documentation for full details.

AOP Interceptor Binding

When binding an AOP annotation to an interceptor, only the presence of the annotation is used to determine if the interceptor should be applied. Now it’s possible to also bind based on the values of the annotation. To enable this feature, set the bindMembers member of the ann:aop.InterceptorBinding[] annotation to true.

Netty Buffer Allocation

It is now possible to configure the default Netty buffer allocator. See the configuration reference.

Improved Flexibility in Class Style

Many features of the Micronaut framework rely on the convention of getters and setters. Due to things like records and builders, the method names we look for are now configurable with the ann:core.annotation.AccessorsStyle[] annotation. For example, the annotation can be placed on ann:context.annotation.ConfigurationProperties[] beans to allow for binding configuration to methods that do not begin with set. It can also be used with classes annotated with ann:core.annotation.Introspected[].

Access Log Exclusions

The Netty access logger now supports excluding requests based on a set of regular expression patterns that match against the URI. See the AccessLogger documentation.

New Serialization/Deserialization Module

Micronaut Serialization is a new module created as an alternative to Jackson. It supports serializing and deserializing Java types (including Java 17 records) to and from JSON and other formats.

Users now have the choice of an alternative implementation that’s largely compatible with existing Jackson annotations but contains many benefits, including the elimination of reflection, compile-time validation, greater security because only explicit types are serializable, and reduction of native image build sizes, build times, and memory usage.

New Email Module

Micronaut Email is a new module to ease sending emails from a Micronaut application. It provides integration with transactional email providers such as Amazon Simple Email Service, Postmark, Mailjet or SendGrid.

Micronaut AOT

During this minor cycle, we released a milestone release of a new module Micronaut AOT. You can use Micronaut AOT and use the build-time optimizations provided by the module to achieve faster startup times via the Micronaut Gradle Plugin. Please, read more about it in the announcement blog post.

Micronaut Kubernetes 3.3.0

Micronaut Kubernetes 3.3 adds support to easily create the Kubernetes Operator. The Kubernetes Operator is a known pattern used to extend the capabilities of Kubernetes by creating application specific controllers for both native and custom resources. See more on Kubernetes Operator.

The version of Micronaut Kubernetes 3.3.0 also adds new Kubernetes reactive client for RxJava3.

Other Module Upgrades

  • Micronaut Cache 3.1.0

  • Micronaut Discovery Client 3.1.0

  • Micronaut Elasticsearch 4.2.0

  • Micronaut Flyway 5.1.1

  • Micronaut Kafka 4.1.1

  • Micronaut Kotlin 3.1.0

  • Micronaut Liquibase 5.1.1

  • Micronaut Openapi 4.0.0

  • Micronaut Picocli 4.1.0

  • Micronaut Problem 2.2.0

  • Micronaut Security 3.3.0

  • Micronaut Sql 4.1.1

  • Micronaut Toml 1.0.0-M2

  • Micronaut Views 3.1.2

Other Dependency Upgrades

  • Apache Commons DBCP 2.9.0

  • Elasticsearch 7.16.3

  • Flyway 8.4.2

  • Hibernate 5.5.9.Final

  • Kotlin 1.6.10

  • Liquibase 4.7.1

  • Logback 1.2.10

  • Swagger 2.1.12

3.3.0 Breaking Changes

endpoints:
  env:
    enabled: true

This will then be available, but mask all values. To restore the previous functionality, you can add a bean that implements api:management.endpoint.env.EnvironmentEndpointFilter[]:

Legacy Environment Filtering Bean
@Singleton
public class LegacyEnvEndpointFilter implements EnvironmentEndpointFilter {
    @Override
    public void specifyFiltering(@NotNull EnvironmentFilterSpecification specification) {
        specification.legacyMasking();
    }
}

See the documentation for more filtering options.

Micronaut Framework 3.2.4

3.2.4 Breaking Changes

Micronaut Framework 3.2.0

What’s new with 3.2.0

GraalVM 21.3.0

Micronaut has been updated to support the latest GraalVM 21.3.0 release. Please keep in mind that, starting with 21.3.0, GraalVM no longer releases a version based on JDK 8. If you still use Java 8, use the GraalVM JDK 11 distribution.

The official GraalVM Maven plugin has new GAV coordinates so if you have declared it in your pom.xml update the coordinates to:

<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
...
</plugin>

Please check the official documentation about how to customize the plugin.

Gradle Plugin 3.0.0

A new major version of the Gradle plugin has been released, including internal changes to use Gradle’s lazy configuration APIs. In the process, documentation has been rewritten.

Support for GraalVM now delegates to the official GraalVM plugin. We recommend to upgrade in order to get the latest bugfixes, but this constitutes a breaking change for some users:

  • the nativeImage task is now replaced with nativeCompile

  • native image configuration happens in the graalvmNative DSL extension instead of the nativeCompile task

  • native image building makes use of Gradle’s toolchain support. Please refer to the documentation for help.

Note
You can still build existing applications or libraries using the 2.x version of the Gradle plugin. Documentation for this version can be found here.

Kotlin 1.6.0

Micronaut 3.2.0 includes support for Kotlin 1.6.0.

HTTP Features

WebSocket Ping API

WebSocket ann:websocket.annotation.OnMessage[] methods can now accept a api:websocket.WebSocketPongMessage[] parameter that will receive a WebSocket pong sent as a response to a ping submitted using the new sendPingAsync method on api:websocket.WebSocketSession[].

HTTP2 Server Push

It is now possible to send resources, e.g. stylesheets required by a HTML page, to the client alongside the request for the page using the HTTP2 server push protocol. See the HTTP/2 documentation for information on how to use this feature.

JsonView on request bodies

You can now specify the Jackson @JsonView annotation on @Body parameters to controller methods.

WebSocket ws/wss protocol support

The WebSocket clients now support the ws/wss protocol. To implement this change, the api:websocket.WebSocketClient[] create methods now take a URI instead of a URL. The URL methods have been deprecated.

Note: Should you be calling WebSocketClient.create(null), the method call is now ambiguous. Insert a cast in that case: WebSocketClient.create((URI) null)

SSL handshake timeout configuration

The SSL handshake timeout can now be configured using the micronaut.ssl.handshakeTimeout and micronaut.http.client.ssl.handshakeTimeout configurations for the server and client respectively.

Module Upgrades

Micronaut Data 3.2.0
  • Repositories with JPA Criteria API specification for Micronaut JDBC/R2DBC

  • Expandable query parameters optimizations

Reactive Modules
  • The RxJava2, RxJava3, and Reactor modules have been updated with the equivalent static create methods on their core counterparts.

Micronaut Micrometer 4.1.0
  • Adds support for metrics with gRPC

Micronaut Security 3.2.0
  • The way JSON Web Key Sets are being cached has been greatly improved for scenarios where there are multiple key sets.

Other Module Upgrades
  • Elasticsearch 7.15.2

  • Flyway 8.0.2

  • gRPC 1.39.0

  • Liquibase 4.6.1

  • Micronaut Elasticsearch 4.0.0

  • Micronaut Flyway 5.0.0

  • Micronaut gRPC 3.1.1

  • Micronaut Liquibase 5.0.0

  • Micronaut OpenAPI 3.2.0

  • Micronaut Redis 5.1.0

  • Testcontainers 1.16.1

3.2.0 Breaking Changes

  • The HTTP client now does SSL certificate verification by default. The old insecure behavior can be re-enabled by setting the micronaut.http.client.ssl.insecureTrustAllCertificates property to true, but consider using a trust store instead if you’re using self-signed certificates.

  • Maven GraalVM Native Image plugin has new GAV coordinates. If you have declared it in your pom.xml please update the coordinates to:

<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
...
</plugin>
  • WebSocketClient.create has been modified to accept a URI parameter instead of URL. The old URL methods still exist, but when called with null like WebSocketClient.create(null), the method call is now ambiguous. Please insert a cast to URI: WebSocketClient.create((URI) null). The same applies for the create method that accepts an additional HttpClientConfiguration parameter.

Micronaut Framework 3.1.0

What’s new with 3.1.0

Core Features

Primitive Beans

Factory Beans can now create beans that are primitive types or primitive array types.

See the section on Primitive Beans and Arrays in the documentation for more information.

Repeatable Qualifiers

Qualifiers can now be repeatable (an annotation annotated with java.lang.annotation.Repeatable) allowing narrowing bean resolution by a complete or partial match of the qualifiers declared on the injection point.

InjectScope

A new ann:context.annotation.InjectScope[] annotation has been added which destroys any beans with no defined scope and injected into a method or constructor annotated with @Inject after the method or constructor completes.

More Build Time Optimizations

Further build time metadata optimizations have been added included reducing the number and size of the classes generated to support Bean Introspection and including knowledge of repeatable annotations in generated metadata avoiding further reflective calls and optimizing Micronaut’s memory usage, in particular with GraalVM.

Improvements to Context Propagation

Support for Reactive context propagation has been further improved by inclusion of request context information in the Reactor context and documentation on how to effectively propagate the context across reactive flows when using Kotlin coroutines.

Improvements to the Element API

The build-time api:inject.ast.Element[] API has been improved in a number of ways:

  • New methods were added to the api:inject.ast.MethodElement[] API to resolve the retriever type and throws declaration

  • A new experimental API has been added to the api:inject.ast.ClassElement[] API to resolve generic placeholders and resolve the generic bound to the element

HTTP Features

Filter By Regex

HTTP filters now support matching URLs by a regular expression. Set the patternStyle member of the annotation to REGEX and the value will be treated as a regular expression.

Random Port Binding

The way the server binds to random ports has improved and should result in fewer port binding exceptions in tests.

Client Data Formatting

The ann:core.convert.format.Format[] annotation now supports several new values that can be used in conjunction with the declarative HTTP client to support formatting data in several new ways. See the client parameters documentation for more information.

StreamingFileUpload

The api:http.multipart.StreamingFileUpload[] API has been improved to support streaming directly to an output stream. As with the other transferTo methods, the write to the stream is offloaded to the IO pool automatically.

Server SSL Configuration

The SSL configuration for the Netty server now responds to refresh events. This allows for swapping out certificates without having to restart the server. See the https documentation for information on how to trigger the refresh.

New Netty Server API

If you wish to programmatically start additional Netty servers on different ports with potentially different configurations, new APIs have been added to do so including a new api:http.server.netty.NettyEmbeddedServerFactory[] interface.

See the documentation on Starting Secondary Servers for more information.

Deprecations

The netty.responses.file.* configuration is deprecated in favor of micronaut.server.netty.responses.file.*. The old configuration key will be removed in the next major version of the framework.

Module Upgrades

Micronaut Data 3.1.0
  • Kotlin’s coroutines support. New repository interface CoroutineCrudRepository.

  • Support for AttributeConverter

  • R2DBC upgraded to Arabba-SR11

  • JPA Criteria specifications

Micronaut JAX-RS 3.1

The JAX-RS module now integrated with Micronaut Security allowing binding of the JAX-RS SecurityContext

Micronaut Kubernetes 3.1.0

Micronaut Kubernetes 3.1 introduces new annotation @Informer. By using the annotation on the ResourceEventHandler the Micronaut will instantiate the SharedInformer from the official Kubernetes Java SDK. Then you only need to take care of handling the changes of the watched Kubernetes resource. See more on Kubernetes Informer.

Micronaut Oracle Coherence 3.0.0

The Micronaut Oracle Coherence module is now out of preview status and includes broad integration with Oracle Coherence including support for caching, messaging and Micronaut Data.

3.1.0 Breaking Changes

Retrieving the port from the Netty embedded server is no longer supported if the server is configured to bind to a random port and the server has not been started.

Micronaut Framework 3.0.0

Upgrading from Micronaut Framework 2.0 to 3.0

This section covers the steps required to upgrade a Micronaut framework 2.x application to Micronaut framework 3.0.0.

The sections below go into more detail, but at a high level the process generally involves:

  • updating versions

  • updating annotations

  • choosing a Reactive implementation

  • adjusting code affected by breaking changes

Typically, upgrading should be straightforward, but it’s possible to save yourself some work with OpenRewrite, an automated refactoring tool that you can use to make many of the required upgrade changes.

Automating Upgrades with OpenRewrite

OpenRewrite works with Micronaut applications written in Java, but OpenRewrite doesn’t currently support Kotlin or Groovy. Like any automated tool, it does much of the work for you, but be sure to review the resulting changes and manually make any changes that aren’t supported by OpenRewrite, for example converting from RxJava2 to Reactor.

Note
If you will be using OpenRewrite, don’t make any upgrade changes yet that would cause your application not to compile, for example updating the Micronaut version to 3.x. This would cause application classes that use javax.inject annotations like @Singleton or RxJava2 classes like io.reactivex.Flowable to not compile since those dependencies are no longer included by default. Instead, use OpenRewrite to do the initial work and just do the steps yourself that aren’t possible or practical to automate.

Adding OpenRewrite support to your build is easy, it just requires adding the Gradle or Maven plugin and configuring the plugin to use the Micronaut upgrade recipe.

See the Gradle feature diff or the Maven feature diff to see the required build script changes.

Once you’ve made the build script changes, you can "dry-run" the Micronaut upgrade recipe to see what changes would be made.

For Gradle, run

$ ./gradlew rewriteDryRun

and view the diff report generated in build/reports/rewrite/rewrite.patch

and for Maven, run

$ ./mvnw rewrite:dryRun

and view the diff report generated in target/site/rewrite/rewrite.patch.

Then you can run the recipe for real, letting OpenRewrite update your code.

For Gradle, run

$ ./gradlew rewriteRun

and for Maven, run

$ ./mvnw rewrite:run

Once the changes have been made, you could remove the plugin, but it’s fine to leave it since OpenRewrite doesn’t run automatically, only when you run one of its commands. And there are many more recipes available beyond the Micronaut upgrade recipe that you might want to include to automate other code changes.

The plugin includes another command to list all recipes currently in the classpath (in this case the core recipes plus those added by the rewrite-micronaut module).

For Gradle, run

$ ./gradlew rewriteDiscover

and for Maven, run

$ ./mvnw rewrite:discover

and the available recipes and styles will be output to the console. Check out the OpenRewrite documentation for more information and to see the many other available recipes available.

Version Update

If you use Gradle, update the micronautVersion property in gradle.properties, e.g.

gradle.properties
micronautVersion={version}

If you use Maven, update the parent POM version and micronaut.version property in pom.xml, e.g.

pom.xml
<parent>
  <groupId>io.micronaut</groupId>
  <artifactId>micronaut-parent</artifactId>
  <version>{version}</version>
</parent>
<properties>

<micronaut.version>{version}</micronaut.version>

</properties>

Build Plugin Update

If you use the Micronaut Gradle plugin update to the latest version.

For Maven users the plugin version is updated automatically when you update the Micronaut version.

Inject Annotations

The javax.inject annotations are no longer a transitive dependency. The Micronaut framework now ships with the Jakarta inject annotations. Either replace all javax.inject imports with jakarta.inject, or add a dependency on javax-inject to continue using the older annotations:

dependency:javax.inject:javax.inject:1[]

Any code that relied on the javax.inject annotations being present in the annotation metadata will still work as expected, however any code that interacts with them must be changed to no longer reference the annotation classes themselves. Static variables in the AnnotationUtil class (e.g. AnnotationUtil.INJECT, AnnotationUtil.SINGLETON, etc.) should be used in place of the annotation classes when working with annotation metadata.

Nullability Annotations

The Micronaut framework now only comes with its own set of annotations to declare nullability. The findbugs, javax, and jetbrains annotations are all still supported, however you must add a dependency to use them. Either switch to the Micronaut ann:core.annotation.Nullable[] / ann:core.annotation.NonNull[] annotations or add a dependency for the annotation library you wish to use.

RxJava2

The Micronaut framework no longer ships any reactive implementation as a default in any of our modules or core libraries. Upgrading to Micronaut 3 requires choosing which reactive streams implementation to use, and then adding the relevant dependency.

For those already using RxJava3 or Project Reactor, there should be no changes required to upgrade to the Micronaut framework 3. If you use RxJava2 and wish to continue using it, you must add a dependency:

dependency:io.micronaut.rxjava2:micronaut-rxjava2[gradleScope="implementation"]

In addition, if any of the Rx HTTP client interfaces were used, a dependency must be added and the imports must be updated.

dependency:io.micronaut.rxjava2:micronaut-rxjava2-http-client[gradleScope="implementation"]

Table 1. RxJava2 HTTP Client Imports
Old New

io.micronaut.http.client.RxHttpClient

io.micronaut.rxjava2.http.client.RxHttpClient

io.micronaut.http.client.RxProxyHttpClient

io.micronaut.rxjava2.http.client.proxy.RxProxyHttpClient

io.micronaut.http.client.RxStreamingHttpClient

io.micronaut.rxjava2.http.client.RxStreamingHttpClient

io.micronaut.http.client.sse.RxSseClient

io.micronaut.rxjava2.http.client.sse.RxSseClient

io.micronaut.websocket.RxWebSocketClient

io.micronaut.rxjava2.http.client.websockets.RxWebSocketClient

If the Netty based server implementation is being used, an additional dependency must be added:

dependency:io.micronaut.rxjava2:micronaut-rxjava2-http-server-netty[gradleScope="implementation"]

Note
We recommend switching to Project Reactor as that is the implementation used internally by Micronaut. Adding a dependency to RxJava2 will result in both implementations in the runtime classpath of your application.

Environment endpoint

As of 3.3.0, the environmental endpoint is now disabled by default, please see the breaking changes for how to restore functionality.

What’s new with 3.0.0

Core Features

Optimized Build-Time Metadata

Micronaut 3.0 introduces a new build time metadata format that is more efficient in terms of startup and code size.

The result is significant improvements to startup and native image sizes when building native images with GraalVM Native Image.

It is recommended that users re-compile their applications and libraries with Micronaut 3.0 to benefit from these changes.

Support for GraalVM 21.2

Micronaut has been updated to support the latest GraalVM 21.2 release.

Jakarta Inject

The jakarta.inject annotations are now the default injection annotations for Micronaut 3

Support for JSR-330 Bean Import

Using the ann:context.annotation.Import[] annotation it is now possible to import bean definitions into your application where JSR-330 (either javax.inject or jakarta.inject annotations) are used in an external library.

See the documentation on Bean Import for more information.

Support for Controlling Annotation Inheritance

api:core.annotation.AnnotationMetadata[] inheritance can now be controlled via Java’s @Inherited annotation. If an annotation is not explicitly annotated with @Inherited it will not be included in the metadata. See the Annotation Inheritance section of the documentation for more information.

Note
This is an important behavioural change from Micronaut 2.x, see the Breaking Changes section for information on how to upgrade.
Support Narrowing Injection by Generic Type Arguments

Micronaut can now resolve the correct bean to inject based on the generic type arguments specified on the injection point:

snippet::io.micronaut.docs.inject.generics.Vehicle[tags="constructor",indent=0]

For more information see the section on Qualifying by Generic Type Arguments.

Support for using Annotation Members in Qualifiers

You can now use annotation members in qualifiers and specify which members should be excluded with the new ann:context.annotation.NonBinding[] annotation.

For more information see the section on Qualifying By Annotation Members.

Support for Limiting the Injectable Types

You can now limit the exposed types of a bean using the typed member of the ann:context.annotation.Bean[] annotation:

snippet::io.micronaut.docs.inject.typed.V8Engine[tags="class",indent=0]

For more information see the section on Limiting Injectable Types.

Factories can produce bean from fields

Beans defined with the ann:context.annotation.Factory[] annotation can now produce beans from public or package protected fields, for example:

snippet::io.micronaut.docs.factories.VehicleMockSpec[tags="class",indent=0]

For more information see the Bean Factories section of the documentation.

Enhanced BeanProvider Interface

The api:context.BeanProvider[] interface has been enhanced with new methods such as iterator() and stream() as well as methods to check for bean existence and uniqueness.

New @Any Qualifier for use in Bean Factories

A new ann:context.annotation.Any[] qualifier has been introduced to allow injecting any available instance into an injection point and can be used in combination with the new BeanProvider interface mentioned above to allow more dynamic behaviour.

snippet::io.micronaut.docs.qualifiers.any.Vehicle[tags="imports,clazz", indent=0, title="Using BeanProvider with Any"]

The annotation can also be used on ann:context.annotation.Factory[] methods to allow customization of how objects are injected via the api:inject.InjectionPoint[] API.

Support for Fields in Bean Introspections

Bean introspections on public or package protected fields are now supported:

snippet::io.micronaut.docs.ioc.beans.User[tags="class", indent=0]

For more information see the "Bean Fields" section of the Bean Introspections documentation.

ApplicationEventPublisher has now a generic event type

For the performance reasons it’s advised to inject an instance of ApplicationEventPublisher with a generic type parameter - ApplicationEventPublisher<MyEvent>.

AOP Features

Support for Constructor Interception

It is now possible to intercept bean construction invocations through the api:aop.ConstructorInterceptor[] interface and ann:aop.AroundConstruct[] annotation.

See the section on Bean Life Cycle Advice for more information.

Support for @PostConstruct & @PreDestroy Interception

It is now possible to intercept @PostConstruct and @PreDestroy method invocations through the api:aop.MethodInterceptor[] interface and ann:aop.InterceptorBinding[] annotation.

See the section on Bean Life Cycle Advice for more information.

Random Configuration Values

It is now possible to set a max and a range for random numbers in configuration. For example to set an integer between 0 and 9, ${random.int(10)} can be used as the configuration value. See the documentation under "Using Random Properties" for more information.

Project Reactor used internally instead of RxJava2

Micronaut 3 uses internally Project Reactor instead RxJava 2. Project Reactor allows Micronaut 3 to simplify instrumentation, thanks to Reactor’s Context, simplifies conversion login and eases the integration with R2DBC drivers. We recommend users to migrate to Reactor. However, it is possible to continue to use RxJava. See Reactive Programming section.

Module Upgrades

Micronaut Data 3.1.0
  • Kotlin’s coroutines support. New repository interface CoroutineCrudRepository.

  • Support for AttributeConverter

  • R2DBC upgraded to Arabba-SR11

  • JPA Criteria specifications

Micronaut Micrometer 4.0.0

The Micrometer module has been upgraded and now supports repeated definitions of the @Timed annotation as well as also supporting the @Counted annotation for counters when you add the micronaut-micrometer-annotation dependency to your annotation processor classpath.

Micronaut Oracle Cloud 2.0.0

Micronaut’s Oracle Cloud Integration has been updated with support for Cloud Monitoring and Tracing.

Micronaut Cassandra 4.0.0

The Micronaut Cassandra integration now includes support for GraalVM out of the box.

Other Modules
  • Micronaut Acme 3.0.0

  • Micronaut Aws 3.0.0

  • Micronaut Azure 3.0.0

  • Micronaut Cache 3.0.0

  • Micronaut Discovery Client 3.0.0

  • Micronaut ElasticSearch 3.0.0

  • Micronaut Flyway 4.1.0

  • Micronaut GCP 4.0.0

  • Micronaut GraphQL 3.0.0

  • Micronaut Groovy 3.0.0

  • Micronaut Grpc 3.0.0

  • Micronaut Jackson XML 3.0.0

  • Micronaut Jaxrs 3.0.0

  • Micronaut JMX 3.0.0

  • Micronaut Kafka 4.0.0

  • Micronaut Kotlin 3.0.0

  • Micronaut Kubernetes 3.0.0

  • Micronaut Liquibase 4.0.2

  • Micronaut Mongo 4.0.0

  • Micronaut MQTT 2.0.0

  • Micronaut Multitenancy 4.0.0

  • Micronaut Nats Io 3.0.0

  • Micronaut Neo4j 5.0.0

  • Micronaut OpenApi 3.0.1

  • Micronaut Picocli 4.0.0

  • Micronaut Problem Json 2.0.0

  • Micronaut R2DBC 2.0.0

  • Micronaut RabbitMQ 3.0.0

  • Micronaut Reactor 2.0.0

  • Micronaut Redis 5.0.0

  • Micronaut RSS 3.0.0

  • Micronaut RxJava2 1.0.0 (new)

  • Micronaut RxJava3 2.0.0

  • Micronaut Security 3.0.0

  • Micronaut Servlet 3.0.0

  • Micronaut Spring 4.0.0

  • Micronaut SQL 4.0.0

  • Micronaut Test 3.0.0

  • Micronaut Views 3.0.0

Dependency Upgrades
  • Caffeine 2.9.1

  • Cassandra 4.11.1

  • Elasticsearch 7.12.0

  • Flyway 7.12.1

  • GraalVM 21.2.0

  • H2 Database 1.4.200

  • Hazelcast 4.2.1

  • Hibernate 5.5.3.Final

  • Hikari 4.0.3

  • Infinispan 12.1.6.Final

  • Jackson 2.12.4

  • Jaeger 1.6.0

  • Jakarta Annotation API 2.0.0

  • JAsync 1.2.2

  • JDBI 3.20.1

  • JOOQ 3.14.12

  • JUnit 5.7.2

  • Kafka 2.8.0

  • Kotlin 1.5.21

  • Kotlin Coroutines 1.5.1

  • Ktor 1.6.1

  • Liquibase 4.4.3

  • MariaDB Driver 2.7.3

  • Micrometer 1.7.1

  • MongoDB 4.3.0

  • MS SQL Driver 9.2.1.jre8

  • MySQL Driver 8.0.25

  • Neo4j Driver 4.2.7

  • Postgres Driver 42.2.23

  • Reactor 3.4.8

  • RxJava3 3.0.13

  • SLF4J 1.7.29

  • Snake YAML 1.29

  • Spock 2.0-groovy-3.0

  • Spring 5.3.9

  • Spring Boot 2.5.3

  • Testcontainers 1.15.3

  • Tomcat JDBC 10.0.8

  • Vertx SQL Drivers 4.1.1

3.0.0 Breaking Changes

Core Changes

Annotation Inheritance

Possibly the most important change in Micronaut 3.0 is how annotations are inherited from parent classes, methods and interfaces.

Micronaut 2.x did not respect the rules defined in the jdk:java.lang.reflect.AnnotatedElement[], and inherited all annotations from parent interfaces and types regardless of the presence of the jdk:java.lang.annotation.Inherited[] annotation.

With Micronaut 3.x and above only annotations that are explicitly meta-annotated with jdk:java.lang.annotation.Inherited[] are now inherited from parent classes and interfaces. This applies to types in the case where one extends another, and methods in the case where one overrides another.

Many of Micronaut’s core annotations have been annotated with @Inherited, so no change will be required, but some annotations that are either outside Micronaut or defined by user code will need changes to code or the annotation.

In general, behaviour which you wish to override is not inherited by default in Micronaut 3.x and above including Bean Scopes, Bean Qualifiers, Bean Conditions, Validation Rules and so on.

The following table summarizes the core Micronaut annotations and which are inherited and which are not:

Table 2. Annotation Inheritance in Micronaut 3.x and above
Annotation Inherited

ann:aop.Adapter[]

ann:aop.Around[]

ann:aop.AroundConstruct[]

ann:aop.InterceptorBean[]

ann:aop.InterceptorBinding[]

ann:aop.Introduction[]

ann:core.annotation.Blocking[]

ann:core.annotation.Creator[]

ann:core.annotation.EntryPoint[]

ann:core.annotation.Experimental[] (source level)

ann:core.annotation.Indexes[] & ann:core.annotation.Indexed[]

ann:core.annotation.Internal[]

ann:core.annotation.Introspected[]

ann:core.annotation.NonBlocking[]

ann:core.annotation.Nullable[]

ann:core.annotation.NonNull[]

ann:core.annotation.Order[]

ann:core.annotation.ReflectiveAccess[]

ann:core.annotation.TypeHint[]

ann:core.async.annotation.SingleResult[]

ann:core.bind.annotation.Bindable[]

ann:core.convert.format.Format[]

ann:core.convert.format.MapFormat[]

ann:core.convert.format.ReadableBytes[]

ann:core.version.annotation.Version[]

ann:context.annotation.AliasFor[]

ann:context.annotation.Any[]

ann:context.annotation.Bean[]

ann:context.annotation.BootstrapContextCompatible[]

ann:context.annotation.ConfigurationBuilder[]

ann:context.annotation.ConfigurationInject[]

ann:context.annotation.ConfigurationProperties[]

ann:context.annotation.ConfigurationReader[]

ann:context.annotation.Context[]

ann:context.annotation.DefaultImplementation[]

ann:context.annotation.DefaultScope[]

ann:context.annotation.EachBean[]

ann:context.annotation.Executable[]

ann:context.annotation.Factory[]

ann:context.annotation.NonBinding[]

ann:context.annotation.Parallel[]

ann:context.annotation.Parameter[]

ann:context.annotation.Primary[]

ann:context.annotation.Property[]

ann:context.annotation.PropertySource[]

ann:context.annotation.Prototype[]

ann:context.annotation.Replaces[]

ann:context.annotation.Requirements[]

ann:context.annotation.Requires[]

ann:context.annotation.Secondary[]

ann:context.annotation.Type[]

ann:context.annotation.Value[]

ann:http.annotation.Controller[]

ann:http.annotation.Body[]

ann:http.annotation.Consumes[]

ann:http.annotation.CookieValue[]

ann:http.annotation.CustomHttpMethod[]

ann:http.annotation.Delete[]

ann:http.annotation.Error[]

ann:http.annotation.Filter[]

ann:http.annotation.FilterMatcher[]

ann:http.annotation.Get[]

ann:http.annotation.Head[]

ann:http.annotation.Header[]

ann:http.annotation.Headers[]

ann:http.annotation.HttpMethodMapping[]

ann:http.annotation.Options[]

ann:http.annotation.Part[]

ann:http.annotation.Patch[]

ann:http.annotation.PathVariable[]

ann:http.annotation.Post[]

ann:http.annotation.Produces[]

ann:http.annotation.Put[]

ann:http.annotation.QueryValue[]

ann:http.annotation.RequestAttribute[]

ann:http.annotation.RequestAttributes[]

ann:http.annotation.RequestBean[]

ann:http.annotation.Status[]

ann:http.annotation.Trace[]

ann:http.annotation.UriMapping[]

ann:http.client.annotation.Client[]

ann:jackson.annotation.JacksonFeatures[]

ann:management.endpoint.annotation.Delete[]

ann:management.endpoint.annotation.Endpoint[]

ann:management.endpoint.annotation.Read[]

ann:management.endpoint.annotation.Sensitive[]

ann:management.endpoint.annotation.Selector[]

ann:management.endpoint.annotation.Write[]

ann:management.health.indicator.annotation.Liveness[]

ann:management.health.indicator.annotation.Readiness[]

ann:messaging.annotation.MessageBody[]

ann:messaging.annotation.MessageHeader[]

ann:messaging.annotation.MessageHeaders[]

ann:messaging.annotation.MessageListener[]

ann:messaging.annotation.MessageMapping[]

ann:messaging.annotation.MessageProducer[]

ann:messaging.annotation.SendTo[]

ann:retry.annotation.CircuitBreaker[]

ann:retry.annotation.Fallback[]

ann:retry.annotation.Recoverable[]

ann:retry.annotation.Retryable[]

ann:runtime.context.scope.Refreshable[]

ann:runtime.context.scope.ScopedProxy[]

ann:runtime.context.scope.ThreadLocal[]

ann:runtime.event.annotation.EventListener[]

ann:runtime.http.scope.RequestScope[]

ann:scheduling.annotation.Async[]

ann:scheduling.annotation.ExecuteOn[]

ann:scheduling.annotation.Scheduled[]

ann:session.annotation.SessionValue[]

@ContinueSpan

@NewSpan

@SpanTag

ann:validation.Validated[]

ann:websocket.annotation.ClientWebSocket[]

ann:websocket.annotation.OnClose[]

ann:websocket.annotation.OnError[]

ann:websocket.annotation.OnMessage[]

ann:websocket.annotation.OnOpen[]

ann:websocket.annotation.ServerWebSocket[]

ann:websocket.annotation.WebSocketComponent[]

ann:websocket.annotation.WebSocketMapping[]

When upgrading an application you may need to take action if you implement an interface or subclass a superclass and override a method.

For example the annotations defined in jakarta.validation are not inherited by default, so they must be defined again in any overridden or implemented methods.

This behaviour grants more flexibility if you need to redefine the validation rules. Note that it is still possible to inherit validation rules through meta-annotations. See the section on Annotation Inheritance for more information.

Error Response Format

The default value of jackson.always-serialize-errors-as-list is now true. That means by default the Hateoas JSON errors will always be a list. For example:

Example error response
{
  ...
  "_embedded": {
    "errors": [
      {
        "message": "Person.name: must not be blank"
      }
    ]
  }
}

To revert to the previous behavior where a singular error was populated in the message field instead of including _embedded.errors, set the configuration setting to false.

Runtime Classpath Scanning Removed

It is no longer possible to scan the classpath at runtime using the scan method of the api:context.env.Environment[] interface.

This functionality has not been needed for some time as scanning is implemented at build time through Bean Introspections.

Inject Annotations

Micronaut now provides the jakarta.inject annotations as a transitive dependency instead of the javax.inject annotations. To continue using the old annotations, add the following dependency.

dependency:javax.inject:javax.inject:1[]

Nullable Annotations

Micronaut no longer exports any third party dependency for nullability annotations. Micronaut now provides its own annotations for this purpose (api:core.annotation.Nullable[] and api:core.annotation.NonNull[]) that are used for our APIs. To continue using other nullability annotations, simply add the relevant dependency.

Internally, Micronaut makes use of a third party annotation that may manifest as a warning in your project:

warning: unknown enum constant When.MAYBE
  reason: class file for javax.annotation.meta.When not found

This warning is harmless and can be ignored. To eliminate this warning, add the following dependency to your project’s compile only classpath:

dependency:com.google.code.findbugs:jsr305[gradleScope="compileOnly"]

Server Filter Behavior

In Micronaut 2 server filters could have been called multiple times in the case of an exception being thrown, or sometimes not at all if the error resulted before route execution. This also allowed for filters to handle exceptions thrown from routes. Filters have changed in Micronaut 3 to always be called exactly once for each request, under all conditions. Exceptions are no longer propagated to filters and instead the resulting error response is passed through the reactive stream.

In the case of a response being created as a result of an exception, the original cause is now stored as a response attribute (api:http.HttpAttributes#EXCEPTION[]). That attribute can be read by filters to have context for the error HTTP response.

The api:http.filter.OncePerRequestHttpServerFilter[] class is now deprecated and will be removed in the next major release. The api:http.filter.OncePerRequestHttpServerFilter[] stores a request attribute when the filter is executed and some functionality may rely on that attribute existing. The class will still create the attribute but it is recommended to instead create a custom attribute in your filter class and use that instead of the one created by api:http.filter.OncePerRequestHttpServerFilter[].

There is also a minor behavior change in when the response gets written. Any modifications to the response after the underlying onNext call is made will not have any effect as the response has already been written.

HTTP Compile Time Validation

Compile time validation of HTTP related classes has been moved to its own module. To continue validating controllers, websocket server classes add http-validation to the annotation processor classpath.

dependency:io.micronaut:micronaut-http-validation[gradleScope="annotationProcessor"]

Decapitalization Strategy

For many cases, one common one being introspections, getter names like getXForwarded() would result in the bean property being XForwarded. The name will now be xForwarded. This can affect many areas of the framework where names like XForwarded are used.

@Order default

Previously the default order value for the @Order annotation was the lowest precedence. It is now 0.

Classes Renaming
  • RxJavaRouteDataCollector has been renamed to DefaultRouteDataCollector.

  • RxJavaBeanDefinitionDataCollector.html has been renamed to DefaultBeanDefinitionDataCollector.

  • RxJavaHealthAggregator has been renamed to DefaultHealthAggregator

Deprecation Removal

Classes, constructors, etc. that have been deprecated in previous versions of Micronaut have been removed.

Reflective Bean Map

In several places in Micronaut, it is required to get a map representation of your object. In previous versions, a reflection based strategy was used to retrieve that information if the class was not annotated with @Introspected. That functionality has been removed and it is now required to annotate classes with @Introspected that are being used in this way. Any class may be affected if it is passed as an argument or returned from any controller or client, among other use cases.

Previously the secure configuration for cookies was only respected if the request was determined to be sent over https. Due to a number of factors including proxies, HTTPS requests can be presented to the server as if they are HTTP. In those cases the setting was not having any effect. The setting is now respected regardless of the status of the request. If the setting is not set, cookies will be secure if the request is determined to be HTTPS.

Server Error Route Priority

Previously if a route could not be satisfied, or an HttpStatusException was thrown, routes for the relevant HTTP status was searched before routes that handled the specific exception. In Micronaut 3 routes that handle the exception will be searched first, then routes that handle the HTTP status.

Status Route Default Response Status

Status error routes will now default to produce responses with the same HTTP status as specified in the @Error annotation. In previous versions a 200 OK response was created. For example:

@Error(status = HttpStatus.UNSUPPORTED_MEDIA_TYPE)
String unsupportedMediaTypeHandler() {
    return "not supported";
}

The above method will result in a response of HTTP status 415 with a body of "not supported". Previously it would have been a response of HTTP status 200 with a body of "not supported". To specify the desired response status, either annotate the method with @Status or return an HttpResponse.

No Longer Possible to Inject a List of Provider

In Micronaut 2.x it was possible to inject a List<javax.inject.Provider>, although this was undocumented behaviour. In Micronaut 3.x injecting a list of Provider instances is no longer possible and you should instead use the api:context.BeanProvider[] API which provides stream() and iterator() methods to provide the same functionality.

Injecting ExecutorService

In previous versions of Micronaut it was possible to inject an ExecutorService without any qualifiers and the default Netty event loop group would be injected. Because the event loop should not be used for general purpose use cases, the injection will now fail by default with a non unique bean exception. The injection point should be qualified for which executor service is desired.

Subclasses Returned From Factories Not Injectable

It is no longer possible to inject the internal implementation type from beans produced via factories. The type returned from the factory or any of its super types are able to be injected.

For example:

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ExecutorService;
import javax.inject.Singleton;
public class ExecutorFactory {
@Singleton
public ExecutorService executorService() {
return ForkJoinPool.commonPool();
}
}

In the above case, if the ExecutorService had been already been retrieved from the context in previous logic, a call to context.getBean(ForkJoinPool.class) would locate the already created bean. This behaviour was inconsistent because if the bean had not yet been created then this lookup would not work. In Micronaut 3 for consistency this is no longer possible.

You can however restore the behaviour by changing the factory to return the implementation type:

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ExecutorService;
import javax.inject.Singleton;
public class ExecutorFactory {
@Singleton
public ForkJoinPool executorService() {
    return ForkJoinPool.commonPool();
}

}

No Longer Possible to Define AOP Advice on a Bean Produced from a Factory with Constructor arguments

In previous versions of Micronaut it was possible to define AOP advice to a factory method that returned a class that featured constructor arguments. This could lead to undefined behaviour since the argument of the generated proxy which would be dependency injected by the framework may be different from manually constructed proxy target.

The following definition is now invalid in Micronaut 3 and above and will lead to a compilation error:

import io.micronaut.context.annotation.*;
import io.micronaut.runtime.context.scope.*;
@Factory
class ExampleFactory {
@ThreadLocal
Test test() {
    return new Test("foo");
}

}

class Test { // illegally defines constructor arguments Test(String name) {} }

Implementations of javax.inject.Provider No Longer Generate Factories

In Micronaut 2.x if you defined a bean that implemented the javax.inject.Provider interface then the return type of the get method also automatically became a bean.

For example:

import javax.inject.Provider;
import javax.inject.Singleton;
@Singleton
public class AProvider implements Provider<A> {
@Override
public A get() {
return new AImpl();
}
}

In the above example a bean of type A would automatically be exposed by Micronaut. This behaviour is no longer supported and instead the ann:context.annotation.Factory[] annotation should be used to express the same behaviour. For example:

import io.micronaut.context.annotation.Factory;
import javax.inject.Provider;
import javax.inject.Singleton;
@Factory
public class AProvider implements Provider<A> {
@Override
@Singleton
public A get() {
return new AImpl();
}
}

Fewer Executable Methods Generated for Controllers and Message Listeners

Previous versions of Micronaut specified the ann:context.annotation.Executable[] annotation as a meta-annotation on the ann:http.annotation.Controller[], ann:http.annotation.Filter[] and ann:messaging.annotation.MessageListener[] annotations. This resulted in generating executable method all non-private methods of classes annotated with these annotations.

In Micronaut 3.x and above the ann:context.annotation.Executable[] has been moved to a meta-annotation of ann:http.annotation.HttpMethodMapping[] and ann:messaging.annotation.MessageMapping[] instead to reduce memory consumption and improve efficiency.

If you were relying on the presence of these executable methods you must explicitly annotate methods in your classes with ann:context.annotation.Executable[] to restore this behaviour.

GraalVM changes

In previous versions of Micronaut annotating a class with @Introspected automatically added it to the GraalVM reflect-config.json file. The original intended usage of the annotation is to generate Bean Introspection Metadata so Micronaut can instantiate the class and call getters and setters without using reflection.

Starting in Micronaut 3.x, the @Introspected annotation doesn’t add the class to the GraalVM reflect-config.json file anymore because, in most cases, it is not necessary. If you need to declare a class to be accessed by reflection, use the @ReflectiveAccess annotation instead.

Another change is regarding the GraalVM resources created at compile-time. In previous versions of Micronaut adding a dependency on io.micronaut:micronaut-graal triggered the generation of the GraalVM resource-config.json that included all the resources in src/main/resources so they were included in the native image. Starting in Micronaut 3.x that is done in either the Gradle or Maven plugins.

Exception Handler Moves

Two exception handlers that were in micronaut-server-netty have now been moved to micronaut-server since they were not specific to Netty. Their package has also changed as a result.

Table 3. Package changes
Old New

http-server-netty/src/main/java/io/micronaut/http/server/netty/converters/DuplicateRouteHandler.java

http-server/src/main/java/io/micronaut/http/server/exceptions/DuplicateRouteHandler.java

http-server-netty/src/main/java/io/micronaut/http/server/netty/converters/UnsatisfiedRouteHandler.java

http-server/src/main/java/io/micronaut/http/server/exceptions/UnsatisfiedRouteHandler.java

Module Changes

New package for Micronaut Cassandra

The classes in Micronaut Cassandra have been moved from io.micronaut.configuration.cassandra to io.micronaut.cassandra package.

Micronaut Security

Many of the APIs in the Micronaut Security module have undergone changes. Please see the Micronaut Security documentation for the details.

Groovy changes

In the previous version, a missing property wouldn’t set the field value to null as it would for the Java code. In version 3, it should behave in the same way.

Please refactor to use the default value in the @Value annotation:

@Nullable
@Value('${greeting}')
protected String before = "Default greeting"
@Nullable
@Value(‘${greeting:Default greeting}’)
protected String after