- 19.4 Breaking Changes
- Micronaut 2.2
- Thread Pool Selection Now Manual
- Micronaut Cache Removed from Core
- Support for RxJava 1.x Removed from Core
- Support for Reactor Removed from Core
- Loggers Endpoint Modifications Now Sensitive
- Server Side Content Negotiation May Require Test Changes
- Server Filter Ordering
- Heartbeat Events No Longer Published if no Discovery Clients present
- Several TypeConverters Are No Longer Beans
- @Executable No Longer Stereotype of @Around
- Spot Bugs Instead of JSR-305 Nullable/NonNull Annotations
- Events Renamed
- New Package for Netty Specific Classes of HTTP Client
- HTTP Clients No Longer Named Beans
- Source Retention Annotations No Longer Retained in Runtime Metadata
- Iterable Beans No Longer Have An Implicit Primary
- No Longer Possible to Return Null to Disable a Bean
- Invalid Configuration File Locations
- PropertySourceLoader Changes
- Deprecation Removal
- Map Property Binding
- GraalVM BOM Entry
@Retryable
and@CircuitBreaker
Exception Handling- MessageSource API Changes
- Environment Order Bugfix
- Introspections and Inner Classes
- Executable Methods
- Super interfaces No Longer Searched for Fallbacks
- AWS FunctionClient Moved to AWS Module
- LogLevel Enum Moved to io.micronaut.logging
19.4 Breaking Changes
This section will document breaking changes between Micronaut 1.0 and Micronaut 2.0
Micronaut 2.2
Kotlin suspend functions in controllers that return null will now correctly respond with a 404. This behavior was inconsistent with other return types in previous versions and returned a 200 OK response.
Thread Pool Selection Now Manual
In Micronaut 1.x, Micronaut would attempt to automatically deduce the thread pool to use based on the return type of the controller method.
This approach caused some confusion and created a false association between reactive types and blocking operations.
Micronaut 2.x now leaves it up to the user to specify the thread pool to schedule operations on, including blocking operations.
If you are upgrading from Micronaut 1.x and have a controller that executes blocking I/O operations (such as JDBC or JPA) it is recommended that you add the @ExecuteOn annotation to execute the blocking operations on a different thread.
Using @ExecuteOn
import io.micronaut.http.annotation.*;
import io.micronaut.scheduling.TaskExecutors;
import io.micronaut.scheduling.annotation.ExecuteOn;
@Controller("/executeOn/people")
public class PersonController {
private final PersonService personService;
PersonController(
PersonService personService) {
this.personService = personService;
}
@Get("/{name}")
@ExecuteOn(TaskExecutors.IO) (1)
Person byName(String name) {
return personService.findByName(name);
}
}
Using @ExecuteOn
import io.micronaut.http.annotation.*
import io.micronaut.scheduling.TaskExecutors
import io.micronaut.scheduling.annotation.ExecuteOn
@Controller("/executeOn/people")
class PersonController {
private final PersonService personService
PersonController(
PersonService personService) {
this.personService = personService
}
@Get("/{name}")
@ExecuteOn(TaskExecutors.IO) (1)
Person byName(String name) {
return personService.findByName(name)
}
}
Using @ExecuteOn
import io.micronaut.http.annotation.*
import io.micronaut.scheduling.TaskExecutors
import io.micronaut.scheduling.annotation.ExecuteOn
@Controller("/executeOn/people")
class PersonController (private val personService: PersonService) {
@Get("/{name}")
@ExecuteOn(TaskExecutors.IO) (1)
fun byName(name: String): Person {
return personService.findByName(name)
}
}
1 | The @ExecuteOn annotation is used to execute the operation on the I/O thread pool |
If you wish to return to the previous behaviour as defined in Micronaut 1.x you can set micronaut.server.thread-selection to AUTO in configuration. |
Micronaut Cache Removed from Core
The micronaut-runtime
module in Micronaut 1.x included support for caching AOP with the @Cache
annotation. The core caching library and a default implementation based on caffeine were included.
If you are using the caffeine backed cache support, you must add a dependency to continue doing so. Add io.micronaut.cache:micronaut-cache-caffeine
to your build to maintain the existing functionality. The new caffeine cache module no longer uses the internal shadowed caffeine version and declares its own normal dependency on caffeine. You may need to exclude the transitive dependency in order to prevent conflicts with other versions that may be being pulled in.
The management endpoint for caches is no longer included by default in the micronaut-management
module. If you would like to use the caches endpoint, add a dependency on io.micronaut.cache:micronaut-cache-management
.
Support for RxJava 1.x Removed from Core
RxJava 1.x support is no longer included in core by default. You can re-enable support by adding the following dependency:
implementation("io.micronaut.rxjava1:micronaut-rxjava1")
<dependency>
<groupId>io.micronaut.rxjava1</groupId>
<artifactId>micronaut-rxjava1</artifactId>
</dependency>
Support for Reactor Removed from Core
Reactor support is no longer included in core by default. You can re-enable support by adding the following dependency:
implementation("io.micronaut.reactor:micronaut-reactor")
<dependency>
<groupId>io.micronaut.reactor</groupId>
<artifactId>micronaut-reactor</artifactId>
</dependency>
Loggers Endpoint Modifications Now Sensitive
The method on the loggers endpoint to modify logging is now sensitive by default. To revert to the previous behavior, apply the following configuration:
endpoints:
loggers:
write-sensitive: false
Server Side Content Negotiation May Require Test Changes
The new support for server side content negotiation may require changes to tests. For example a test that that makes a call such as:
String result = client.toBlocking().retrieve(
HttpRequest.GET('/test')
.accept("text/plain"), String
)
If the server implementation does not declare the route as @Produces("text/plain")
the request will be rejected with a NOT_ACCEPTABLE
HTTP status code.
Server Filter Ordering
In Micronaut 1.x almost all built in filters operated on order 0, meaning the order was non deterministic. That caused some compatibility issues with the metrics and security modules. A new class has been added ServerFilterPhase that defines the phases of server filtering and sets an order. Many filters have been updated to now have their order reflect the phase they participate in.
Heartbeat Events No Longer Published if no Discovery Clients present
A HeartbeatEvent is no longer published automatically if there are no DiscoveryClient instances present.
This behaviour can be changed by setting micronaut.heartbeat.enabled
to true
explicitly in configuration.
Several TypeConverters Are No Longer Beans
Many TypeConverter
instances that were previously beans are no longer beans and are deprecated including:
These should not be injected directly but instead used through the ConversionService API.
@Executable No Longer Stereotype of @Around
In Micronaut 1.x the @Executable annotation was a meta-annotation specified on the @Around and @Introduction annotations. This meant that an ExecutableMethod reference was generated for every usage of AOP advice which consumed additional memory unnecessarily.
In Micronaut 2.x and above this is no longer the case and if you need an ExecutableMethod generated you should add the @Executable annotation to any custom AOP advice you specify otherwise the method will not be available via the BeanDefinition interface (using for example the getExecutableMethods method).
Spot Bugs Instead of JSR-305 Nullable/NonNull Annotations
The JSR-305 annotations library (com.google.code.findbugs:jsr305
) is no longer a dependency (replaced by spotbugs-annotations
). If you need this library you will need to add it manually.
Events Renamed
The following events were renamed to avoid confusion with other events of similar names:
Old Name | New Name |
---|---|
| |
|
New Package for Netty Specific Classes of HTTP Client
The HTTP client implementation classes including DefaultHttpClient (considered internal in Micronaut 1.x) have been moved to a sub-package called io.micronaut.http.client.netty
.
HTTP Clients No Longer Named Beans
HTTP clients declared with micronaut.http.services
(see Manual Service Discovery Configuration) are no longer named beans in the context and cannot be injected with javax.inject.Named
, for example given the configuration:
Manually configuring services
micronaut:
http:
services:
foo:
urls:
- http://foo1
- http://foo2
You can no longer inject an HTTP client with @Named("foo")
:
@Inject
@Named("foo")
RxHttpClient httpClient;
Instead you should always use @Client:
@Inject
@Client("foo")
RxHttpClient httpClient;
Source Retention Annotations No Longer Retained in Runtime Metadata
In Micronaut 1.x annotations specified as source retention were still retained in the AnnotationMetadata interface. As of Micronaut 2.x this is no longer the case with source retention annotations only available within the compiler APIs.
If you wish to retain a particular source level annotation when upgrading you can write an AnnotationTransformer that alters the RetentionPolicy
of the annotation.
Iterable Beans No Longer Have An Implicit Primary
In Micronaut 1.x injecting a single instance of an iterable bean without qualifiers would inject the first bean. An iterable bean is typically anything annotated with @EachProperty
or @EachBean
. Those beans typically are referenced from configuration. The first bean in this context is the first item in configuration that matches what the annotation expects.
For example if you created a bean with @EachProperty("cars")
, then specified the following in your config:
cars:
ford:
cylinders: 8
subaru:
cylinders: 4
Requesting a single instance of that bean would result in the “ford” instance being injected. Because that behavior is surprising and inconsistent with other types of beans, that is no longer the case and a NonUniqueBeanException
will be thrown.
This change does not apply to an explicit primary defined in the annotation (@EachProperty(value = “cars”, primary = “ford”) ), nor requesting the instance by a qualifier (@Named(“ford”) CarConfig carConfig ). |
No Longer Possible to Return Null to Disable a Bean
It is no longer possible to return null
from a @Factory bean method to disable the bean. You should now throw DisabledBeanException instead.
Invalid Configuration File Locations
Specifying a file with micronaut.config.files
, either through the system property or environment variable, that does not exist or cannot be read will now result in the application failing to startup. In previous versions of Micronaut a warning would be logged and the file would be ignored.
PropertySourceLoader Changes
Some default interface methods are no longer default and require implementation.
Deprecation Removal
Most if not all deprecated classes and methods have been removed.
Map Property Binding
In Micronaut 1.x java.util.Map
properties being bound from config were inconsistently bound as either a nested or flat. Now maps are bound as nested by default and the @MapFormat annotation’s default value for transformation
has been changed to reflect that.
For example given the config:
persons:
joe:
age: 30
sally:
age: 25
A map property injected via @Property(name ="persons")
may have been injected flat or nested depending on a couple factors.
Flat
{"joe.age": 30, "sally.age": 25}
Nested
{"joe": {"age": 30}, "sally": {"age": 25}}
To bind to a map with flat keys, add the @MapFormat annotation and set the transformation
member.
GraalVM BOM Entry
The no longer used group for Graal is no longer part of the bom. While upgrading if you depend on Graal you may see Could not find com.oracle.substratevm:svm:.
. To resolve the issue, change the dependency group to org.graalvm.nativeimage
.
@Retryable
and @CircuitBreaker
Exception Handling
@Retryable
and @CircuitBreaker
in previous versions of Micronaut resolved includes
and excludes
explicitly. Any exception thrown had to exactly match one of the exceptions specified. This has been changed to now also include subclasses of the exception types specified.
MessageSource API Changes
The semantics of the getMessage
method have been changed to also interpolate the message with any provided variables. In previous versions of Micronaut, the raw message was returned from the bundle. To support reading the raw message, a new method getRawMessage
has been added.
In addition, escaping of messages with single quotes is now implemented in accordance with the standard Java MessageFormat class. Messages that contain a single quote will now need escaping in order for the quote to output as it did previously. For example:
my.message=We love Micronaut's documentation
Would now be output as We love Micronauts documentation
. To achieve the desired result, escape the single quote with another single quote.
my.message=We love Micronaut''s documentation
This change also applies to messages in custom constraint annotations, which interpolate the message via the message source api. |
Environment Order Bugfix
Environments specified through the application context builder have priority over environments deduced or supplied through the MICRONAUT_ENVIRONMENTS environment variable, or the equivalent system property. A bug in the logic however did not change the order of a specified environment if it previously was found or deduced. This issue manifested itself with @MicronautTest(environments = "test")
. The test
environment is already deduced for tests, so it retained the order of other deduced environments, and was able to be overridden by MICRONAUT_ENVIRONMENTS=dev
. In Micronaut 1.x configuration for dev
would have overridden test
. In Micronaut 2.x test
will override dev
.
Introspections and Inner Classes
A bug in Micronaut 1.x caused bean introspections to be generated for inner classes of classes annotated with @Introspected
. That also applies to classes where @Introspection
is a meta annotation, like @Entity
. This may have an impact for GraalVM users that rely on accesses to those classes without using reflection. For example:
@Entity
public class Pet {
...
private PetType type = PetType.DOG;
// getters & setters
public enum PetType {
DOG,
CAT
}
}
Previously a bean introspection would have been generated for PetType
. That is no longer the case. If the type should be introspected, simply add the annotation.
Executable Methods
A bug in Micronaut 1.x caused bean definitions to be created for classes that only declared executable annotations on one or more methods. Classes with executable methods must now be explicitly declared as a bean with a scope annotation in order for a bean definition to be created.
Super interfaces No Longer Searched for Fallbacks
If the @Fallback annotation is used to specify a fallback for a @Client interface, the super interfaces of the client will no longer be traversed to lookup the fallback to invoke.
In this case it may be necessary to specify the api
member of the @Recoverable annotation to ensure the fallback can be looked up. For example:
Specifying the api
to recover from
@Client("/Books")
@Recoverable(api = BookApi)
interface BookClient extends BookApi {
@Override
Book get(Long id);
}
AWS FunctionClient Moved to AWS Module
The AWS based function client has been made part of the Micronaut AWS project. If you need this functionality add the following dependency:
implementation("io.micronaut.aws:micronaut-function-client-aws")
<dependency>
<groupId>io.micronaut.aws</groupId>
<artifactId>micronaut-function-client-aws</artifactId>
</dependency>
LogLevel Enum Moved to io.micronaut.logging
io.micronaut.management.endpoint.loggers.LogLevel
enum has moved to package io.micronaut.logging