1.1 What’s New?

Micronaut 3.0.0 includes the following changes:

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 @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

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.

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:

  1. @Inject
  2. public Vehicle(Engine<V8> engine) {
  3. this.engine = engine;
  4. }
  1. @Inject
  2. Vehicle(Engine<V8> engine) {
  3. this.engine = engine
  4. }
  1. @Singleton
  2. class Vehicle(val engine: Engine<V8>) {

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 @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 @Bean annotation:

  1. @Singleton
  2. @Bean(typed = Engine.class) (1)
  3. public class V8Engine implements Engine { (2)
  4. @Override
  5. public String start() {
  6. return "Starting V8";
  7. }
  8. @Override
  9. public int getCylinders() {
  10. return 8;
  11. }
  12. }
  1. @Singleton
  2. @Bean(typed = Engine) (1)
  3. class V8Engine implements Engine { (2)
  4. @Override
  5. String start() { "Starting V8" }
  6. @Override
  7. int getCylinders() { 8 }
  8. }
  1. @Singleton
  2. @Bean(typed = [Engine::class]) (1)
  3. class V8Engine : Engine { (2)
  4. override fun start(): String {
  5. return "Starting V8"
  6. }
  7. override val cylinders: Int = 8
  8. }

For more information see the section on Limiting Injectable Types.

Factories can produce bean from fields

Beans defined with the @Factory annotation can now produce beans from public or package protected fields, for example:

  1. @MicronautTest
  2. public class VehicleMockSpec {
  3. @Requires(beans=VehicleMockSpec.class)
  4. @Bean @Replaces(Engine.class)
  5. Engine mockEngine = () -> "Mock Started"; (1)
  6. @Inject Vehicle vehicle; (2)
  7. @Test
  8. void testStartEngine() {
  9. final String result = vehicle.start();
  10. assertEquals("Mock Started", result); (3)
  11. }
  12. }
  1. @MicronautTest
  2. class VehicleMockSpec extends Specification {
  3. @Requires(beans=VehicleMockSpec.class)
  4. @Bean @Replaces(Engine.class)
  5. Engine mockEngine = {-> "Mock Started" } as Engine (1)
  6. @Inject Vehicle vehicle (2)
  7. void "test start engine"() {
  8. given:
  9. final String result = vehicle.start()
  10. expect:
  11. result == "Mock Started" (3)
  12. }
  13. }
  1. @MicronautTest
  2. class VehicleMockSpec {
  3. @get:Bean
  4. @get:Replaces(Engine::class)
  5. val mockEngine: Engine = object : Engine { (1)
  6. override fun start(): String {
  7. return "Mock Started"
  8. }
  9. }
  10. @Inject
  11. lateinit var vehicle : Vehicle (2)
  12. @Test
  13. fun testStartEngine() {
  14. val result = vehicle.start()
  15. Assertions.assertEquals("Mock Started", result) (3)
  16. }
  17. }

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

Enhanced BeanProvider Interface

The 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 @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.

Using BeanProvider with Any

  1. import io.micronaut.context.BeanProvider;
  2. import io.micronaut.context.annotation.Any;
  3. import jakarta.inject.Singleton;
  4. @Singleton
  5. public class Vehicle {
  6. final BeanProvider<Engine> engineProvider;
  7. public Vehicle(@Any BeanProvider<Engine> engineProvider) { (1)
  8. this.engineProvider = engineProvider;
  9. }
  10. void start() {
  11. engineProvider.ifPresent(Engine::start); (2)
  12. }
  13. }

Using BeanProvider with Any

  1. import io.micronaut.context.BeanProvider
  2. import io.micronaut.context.annotation.Any
  3. import jakarta.inject.Singleton
  4. @Singleton
  5. class Vehicle {
  6. final BeanProvider<Engine> engineProvider
  7. Vehicle(@Any BeanProvider<Engine> engineProvider) { (1)
  8. this.engineProvider = engineProvider
  9. }
  10. void start() {
  11. engineProvider.ifPresent(Engine::start) (2)
  12. }
  13. }

Using BeanProvider with Any

  1. import io.micronaut.context.BeanProvider
  2. import io.micronaut.context.annotation.Any
  3. import jakarta.inject.Singleton
  4. @Singleton
  5. class Vehicle(@param:Any val engineProvider: BeanProvider<Engine>) { (1)
  6. fun start() {
  7. engineProvider.ifPresent { it.start() } (2)
  8. }
  9. fun startAll() {
  10. if (engineProvider.isPresent) { (1)
  11. engineProvider.forEach { it.start() } (2)
  12. }
  13. }

The annotation can also be used on @Factory methods to allow customization of how objects are injected via the InjectionPoint API.

Support for Fields in Bean Introspections

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

  1. import io.micronaut.core.annotation.Introspected;
  2. @Introspected(accessKind = Introspected.AccessKind.FIELD)
  3. public class User {
  4. public final String name; (1)
  5. public int age = 18; (2)
  6. public User(String name) {
  7. this.name = name;
  8. }
  9. }
  1. import io.micronaut.core.annotation.Introspected
  2. @Introspected(accessKind = Introspected.AccessKind.FIELD)
  3. class User {
  4. public final String name (1)
  5. public int age = 18 (2)
  6. User(String name) {
  7. this.name = name
  8. }
  9. }

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 ConstructorInterceptor interface and @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 MethodInterceptor interface and @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.0.0

Huge Micronaut Data update including many new features including:

  • Full support for immutable entities. You can use Java 16 records or Kotlin immutable data classes

  • Integrated support for R2DBC, now the data-r2dbc module is a part of the data project and shares the same code with JDBC

  • Optimistic locking for JDBC/R2DBC

  • Repositories now support batch insert/update/delete even with a custom query

  • Rewritten entity mapper allows more complex mapping for JDBC/R2DBC entities

  • Support for @JoinTable and @JoinColumn annotations

  • A lot of bugfixes!

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