Migration

Migrate from Vert.x 4 to 5

This guide describes the updates in Eclipse Vert.x 5 release. Use the information to upgrade your Vert.x 4.x applications to Vert.x 5. It provides information about the new, deprecated and unsupported features in this release.

Depending on the modules used in your application, you can read the relevant section to know more about the changes in Vert.x 5.

About Vert.x

Vert.x is a toolkit used for creating reactive, non-blocking, and asynchronous applications that run on Java Virtual Machine. (JVM). It contains several components that help you create reactive applications. It is designed to be cloud-native.

Since Vert.x supports asynchronous applications it can be used to create applications with high volume of messages, large event processing, HTTP interactions, and so on.

What’s changed in Vert.x 5

This section explains the fundamental differences between Vert.x 5 and 4.x releases.

Handling deprecations and removals

Some features and functions have been deprecated or removed in Vert.x 5. Before you migrate your applications to Vert.x 5, check for deprecations and removals.

  • Some APIs were deprecated in an Vert.x 4.x release and new equivalent APIs were provided in that release.

  • The deprecated APIs have been removed in Vert.x 5.

If your application uses a deprecated API, you should update your application to use the new API. This helps in migrating applications to the latest version of the product.

The Java compiler generates warnings when deprecated APIs are used. You can use the compiler to check for deprecated methods while migrating applications to Vert.x 5.

Components sunsets and removals

A few components are sunsetting in 5, that means they are still supported for the lifetime of the 5.x series, but we don’t encourage using them anymore since we provide replacements for them. Such components are scheduled to go away in the next major release (Vert.x 6).

Here is the list of components sunsetting in 5:

Component Replacement

gRPC Netty

Vert.x gRPC client and server

JDBC API

SQL client API implementation for JDBC

Service Discovery

Vert.x Service Resolver

RxJava 2

Mutiny or RxJava 3

OpenTracing

OpenTelemetry

Vert.x Unit

Vert.x JUnit 5

Here is the list of components removed in 5, that were sunset in the 4.x series.

Component Replacement

Vert.x Sync

Vert.x virtual threads

Service Factories

None

Maven Service Factory

None

HTTP Service Factory

None

Vert.x Web OpenAPI

Vert.x Web OpenAPI Router

Embracing the future model

Vert.x 4 extended the 3.x callback asynchronous model to a future/callback hybrid model, to facilitate migration from Vert.x 3.

Every callback method has a matching future method:

public interface HttpClient {

   // Future version
   Future<HttpClientRequest> request(RequestOptions request);

   // Callback version
   void request(RequestOptions request, Handler<AsyncResult<HttpClientRequest>> callback);
   ...
}

Vert.x 5 only retains the future model and thus the callback model is gone, instead you get:

public interface HttpClient {

   // Future version
   Future<HttpClientRequest> request(RequestOptions request);
   ...
}

Callback methods Vert.x 4.x are not deprecated methods, however after the release of Vert.x 5, the callback methods shall be deprecated in order to facilitate the migration to Vert.x 5.

Vert.x builders

Vert.x 5 has introduced the usage of the builder pattern that facilitate component configuration with instances of objects.

Until 5, such customisation was usually supported by options.

Customizing a Vertx instance in Vert.x 4.x
Future<Vertx> future = Vertx.clusteredVertx(options.setClusterManager(clusterManager));

The builder pattern provide a clean and simple alternative to separate configuration and customization.

Customizing a Vertx instance in Vert.x 5
Future<Vertx> f = Vertx
  .builder()
  .with(options)
  .withClusterManager(clusterManager)
  .buildClustered();

This pattern has been adopted whenever possible in Vert.x 5 and will be detailed on a per component basis.

Vert.x command-line tool removal

The vertx command-line tool has been removed in Vert.x 5.

We want to focus on the use case of the typical Vert.x application: compiled and optionally packaged as an executable uber-jar.

You can do this with Maven and the Vert.x Maven Plugin. The plugin can create a new Maven project in your repository or update an existing one.

In addition to packaging the application as an executable uber-jar, it can also start your application in development mode (redeploying the main verticle when file changes are detected).

If you’re a Gradle user, the Vert.x Gradle Plugin provides similar features.

CLI framework deprecation

The CLI framework is deprecated in Vert.x 5. This includes the io.vertx.core.Launcher class, which is based on it.

If your application is a command-line tool or needs one, checkout alternatives like Picocli. In fact, in various aspects, Picocli is more flexible and more powerful than the Vert.x CLI framework.

Vert.x Legacy CLI

If, while evaluating alternatives, you need to preserve the CLI framework functionality, you may do so by adding this dependency to your project (Maven):

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-launcher-legacy-cli</artifactId>
  <version>5.0.0</version>
</dependency>

This new project contains the legacy CLI framework, including the io.vertx.core.Launcher class.

Beware it is not guaranteed that backward compatibility can be maintained for the whole Vert.x 5 lifetime.

Vert.x Application Launcher

In Vert.x 5, a new module, the Vert.x Application Launcher replaces the Vert.x 4.x io.vertx.core.Launcher class.

First, you must add it to your project’s dependencies (Maven):

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-launcher-application</artifactId>
  <version>5.0.0</version>
</dependency>

To start your application, use io.vertx.launcher.application.VertxApplication as the main class.

# Assuming the command is executed on a Unix-like system which has the classpath configured in the CLASSPATH environment variable.
java -cp $CLASSPATH io.vertx.launcher.application.VertxApplication my.app.MainVerticle

If your application is packaged as an executable JAR, having the Main-Class attribute set to io.vertx.launcher.application.VertxApplication in the META-INF/MANIFEST.MF file, the command can be simplified.

java -jar myapp.jar my.app.MainVerticle

Vert.x Core

Vert.x instance customization

An instance of Vertx can be customized with a few moving parts:

  • cluster manager

  • metrics factory

  • tracing factory

In Vert.x 5 customization is achieved by the VertxBuilder.

Customizing with a cluster manager
// 4.x
Future<Vertx> f = Vertx.clusteredVertx(
  new VertxOptions().setClusterManager(clusterManager)
);

// 5.0
Future<Vertx> f = Vertx
  .builder()
  .withClusterManager(clusterManager)
  .buildClustered();

Likewise, metrics and tracing factories are configured similarly

Customizing with tracing/metrics factories
// 4.x
Vertx vertx = Vertx.vertx(
  new VertxOptions()
    .setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory))
    .setTracingOptions(new TracingOptions().setFactory(factory))
);

// 5.0
Vertx vertx = Vertx
   .builder()
  .withMetrics(factory)
  .withTracer(factory)
  .build();

The tracing implementations of Vert.x have been updated accordingly to support customizing with a tracer implementation for this purpose:

Customizing an instance with an OpenTelemetry instance
// 4.x
Vertx vertx = Vertx.vertx(new VertxOptions()
    .setTracingOptions(
      new OpenTelemetryOptions(openTelemetry)
    )
  );

// 5.0
Vertx vertx = Vertx.builder()
 .withTracer(new OpenTelemetryTracingFactory(openTelemetry))
 .build();

The metrics implementations of Vert.x have been updated accordingly to support customizing with a metrics implementation for this purpose:

Customizing an instance with a Dropwizard metrics registry
// 4.x
Vertx vertx = Vertx.vertx(new VertxOptions()
 .setMetricsOptions(new DropwizardMetricsOptions()
   .setMetricsRegistry(myRegistry)
   .setEnabled(true)));

// 5.0
Vertx vertx = Vertx.builder()
  .with(new VertxOptions()
    .setMetricsOptions(new DropwizardMetricsOptions()
    .setEnabled(true)))
  .withMetrics(new DropwizardMetricsFactory(myRegistry))
  .build();

HTTP/2 connection shutdown handler

The HTTP/2 connection shutdown handler notifies the handler when the connection shutdown begins, previously the handler was notified when after all the connection streams have been closed. The previous behavior can be obtained with the connection close handler.

This allows to be aware of a connection shutdown and take appropriate measures to stop the inflight streams being processed. It also aligns with the behaviour of other shutdown handlers.

Removal of HTTP connection shutdown variant without a timeunit

The HttpConnection#shutdown(long) variant is removed in favor of HttpConnection#shutdown(long, TimeUnit).

// 4.x
connection.shutdown(5 * 1000); // 5 seconds

// 5.0
connection.shutdown(5, TimeUnit.SECONDS); // 5 seconds

Removal of HTTP server response push with a string authority

HttpServerResponse#push methods with a string authority have been removed in favour of the same method with an HostAndPort type instead.

// 4.x
response.push(httpMethod, authorityAsString path);

// 5.0
response.push(httpMethod, HostAndPort.parse(authorityAsString) path);

The deprecated HttpServerRequest#cookieMap method has been removed, instead the HttpServerRequest#cookies method should be used.

// 4.x
Map<String, Cookie> cookieMap = request.cookieMap();

// 5.0
Set<Cookie> cookies = request.cookies();

Use of uniform byte distributor for HTTP/2 streams

The default stream byte distributor use stream priorities to determine the amount of bytes to be sent for each stream, this change allows to use a strategy that does not use stream priorities and yields better performance since it consumes less CPU.

The default implementation is now UniformStreamByteDistributor instead of WeightedFairQueueByteDistributor.

Rename HttpClientRequest setTimeout to setIdleTimeout

The request timeout is actually an idle timeout, it has been renamed to avoid confusion.

// 4.x
request.setTimeout(timeout);

// 5.0
request.setIdleTimeout(timeout);

Removal of HttpClient WebSocket methods

HttpClient WebSocket methods are moved to a new WebSocketClient API.

// 4.x
HttpClient httpClient = vertx.createHttpClient();
Future<WebSocket> f = httpClient.webSocket(connectOptions);

// 5.0
WebSocketClient wsClient = vertx.createWebSocketClient();
Future<WebSocket> f = wsClient.connect(connectOptions);

HTTP client customization

HttpClient customization methods have been moved to a new HttpClientBuilder:

  • redirectHandler

  • connectionHandler

// 4.x
HttpClient client = vertx.createHttpClient();
client.connectionHandler(conn -> ...);
client.redirectHandler(request -> ...);

// 5.0
HttpClient client = vertx.httpClientBuilder()
  .withConnectHandler(conn -> ...)
  .withRedirectHandler(request -> ...)
  .build();

HttpClient API cleanup

In Vert.x 4.x, HttpClient API exposes two distincts API:

  • HTTP interactions, like request method.

  • HTTP client operations, like updateSSLOptions

Since Vert.x 5, HttpClient only retains HTTP interactions, a new HttpClientAgent API extends HttpClient and exposes these methods:

// 4.x
HttpClient client = vertx.createHttpClient();
client.updateSSLOptions(sslOptions);

// 5.0
HttpClientAgent client = vertx.createHttpClient();
client.updateSSLOptions(sslOptions);

HttpClient pool configuration

In Vert.x 4.x, HttpClientOptions configures the HTTP/1.x and HTTP/2 pool.

Since Vert.x 5, this configuration is done through PoolOptions.

// 4.x
HttpClient client = vertx.createHttpClient(new HttpClientOptions()
  .setMaxPoolSize(http1MaxPoolSize)
  .setHttp2MaxPoolSize(http2MaxPoolSize)
);

// 5.0
HttpClient client = vertx.createHttpClient(new PoolOptions()
  .setHttp1MaxSize(http1MaxPoolSize)
  .setHttp2MaxSize(http2MaxPoolSize)
);

Removal of HttpServerResponse close method

The HttpServerResponse close method closes the HTTP connection, it can be misleading as there are better API to interact with the current request/connection lifecycle which are HttpServerResponse#reset and HttpConnection#close.

When the actual HTTP connection must be closed:

// 4.x
response.close();

// 5.0
request.connection().close();

When the current request/response must be disposed:

// 4.x
response.close();

// 5.0
response.reset();

HTTP stream async methods returns now a future instead of being fluent

A few methods have seen their fluent return type to be changed to a future type instead in order to signal the completion result:

  • writeCustomFrame

  • writeContinue

  • reset

// 4.x
response.writeCustomFrame(12, 134, expectedRecv).end();

// 5.0
response.writeCustomFrame(12, 134, expectedRecv);
response.end();

New authority property replacing host/port

HttpClientRequest and HttpServerRequest expose the request authority using a host/port combination for the client request and a single host header for the server. In addition, this terminology is also confusing with the actual server host and port.

Those are replaced by a new authority property:

Client request
// 4.x
request.setHost(host).setPort(port);

// 5.0
request.authority(HostAndPort.create(host, port));
Server request
// 4.x
String host = request.host(); // host:port string

// 5.0
HostAndPort authority = request.authority();

HttpServer request and WebSocket streams removal

HttpServer#requestStream() and HttpServer#timeoutStream() have been removed. These streams were designed for Rx like languages and the actually don’t provide any benefits.

// 4.x
server.requestStream().handler(request -> ...);

// 5.0
server.requestHandler(request -> ...).listen();

Removal of server WebSocket handshake methods

The server WebSocket API can control handshake implicitly (e.g. sending a message) or explicitly (accept or any WebSocket interaction). This result in a more complex implementation than it should be for such API.

Accepting a handshake
// 4.x
server.webSocketHandler(ws -> {
  ws.accept();
  ws.write();
};

// 5.0
server.webSocketHandshakeHandler(handshake -> {
  handshake.accept();
});
server.webSocketHandler(ws -> {
  ws.write();
};
Rejecting a handshake
// 4.x
server.webSocketHandler(ws -> {
  ws.reject();
};

// 5.0
server.webSocketHandshakeHandler(handshake -> {
  handshake.reject();
});

Future

CompositeFuture raw Future type removal

CompositeFuture methods declare raw Future types, e.g. all(Future,Future) or all(List<Future>>), such declarations force the user to cast when using a List<Future<Something>>. These methods have been made fully generic, using the wildcard type.

List<Future<User>> users = ...

// 4.x
CompositeFuture cf = CompositeFuture.all((List<Future>)users);

// 5.0
CompositeFuture cf = Future.all(users);

Removal of Future eventually method that takes a function as argument

Future#eventually method takes as parameter a Function<Void, Future<T>>, this was developed for codegen which does not support Supplier. The Future object is not code generated anymore since Vert.x 4.x, we can therefore use Supplier which is more suitable.

// 4.x
future.eventually(v -> someFuture());

// 5.0
future.eventually(() -> someFuture());

Logging

Vert.x Logging API usage has been reduced in Vert.x 4 to be used by Vert.x components, in other words the API has become internal to Vert.x:

io.vertx.core.logging.Logger and io.vertx.core.logging.LoggerFactory have been deprecated to discourage usage of this API. Instead, a logging API should be used such as Log4j 2 or SLF4J.

Of course, configuration of the Vert.x logging back-end remains fully supported as usual, like the vertx.logger-delegate-factory-class-name system property.

System properties

A few system properties have been removed in Vert.x 5.

Name Comment

vertx.json.base64

Vert.x 3.x Json supports RFC-7493, however the JSON encoder/decoder format was incorrect. Users who needed to interop with Vert.x 3.x applications should have set the system property vertx.json.base64 to legacy.

vertx.cluster.managerClass

Not used, neither documented nor tested.

vertx.javaCompilerOptions

Not used, neither documented nor tested.

vertx.flashPolicyHandler

Vert.x HTTP/1.1 server contains a hidden option to detect Adobe Flash clients and return a policy file response. This option is activated by a system property vertx.flashPolicyHandler only referenced in source code (private field) and not tested.

vertx.cwd

This system property was not documented and only used in the vertx-examples repository.

vertx.disableTCCL

Instead, VertxOptions#setDisableTCCL(boolean) should be used.

Worker verticles

Removal of deployment worker property

DeploymentOptions#setWorker and DeploymentOptions#getWorker methods are removed since the introduction of the new ThreadingModel.

// 4.x
Future<String> f = vertx.deployVerticle(new DeploymentOptions().setWorker(true, ...)

// 5.0
Future<String> f = vertx.deployVerticle(new DeploymentOptions().setThreadingModel(ThreadingModel.WORKER, ...)

Worker event-loop assignment

Since Vert.x 5 worker deployment uses a single event-loop for all worker verticles instead of an event-loop per worker instance.

Previously, this was following event-loop deployments which use an event-loop per verticle instance for scalability purpose.

Miscellaneous

NetServer connect stream removals

NetServer#connectStream() has been removed. This stream was designed for Rx like languages and the actually don’t provide any benefits at the expense of the API.

// 4.x
server.connectStream().handler(socket -> ...);

// 5.0
server.connectHandler(socket -> ...).listen();

TimeoutStream removal

TimeoutStream has been removed. This stream was designed for Rx like languages and the actually don’t provide any benefits at the expense of the API. Instead, the framework scheduler should be used instead along with a Vert.x context.

// 4.x
vertx.periodicStream(1L).handler(timerID -> ...);

// 5.0
server.setPeriodic(1L, timerID -> ...);

For RxJava like integrations

// 4.x
Observable<Long> timer = vertx.periodicStream(1000).toObservable();

// 5.0
Scheduler scheduler = RxHelper.scheduler(vertx);
Observable<Long> timer = Observable.interval(100, 100, TimeUnit.MILLISECONDS, scheduler);

keyCertOptions key manager mapper removal

KeyCertOptions#keyManagerMapper() method has been removed in Vert.x 5, implementors must instead implement keyManagerFactoryMappermethod that provides the opportunity to cache the KeyManagerFactory to the implementor that controls the lifecycle of the key manager.

Removal of execute blocking methods with a handler of promise

The API for executing blocking actions uses a pattern with handler completing or failing a promise, instead this can be replaced with java.util.concurrent.Callable that returns the same value or throws an exception.

// 4.x
Future<String> fut = vertx.executeBlocking(promise -> promise.complete("result"));

// 5.0
Future<String> fut = vertx.executeBlocking(() -> "result");

processArgs methods deprecated

io.vertx.core.Context#processArgs and io.vertx.core.AbstractVerticle#processArgs are deprecated.

As of version 5, Vert.x is no longer tightly coupled to the CLI.

Netty type usage removals

The Vert.x API exposes the Netty API in its public API, allowing interactions with the Netty API. Since Netty is evolving toward Netty 5, we should remove Netty API from the Vert.x public API in Vert.x 5 to have the opportunity to change the underlying Netty version used by Vert.x without worrying about the version of the Netty version.

Such API continues to exist in Vert.x 5 but is moved to internal API which is not contractual, therefore experimented users of this API can continue to use it granted that the version of Vert.x 5 uses Netty 4.

// 4.x
ByteBuf bb = buff.getByteBuf();
Buffer buf = Buffer.buffer(bb);
EventLoopGroup group = vertx.nettyEventLoopGroup();

// 5.0
ByteBuf bb = ((BufferInternal)buff).getByteBuf();
buf = BufferInternal.buffer(bb);
group = ((VertxInternal)vertx).nettyEventLoopGroup();

Vert.x Auth

AuthProvider pruning

io.vertx.ext.auth.AuthProvider` has been deprecated in Vert.x 4.0 in favour of io.vertx.ext.auth.authentication.AuthenticationProvider.

// 4.x
AuthProvider authProvider = ...

// 5.0
AuthenticationProvider authProvider = ...

Vert.x for Kotlin

Removal of await extension methods generation

Vert.x 4.x for Kotlin generates suspending extension methods to facilitate the invocation of Vert.x asynchronous method.

suspend fun HttpServer.listenAwait(port: Int, host: String): HttpServer {
   return awaitResult {
     this.listen(port, host, it)
  }
}

Such methods have been deprecated since the equivalent can be achieved using a Vert.x future instance and removed in Vert.x 5.

// 4.x
server.listenAwait(port, host)

// 5.0
server.listen(host, port).coAwait()

Vert.x gRPC

Removal of GrpcReadStream#collecting in favour of ReadStream#collect

// 4.x
stream.collecting(collector);

// 5.0
stream.collect(collector);

Removal of methods declaring a method descriptor

GrpcClient/GrpcServer methods declaring a MethodDescriptor have been removed.

Instead, these methods are now available in GrpcIoClient/GrpcIoServer interfaces which extend GrpcClient/GrpcServer interfaces.

// 4.x
GrpcServer server = GrpcServer.create(vertx);

// 5.0
GrpcIoServer server = GrpcIoServer.create(vertx);
server.callHandler(methodDescriptor, request -> ...);

Vert.x Web

RoutingContext user API

User related operations have been moved under a single context API accessible from RoutingContext

Logout

// 4.x
routingContext.clearUser();

// 5.0
UserContext userContext = routingContext.userContext();
userContext.logout();

Setting a user

The RoutingContext#setUser method has been removed, this operation should be performed by authentication handlers instead.

Static handler configuration

StaticHandler methods setAllowRootFileSystemAccess and setWebRoot are removed after deprecation in Vert.x 4.x.

Instead, the handler must be configured at creation time:

// 4.x
StaticHandler handler = StaticHandler.create().setAllowRootFileSystemAccess(true).setWebRoot(root);

// 5.0
StaticHandler handler = StaticHandler.create(FileSystemAccess.ROOT, root);

Vert.x Web Client

Response expectation replacement

Vert.x Core introduces a new API to implement expectation checks inspired from the Web Client response expectation feature.

The Vert.x HTTP Client comes with the same set of predefined expectations than the Web Client response expectations, more importantly HTTP client response expectations can be re-used by Web Client.

HTTP response expectations leverages the new Future#expecting operation combined with the HttpResponseExpectation implementation.

// 4.x
client
  .get(8080, "myserver.mycompany.com", "/some-uri")
  .expect(ResponsePredicate.SC_SUCCESS)
  .send()
  .onSuccess(res -> {
    // ....
  });

// 5.0
client
  .get(8080, "myserver.mycompany.com", "/some-uri")
  .send()
  .expecting(HttpResponseExpectation.SC_SUCCESS)
  .onSuccess(res -> {
    // ....
  });

Vert.x Web Validation

Replacement of deprecated SchemaParser

Vert.x Web Validation was based on a deprecated JSON Schema API, which is no longer available in Vert.x 5.

// 4.x
ValidationHandlerBuilder.create(schemaParser)

// 5.0
SchemaRepository schemaRepo = SchemaRepository.create(new JsonSchemaOptions().setDraft(DRAFT7));
ValidationHandlerBuilder.create(schemaRepo);
To improve security, the new SchemaRepository is not automatically loading external references. In case your schema contains an external references you must provide and dereference them upfront.

Vert.x SQL Client

Client builder

The Pool subtypes are not really useful as they don’t carry any extra method and are use mainly for statically building pool.

In addition, those static methods are not flexible and are numerous due to overloading.

We are replacing these methods with a new client builder API.

// 4.x
PgPool client = PgPool.pool(vertx, connectOptions, poolOptions);

//5.0
Pool client = PgBuilder.pool()
  .with(poolOptions)
  .connectingTo(connectOptions)
  .using(vertx)
  .build();

Connect options

The SqlConnectOptions class does not extend anymore NetClientOptions class.

SqlConnectOptions TLS configuration still happens on this class.

// 4.x
// 5.0
PgConnectOptions options = new PgConnectOptions()
  .setPort(port)
  .setHost(host)
  .setDatabase(database)
  .setUser(user)
  .setPassword(password)
  .setSslOptions(new ClientSSLOptions()
    .setTrustOptions(new PemTrustOptions().addCertPath(pathToCert))
  );

NetClientOptions can still be passed when building a client thanks to the ClientBuilder.

// 5.0
Pool pool = PgBuilder.pool()
      .connectingTo(connectOptions)
      .with(tcpOptions)
      .build();

Pool connect handler

Pool#connectHandler method is moved to the new ClientBuilder, the handler is set once at build time instead of being a mutable field of the pool implementations.

// 4.x
pool.connectHandler(connectHandler);

// 5.0
builder.connectHandler(connectHandler);

Pool connection provider

Pool#connectionProvider method is replaced by a Supplier<Future<SqlConnectOptions>> builder method.

// 4.x
pool.connectionProvider(ctx -> futureOfSqlConnection(ctx));

// 5.0
builder.connectingTo(() -> futureOfSqlConnectOptions());

Vert.x Mongo Client

Upgrade to MongoDB Java Driver 5

MongoDB Java Driver 5.x is a breaking change release.

In IndexOptions, bucketSize has been removed.

Besides, StreamFactoryFactory has been replaced by TransportSettings, and Netty is the only available transport.

Vert.x Redis Client

Removal of request null argument

Redis does not accept null values in the request. The Request#nullArg() method therefore encoded null as the 4-character "null" string.

This method, which was deprecated in 4.x, is removed. All places that used it to encode the null value now throw an IllegalArgumentException.

If you use null values in Redis requests, you should stop doing that. To restore previous behavior, you should encode null values as "null" manually. This applies to:

  • Request.arg(String)

  • Request.arg(Buffer)

  • Request.arg(JsonArray): both the array itself, and individual elements

  • Request.arg(JsonObject): both the object itself, and individual elements

Automatic forwarding of Redis subscriptions to the Vert.x event bus

In Vert.x 4.x, the Redis subscriptions were automatically forwarded to the event bus, unless the message handler was set explicitly (using RedisConnection.handler()).

This is no longer the case. Since Vert.x 5, you always have to register a message handler. If you still want the subscription messages forwarded to the event bus, you have to manually create an instance of EventBusHandler and register it using RedisConnection.handler():

RedisConnection conn = ...;
conn.handler(EventBusHandler.create(vertx));
conn.send(Request.cmd(Command.SUBSCRIBE).arg("news"));

In addition, the EventBusHandler does not forward only messages ([p]message); it also forwards subscriptions and un-subscriptions ([p]subscribe and [p]unsubscribe).

RedisCluster.groupByNodes() changed return type + code generation changes

The RedisCluster#groupByNodes() method used to return Future<List<List<Request>>>. Due to this return type, the RedisCluster wasn’t @VertxGen.

This has changed in Vert.x 5. The groupByNodes() method now returns Future<RequestGrouping> and the entire interface is @VertxGen.

Further, the Request, Response and Command interfaces are no longer @VertxGen — instead, they are @DataObject. This means that users of code-generated APIs (such as Vert.x Rx) will no longer use the generated wrappers; they will use the core Vert.x Redis interfaces.

JSON serialization/deserialization of RedisOptions

The RedisOptions class has multiple methods to configure the Redis endpoints. These methods are still available, but the JSON format of this class has changed to only include one canonical field: endpoints.

If you rely on the JSON form of RedisOptions objects, note that the endpoint, connectionString and connectionStrings members of the JSON object are no longer recognized by the deserializer and are no longer generated by the serializer. Ensure that the necessary information is present in the endpoints member.

Options addEndpoint/setEndpoint replacements

RedisOptions#addEndpoint and RedisOptions#setEndpoint are replaced by RedisOptions#addConnectionString and RedisOptions#setConnectionString

// 4.x
options.setEndpoint(location);

// 4.x
options.setConnectionString(location);

Vert.x Health Check

Health checks dependencies improvements

Previously, Vert.x Health Check depended on Vert.x Web and Vert.x Auth. It now only defines the health check API, the health check route handler has been moved to Vert.x Web.

This result in a package change in import declarations.

// 4.x
import io.vertx.ext.healthchecks.HealthCheckHandler;

// 5.0
import io.vertx.ext.web.healthchecks.HealthCheckHandler;

Vert.x Circuit Breaker

Remove deprecated for removal retry policy

The circuit breaker retry policy with a Java function argument has been removed after deprecation in 4.x.

Instead, the RetryPolicy functional interface should be used.

// 4.x
breaker.retryPolicy(retryCount -> 5);

// 5.0
breaker.retryPolicy((failure, retryCount) -> 5);

Vert.x MQTT

Client options will message string getter/setter deprecated removal

Client options will message string getter/setter have been removed after deprecation in 4.x.

Instead, the Buffer version should be used

// 4.x
options.setWillMessage(str);

// 5.0
options.setWillMessageBytes(Buffer.buffer(str));

Vert.x Mail Client

Remove deprecated MailConfig setKeyStore/setKeyStorePassword

Remove deprecated MailConfig#setKeyStore and MailConfig#setKeyStorePassword properties.

Instead, use MailConfig#setTrustOptions.

// 4.x
options.setKeyStore(trustStorePath);
options.setKeyStorePassword(trustStorePassword);

// 5.0
options.setTrustOptions(new JksOptions().setPath(trustStorePath).setPassword(trustStorePassword));

Vert.x JUnit 5

Remove deprecated test context succeeding

Instead, use succeedingThenComplete() or succeeding(Handler).

// 4.x
someFuture.onComplete(testContext.succeeding());

// 5.0
someFuture.onComplete(testContex.succeedingThenComplete());

Vert.x Service Proxy

ServiceAuthInterceptor removal

Instead, use AuthorizationInterceptor.

// 4.x
new ServiceBinder(vertx)
   .addInterceptor(new ServiceAuthInterceptor()...)
   .register(SomeService.class, service);

// 5.0
new ServiceBinder(vertx)
   .addInterceptor(AuthorizationInterceptor.create(authorizationProvider)...)
   .register(SomeService.class, service);

ServiceBinder functionnal interceptor

The ServiceBinder#addInterceptor(Function) and ServiceBinder#addInterceptor(String, Function) have been removed in favor of the variant with the ServiceInterceptor functional interface.

// 4.x
binder.addInterceptor(msg -> vertx.timer(10, TimeUnit.MILLISECONDS).map(msg));

// 5.0
binder.addInterceptor((vertx, interceptorContext, body) -> vertx.timer(10, TimeUnit.MILLISECONDS).map(body));

Removal of ProxyHelper util class

The ProxyHelper util class is removed in favor of ServiceProxyBuilder / ServiceBinder equivalents.

// 4.x
ProxyHelper.registerService(MyService.class, vertx, service, "the-address");
MyService proxy = ProxyHelper.createProxy(MyService.class, vertx, "the-address");

// 5.0
new ServiceBinder(vertx)
  .setAddress("the-address")
  .register(MyService.class, service);
MyService proxy = new ServiceProxyBuilder(vertx)
  .setAddress("the-address")
  .build(MyService.class)

Vert.x Reactive Extensions

Data object changes

A few classes of Vert.x which have been historically annotated with @VertxGen and thus considered as asynchronous types have been converted to data objects.

As consequence reactive streams like generators will not need anymore to wrap/unwrap this type which avoids un-necessary allocation.

This implies that these objects are not anymore wrapped by Vert.x RX and the type will have their package name changed.

The following classes have been promoted to data objects:

  • io.vertx.core.buffer.Buffer

  • io.vertx.core.net.HostAndPort

  • io.vertx.core.net.SocketAddress

  • io.vertx.core.net.SelfSignedCertificate

  • io.vertx.core.MultiMap

  • io.vertx.core.datagram.DatagramPacket

  • io.vertx.core.dns.MxRecord

  • io.vertx.core.dns.SrvRecord

  • io.vertx.core.file.FileProps

  • io.vertx.core.file.FileSystemProps

  • io.vertx.core.http.Cookie

  • io.vertx.core.http.HttpFrame

  • io.vertx.core.http.WebSocketFrame

  • io.vertx.core.json.JsonEvent

Among all the types above, the Vert.x buffer type is likely the most impacting change.

io.vertx.core.buffer.Buffer has historically been part of the API as an async generated type, annotated by @VertxGen. It has always been wrapped/unwrapped with reactive stream based like generators.

// 4.x
io.vertx.reactivex.core.buffer.Buffer buffer = rxApi.getBuffer();

// 5.0
io.vertx.core.buffer.Buffer buffer = rxApi.getBuffer();

or

// 4.x
stream.write(io.vertx.reactivex.core.buffer.Buffer.buffer("the-string"));

// 5.0
stream.write(io.vertx.core.buffer.Buffer.buffer("the-string"));

The same applies to the other types mentioned.

Vert.x Micrometer Metrics

Upgrade to Micrometer 1.14

Micrometer 1.14 comes after 1.13, which is a breaking change release if you are using the PrometheusMeterRegistry API in your code.

Please take a look at Micrometer’s migration guide.

HTTP client pool metrics

HTTP client pool metrics are now exposed as generic pool metrics with pool type http

  • vertx_http_client_queue_pendingvertx_pool_queue_pending

  • vertx_http_client_queue_time_secondsvertx_pool_queue_time_seconds

Remove setting a registry on options

The micrometer options setter for a MeterRegistry has been removed in favour of the new VertxBuilder along with the MicrometerMetricsFactory.

// 4.x
Vertx vertx = Vertx.vertx(new VertxOptions()
 .setMetricsOptions(new MicrometerMetricsOptions()
   .setMicrometerRegistry(myRegistry)
   .setEnabled(true)));

// 5.0
Vertx vertx = Vertx.builder()
  .with(new VertxOptions()
    .setMetricsOptions(new MicrometerMetricsOptions()
    .setEnabled(true)))
  .withMetrics(new MicrometerMetricsFactory(myRegistry))
  .build();

Remove InfluxDB options number of threads

VertxInfluxDbOptions#getNumThreads and VertxInfluxDbOptions#setNumThreads are no longer used.

// 4.x
influxDbOptions.setNumThreads(numThreads);

// 5.0

Rename metrics options request tag provider

VertxMicrometerMetricsOptions#setRequestTagsProvider and VertxMicrometerMetricsOptions#getRequestTagsProvider are removed in favour of VertxMicrometerMetricsOptions#setServerRequestTagsProvider and VertxMicrometerMetricsOptions#getServerRequestTagsProvider.

// 4.x
options.setRequestsTagsProvider(provider);

// 5.0
options.setServerRequestsTagsProvider(provider);

Vert.x Dropwizard Metrics

HTTP client pool metrics

HTTP client pool metrics are now exposed as generic pool metrics with pool type http and named after the endpoint socket address

  • endpoint.<host:port>.queue-delayqueue-delay

  • endpoint.<host:port>.queue-sizequeue-size

Remove setting a metrics registry on metrics options

The drop wizard options setter for a MetricsRegistry has been removed in favour of the new VertxBuilder along with the DropwizardMetricsFactory.

// 4.x
Vertx vertx = Vertx.vertx(new VertxOptions()
 .setMetricsOptions(new DropwizardMetricsOptions()
   .setMetricsRegistry(myRegistry)
   .setEnabled(true)));

// 5.0
Vertx vertx = Vertx.builder()
  .with(new VertxOptions()
    .setMetricsOptions(new DropwizardMetricsOptions()
    .setEnabled(true)))
  .withMetrics(new DropwizardMetricsFactory(myRegistry))
  .build();

Vert.x Json Schema

Deprecated APIs removal

In Vert.x 5 the deprecated JSON Schema APIs are removed. Previously you had for every Draft an own SchemaParser. Now you have a SchemaRepository and can set the Draft in the options.

// 4.x
JsonObject schemaJson = new JsonObject(...);
Schema schema = new Draft7SchemaParser(SchemaRouter.create(vertx, new SchemaRouterOptions())).parse(schemaJson , scope);
JsonObject jsonToValidate = new JsonObject(...);
schema.validateSync(jsonToValidate);

// 5.0
JsonObject schemaJson = new JsonObject(...);
SchemaRepository schemaRepo = SchemaRepository.create(new JsonSchemaOptions().setDraft(DRAFT7));
JsonObject jsonToValidate = new JsonObject(...);
OutputUnit result = schemaRepo.validator(JsonSchema.of(schemaJson)).validate(jsonToValidate);

if (result.getValid()) {
  // Successful validation
}

Additional Error Types

In Vert.x 5 extra basic error types for output units have been added.

If you are constructing your own OutputUnits, you will need to include the OutputErrorType now as well. This helps to determine the cause of the failure.

// 4.x
OutputUnit ou = new OutputUnit("instanceLocation", "absoluteKeywordLocation", "keywordLocation", "error");

// 5.0
// Available error types are current OutputErrorType.NONE, OutputErrorType.INVALID_VALID, OutputErrorType.MISSING_VALUE
OutputUnit ou = new OutputUnit("instanceLocation", "absoluteKeywordLocation", "keywordLocation", "error", OutputErrorType.INVALID_VALUE);

Removal of SchemaType INT constant

Instead, use SchemaType#INTEGER.

Remove of ValidationException createException methods

Instead, use the same signature ValidationException#create replacements.

Vert.x Hazelcast

Upgrade to Hazelcast 5.3

This version includes many security fixes since Hazelcast 4.2.8. It requires JDK 11 to run, which is now the minimum required version in Vert.x 5.

The cluster manager is also tested with Hazelcast 5.4 and Hazelcast 5.5. But these versions require JDK 17 and JDK 21 as a minimum, respectively. Therefore, we cannot use them by default.