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:
-
With Micronaut
3.8.0, you can use@RequestBeanannotations with Records. Before3.8.0, you could use a POJO as a controller method parameter and annotate the parameter with@RequestBeanto bind any Bindable value (e.g.,HttpRequest,@PathVariable,@QueryValueor@Headerfields). -
If you enable CORS from any origin while running your app in localhost (e.g., test or development), since
3.8.0, theCorsFilterreturns 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
PropertySourceLoaderimplementations by callingApplicationContextBuilder::enableDefaultPropertySources(false)when starting your application. -
Better
java.timeconversion for YAML configuration -
Client SSL inner configuration is Bootstrap context compatible.
-
UriBuildermethodsqueryParamandreplaceQueryParamignore 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.
Micronaut Gradle Plugin v3.4.0 and Micronaut Maven Plugin v3.3.0 support 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
Micronaut Data 3.4.0 supports:
-
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
-
Micronaut Test 3.2.0 adds support for KoTest 5.
-
Micronaut AWS 3.5.0 adds a new module Micronaut AWS CDK. It also upgrades to the latest versions of the AWS SDKs.
-
Micronaut Micrometer 4.3.0 updates to Micrometer 1.9.0.
-
Micronaut GCP 4.2.0 updates to
grpc-auth1.45.1 andgrpc-netty-shaded. Moreover, we have clarified the documentation to support GraalVM Native Images when using the GCP libraries, and the Micronaut GCP Bom now includes thecom.google.cloud:native-image-supportdependency. -
Micronaut GRPC to 3.3.0 allows exposing a gRPC Health Check for a grpc-server.
-
Micronaut Serialization to 1.1.0. It allows the serialization and deserialization of object arrays.
-
Micronaut OpenAPI to 4.1.0 updates to Swagger 2.2.0.
-
Micronaut R2DBC to 3.0.0 updates to R2DBC
1.0.0.RELEASE.
Several modules publish a BOM (Bill of Materials) or use a Gradle Version Catalogs:
Schema Migration Modules
-
Micronaut Flyway 5.3.0 updates Flyway to 8.5.8.
-
Micronaut Liquibase 5.3.0 updates Liquibase to 4.9.1
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.
With 3.4.0, you can reference other beans properties in @Requires to load beans conditionally.
@Requires(bean=Config.class, beanProperty="foo", value="John")
Micronaut Data MongoDB
Micronaut Data 3.3.0 includes 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:
-
Micronaut GCP 4.1.0. It includes updates to the latest versions of Google Cloud dependencies.
-
Micronaut Reactor 2.2.1. It includes updates to the Project Reactor dependencies.
-
Micronaut Servlet 3.2.0. It includes updates to Tomcat and Undertow dependencies.
Other Module Upgrades
-
Micronaut AWS 3.2.0 updates to the latest version of AWS SDK, ASK SDK and AWS Serverless Java Container.
-
Micronaut Email 1.1.0 updates to the Sendgrid 4.8.3 and contains improvements for
javamailmodule users. -
Micronaut Test 3.1.0 updates the underlying testing dependencies.
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
-
The environmental endpoint is now disabled by default. To enable it, you must update your endpoint config:
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[]:
@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
-
The ProxyHttpClient now sends the Host header of the proxied service as per the RFC, instead of the originating service.
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
nativeImagetask is now replaced withnativeCompile -
native image configuration happens in the
graalvmNativeDSL extension instead of thenativeCompiletask -
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
createmethods 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.insecureTrustAllCertificatesproperty totrue, 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.xmlplease update the coordinates to:
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
...
</plugin>
-
WebSocketClient.createhas been modified to accept aURIparameter instead ofURL. The oldURLmethods still exist, but when called withnulllikeWebSocketClient.create(null), the method call is now ambiguous. Please insert a cast toURI:WebSocketClient.create((URI) null). The same applies for thecreatemethod that accepts an additionalHttpClientConfigurationparameter.
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.
micronautVersion={version}
If you use Maven, update the parent POM version and micronaut.version property in pom.xml, e.g.
<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"]
| 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:
| 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[] |
✅ |
✅ |
|
✅ |
|
✅ |
|
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:
{
...
"_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
-
RxJavaRouteDataCollectorhas been renamed toDefaultRouteDataCollector. -
RxJavaBeanDefinitionDataCollector.htmlhas been renamed toDefaultBeanDefinitionDataCollector. -
RxJavaHealthAggregatorhas been renamed toDefaultHealthAggregator
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.
Cookie Secure Configuration
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.
| 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