Chapter 4. Changes in common components

This section explains the changes in basic Eclipse Vert.x components.

4.1. Changes in messaging

This section explains the changes in the messaging methods.

4.1.1. Write and end methods in write streams are no longer fluent

The WriteStream<T>.write() and WriteStream<T>.end() methods are no longer fluent.

  • Write and end callback methods return void.
  • Other write and end methods return Future<Void>.

This is a breaking change. Update your applications if you have used the fluent aspect for write streams.

4.1.2. MessageProducer does not extend WriteStream

The MessageProducer interface does not extend the WriteStream interface.

In the previous releases of Eclipse Vert.x, the MessageProducer interface extended the WriteStream interface. The MessageProducer interface provided limited support for message back-pressure. Credit leaks would result in a reduction of credits in the message producer. If these leaks used all the credits, messages would not be sent.

However, MessageConsumer will continue to extend ReadStream. When MessageConsumer is paused and the pending message queue is full, the messages are dropped. This continues the integration with Rx generators to build message consuming pipelines.

4.1.3. Removed the send methods from MessageProducer

The send methods in the MessageProducer interface have been removed.

Use the methods MessageProducer<T>.write(T) instead of MessageProducer<T>.send(T) and EventBus.request(String,Object,Handler) instead of MessageProducer.send(T,Handler).

4.2. Changes in EventBus

The following section describes the changes in EventBus.

4.2.1. Removed the request-response send methods in EventBus

The EventBus.send(…​, Handler<AsyncResult<Message<T>>>) and Message.reply(…​, Handler<AsyncResult<Message<T>>>) methods have been removed. These methods would have caused overloading issues in Eclipse Vert.x 4. The version of the method returning Future<Message<T>> would collide with the fire and forget version.

The request-response messaging pattern should use the new request and replyAndRequest methods.

  • Use the method EventBus.request(…​, Handler<AsyncResult<Message<T>>>) instead of EventBus.send(…​, Handler<AsyncResult<Message<T>>>) to send a message.
  • Use the method Message.replyAndRequest(…​, Handler<AsyncResult<Message<T>>>) instead of Message.reply(…​, Handler<AsyncResult<Message<T>>>) to reply to the message.

The following example shows the request and reply to a message in Eclipse Vert.x 3.x releases.

Request
eventBus.send("the-address", body, ar -> ...);
Reply
eventBus.consumer("the-address", message -> {
       message.reply(body, ar -> ...);
});

The following example shows the request and reply to a message in Eclipse Vert.x 4.

Request
eventBus.request("the-address", body, ar -> ...);
Reply
eventBus.consumer("the-address", message -> {
  message.replyAndRequest(body, ar -> ...);
});

4.3. Changes in future

This section explains the changes in future.

4.3.1. Support for multiple handlers for futures

From Eclipse Vert.x 4 onward, multiple handlers are supported for a future. The Future<T>.setHandler() method used to set a single handler and has been removed. Use Future<T>.onComplete(), Future<T>.onSuccess(), and Future<T>.onFailure() methods instead to call handlers on completion, success, and failure results of an action.

The following example shows how to call a handler in Eclipse Vert.x 3.x releases.

Future<String> fut = getSomeFuture();
fut.setHandler(ar -> ...);

The following example shows how to call the new Future<T>.onComplete() method in Eclipse Vert.x 4.

Future<String> fut = getSomeFuture();
fut.onComplete(ar -> ...);

4.3.2. Removed the completer() method in future

In earlier releases of Eclipse Vert.x, you would use the Future.completer() method to access Handler<AsyncResult<T>>, which was associated with the Future.

In Eclipse Vert.x 4, the Future<T>.completer() method has been removed. Future<T> directly extends Handler<AsyncResult<T>>. You can access all the handler methods using the Future object. The Future object is also a handler.

4.3.3. Removed the connection handler method in HTTP client request

The HttpClientRequest.connectionHandler() method has been removed. Use HttpClient.connectionHandler() method instead to call connection handlers for client requests in your application.

The following example shows how the HttpClientRequest.connectionHandler() method was used in Eclipse Vert.x 3.x releases.

client.request().connectionHandler(conn -> {
  // Connection related code
}).end();

The following example shows you how to use the new HttpClient.connectionHandler() method in Eclipse Vert.x 4.

client.connectionHandler(conn -> {
  // Connection related code
});

4.4. Changes in verticles

This section explains the changes in the verticles.

4.4.1. Updates in the create verticle method

In earlier releases of Eclipse Vert.x, VerticleFactory.createVerticle() method synchronously instantiated a verticle. From Eclipse Vert.x 4 onward, the method asynchronously instantiates the verticle and returns the callback Callable<Verticle> instead of the single verticle instance. This improvement enables the application to call this method once and invoke the returned callable multiple times for creating multiple instances.

The following code shows how verticles were instantiated in Eclipse Vert.x 3.x releases.

Verticle createVerticle(String verticleName, ClassLoader classLoader) throws Exception;

The following code shows how verticles are instantiated in Eclipse Vert.x 4.

void createVerticle(String verticleName, ClassLoader classLoader, Promise<Callable<Verticle>> promise);

4.4.2. Updates in the factory class and methods

The VerticleFactory class has been simplified. The class does not require initial resolution of an identifier because the factory can instead use nested deployment to deploy the verticle.

If your existing applications use factories, in Eclipse Vert.x 4 you can update the code to use a callable when a promise completes or fails. The callable can be called several times.

The following example shows existing factories in an Eclipse Vert.x 3.x application.

return new MyVerticle();

The following example shows how to update existing factories to use promise in Eclipse Vert.x 4.

promise.complete(() -> new MyVerticle());

Use the Vertx.executeBlocking() method, if you want the factory to block code. When the factory receives the blocking code, it should resolve the promise and get the verticle instances from the promise.

4.4.3. Removed the multithreaded worker verticles

Multi-threaded worker verticle deployment option has been removed. This feature could only be used with Eclipse Vert.x event-bus. Other Eclipse Vert.x components such as HTTP did not support the feature.

Use the unordered Vertx.executeBlocking() method to achieve the same functionality as multi-threaded worker deployment.

4.5. Changes in threads

This section explains the changes in threads.

4.5.1. Context affinity for non Eclipse Vert.x thread

The Vertx.getOrCreateContext() method creates a single context for each non Eclipse Vert.x thread. The non Eclipse Vert.x threads are associated with a context the first time a context is created. In earlier releases, a new context was created each time the method was called from a non Eclipse Vert.x thread.

new Thread(() -> {
  assertSame(vertx.getOrCreateContext(), vertx.getOrCreateContext());
}).start();

This change does not affect your applications, unless your application implicitly relies on a new context to be created with each invocation.

In the following example the n blocks run concurrently as each blocking code is called on a different context.

for (int i = 0;i < n;i++) {
  vertx.executeBlocking(block, handler);
}

To get the same results in Eclipse Vert.x 4, you must update the code:

for (int i = 0;i < n;i++) {
  vertx.executeBlocking(block, false, handler);
}

4.6. Changes in HTTP

This section explains the changes in HTTP methods.

4.6.1. Generic updates in Eclipse Vert.x HTTP methods

The following section describes the miscellaneous updates in Eclipse Vert.x HTTP methods.

4.6.1.1. Updates in HTTP Methods for WebSocket

The changes in WebSocket are:

  • The usage of the term WebSocket in method names was inconsistent. The method names had incorrect capitalization, for example, Websocket, instead of WebSocket. The methods that had inconsistent usage of WebSocket in the following classes have been removed. Use the new methods that have correct capitalization instead.

    • The following methods in HttpServerOptions class have been removed.

      Removed methodsNew methods

      getMaxWebsocketFrameSize()

      getMaxWebSocketFrameSize()

      setMaxWebsocketFrameSize()

      setMaxWebSocketFrameSize()

      getMaxWebsocketMessageSize()

      getMaxWebSocketMessageSize()

      setMaxWebsocketMessageSize()

      setMaxWebSocketMessageSize()

      getPerFrameWebsocketCompressionSupported()

      getPerFrameWebSocketCompressionSupported()

      setPerFrameWebsocketCompressionSupported()

      setPerFrameWebSocketCompressionSupported()

      getPerMessageWebsocketCompressionSupported()

      getPerMessageWebSocketCompressionSupported()

      setPerMessageWebsocketCompressionSupported()

      setPerMessageWebSocketCompressionSupported()

      getWebsocketAllowServerNoContext()

      getWebSocketAllowServerNoContext()

      setWebsocketAllowServerNoContext()

      setWebSocketAllowServerNoContext()

      getWebsocketCompressionLevel()

      getWebSocketCompressionLevel()

      setWebsocketCompressionLevel()

      setWebSocketCompressionLevel()

      getWebsocketPreferredClientNoContext()

      getWebSocketPreferredClientNoContext()

      setWebsocketPreferredClientNoContext()

      setWebSocketPreferredClientNoContext()

      getWebsocketSubProtocols()

      getWebSocketSubProtocols()

      setWebsocketSubProtocols()

      setWebSocketSubProtocols()

      The new methods for WebSocket subprotocols use List<String> data type instead of a comma separated string to store items.

    • The following methods in HttpClientOptions class have been removed.

      Removed MethodsReplacing Methods

      getTryUsePerMessageWebsocketCompression()

      getTryUsePerMessageWebSocketCompression()

      setTryUsePerMessageWebsocketCompression()

      setTryUsePerMessageWebSocketCompression()

      getTryWebsocketDeflateFrameCompression()

      getTryWebSocketDeflateFrameCompression()

      getWebsocketCompressionAllowClientNoContext()

      getWebSocketCompressionAllowClientNoContext()

      setWebsocketCompressionAllowClientNoContext()

      setWebSocketCompressionAllowClientNoContext()

      getWebsocketCompressionLevel()

      getWebSocketCompressionLevel()

      setWebsocketCompressionLevel()

      setWebSocketCompressionLevel()

      getWebsocketCompressionRequestServerNoContext()

      getWebSocketCompressionRequestServerNoContext()

      setWebsocketCompressionRequestServerNoContext()

      setWebSocketCompressionRequestServerNoContext()

    • The following handler methods in HttpServer class have been removed.

      Deprecated MethodsNew Methods

      websocketHandler()

      webSocketHandler()

      websocketStream()

      webSocketStream()

  • WebsocketRejectedException is deprecated. The methods throw UpgradeRejectedException instead.
  • The HttpClient webSocket() methods use Handler<AsyncResult<WebSocket>> instead of Handler or Handler<Throwable>.
  • The number of overloaded methods to connect an HTTP client to a WebSocket has also been reduced by using the methods in WebSocketConnectOptions class.
  • The HttpServerRequest.upgrade() method has been removed. This method was synchronous.

    Use the new method HttpServerRequest.toWebSocket() instead. This new method is asynchronous.

    The following example shows the use of synchronous method in Eclipse Vert.x 3.x.

    // 3.x
    server.requestHandler(req -> {
      WebSocket ws = req.upgrade();
    });

    The following example shows the use of asynchronous method in Eclipse Vert.x 4.

    // 4.x
    server.requestHandler(req -> {
      Future<WebSocket> fut = req.toWebSocket();
      fut.onSuccess(ws -> {
      });
    });

4.6.1.2. Setting the number of WebSocket connections

In Eclipse Vert.x 3.x, you could use the the HTTP client pool size to define the maximum number of WebSocket connections in an application. The value accessor methods HttpClientOptions.maxPoolSize() were used to get and set the WebSocket connections. The default number of connections was set to 4 for each endpoint.

The following example shows how WebSocket connections are set in Eclipse Vert.x 3.x.

// 3.x
options.setMaxPoolSize(30); // Maximum connection is set to 30 for each endpoint

However, in Eclipse Vert.x 4, there is no pooling of WebSocket TCP connections, because the connections are closed after use. The applications use a different pool for HTTP requests. Use the value accessor methods HttpClientOptions.maxWebSockets() to get and set the WebSocket connections. The default number of connections is set to 50 for each endpoint.

The following example shows how to set WebSocket connections in Eclipse Vert.x 4.

// 4.x
options.setMaxWebSockets(30); // Maximum connection is set to 30 for each endpoint

4.6.1.3. HttpMethod is available as a interface

HttpMethod is available as a new interface.

In earlier releases of Eclipse Vert.x, HttpMethod was declared as an enumerated data type. As an enumeration, it limited the extensibility of HTTP. Further, it prevented serving other HTTP methods with this type directly. You had to use the HttpMethod.OTHER value along with the rawMethod attribute during server and client HTTP requests.

If you are using HttpMethod enumerated data type in a switch block, you can use the following code to migrate your applications to Eclipse Vert.x 4.

The following example shows a switch block in Eclipse Vert.x 3.x releases.

switch (method) {
  case GET:
    ...
    break;
  case OTHER:
    String s = request.getRawMethod();
    if (s.equals("PROPFIND") {
      ...
    } else ...
}

The following example shows a switch block in Eclipse Vert.x 4.

switch (method.name()) {
  case "GET":
    ...
    break;
  case "PROPFIND";
    ...
    break;
}

You can also use the following code in Eclipse Vert.x 4.

HttpMethod PROPFIND = HttpMethod.valueOf("PROPFIND");

if (method == HttpMethod.GET) {
  ...
} else if (method.equals(PROPFIND)) {
  ...
} else {
  ...
}

If you are using HttpMethod.OTHER value in your applications, use the following code to migrate the application to Eclipse Vert.x 4.

The following example shows you the code in Eclipse Vert.x 3.x releases.

client.request(HttpMethod.OTHER, ...).setRawName("PROPFIND");

The following example shows you the code in Eclipse Vert.x 4.

client.request(HttpMethod.valueOf("PROPFIND"), ...);

4.6.2. Changes in HTTP client

This section describes the changes in HTTP client.

The following types of Eclipse Vert.x clients are available:

Eclipse Vert.x web client
Use the Eclipse Vert.x web client when your applications are web oriented. For example, REST, encoding and decoding HTTP payloads, interpreting the HTTP status response code, and so on.
Eclipse Vert.x HTTP client
Use the Eclipse Vert.x HTTP client when your applications are used as HTTP proxy. For example, as an API gateway. The HTTP client has been updated and improved in Eclipse Vert.x 4.
Note

Eclipse Vert.x web client is based on Eclipse Vert.x HTTP client.

4.6.2.1. Migrating applications to Eclipse Vert.x web client

The web client was available from Eclipse Vert.x 3.4.0 release. There is no change in the web client in Eclipse Vert.x 4.

The client provides simplified HTTP interactions and some additional features, such as HTTP session, JSON encoding and decoding, response predicates, which are not available in the Eclipse Vert.x HTTP Client.

The following example shows how to use HTTP client in Eclipse Vert.x 3.x releases.

HttpClientRequest request = client.get(80, "example.com", "/", response -> {
  int statusCode = response.statusCode();
  response.exceptionHandler(err -> {
    // Handle connection error, for example, connection closed
  });
  response.bodyHandler(body -> {
    // Handle body entirely
  });
});
request.exceptionHandler(err -> {
  // Handle connection error OR response error
});
request.end();

The following example shows how to migrate an application to web client in Eclipse Vert.x 3.x and Eclipse Vert.x 4 releases.

client.get(80, "example.com", "/some-uri")
  .send(ar -> {
    if (ar.suceeded()) {
      HttpResponse<Buffer> response = ar.result();
      // Handle response
    }  else {
      // Handle error
    }
  });

4.6.2.2. Migrating applications to Eclipse Vert.x HTTP client

The HTTP client has fine grained control over HTTP interactions and focuses on the HTTP protocol.

The HTTP client has been updated and improved in Eclipse Vert.x 4:

  • Simplified APIs with fewer interactions
  • Robust error handling
  • Support for connection reset for HTTP/1

The updates in HTTP client APIs are:

  • The methods in HttpClientRequest such as, get(), delete(), put() have been removed. Use the method HttpClientRequest> request(HttpMethod method, …) instead.
  • HttpClientRequest instance is created when a request or response is possible. For example, an HttpClientRequest instance is created when the client connects to the server or a connection is reused from the pool.
4.6.2.2.1. Sending a simple request

The following example shows how to send a GET request in Eclipse Vert.x 3.x releases.

HttpClientRequest request = client.get(80, "example.com", "/", response -> {
  int statusCode = response.statusCode();
  response.exceptionHandler(err -> {
    // Handle connection error, for example, connection closed
  });
  response.bodyHandler(body -> {
    // Handle body entirely
  });
});
request.exceptionHandler(err -> {
  // Handle connection error OR response error
});
request.end();

The following example shows how to send a GET request in Eclipse Vert.x 4.

client.request(HttpMethod.GET, 80, "example.com", "/", ar -> {
  if (ar.succeeded()) {
    HttpClientRequest = ar.result();
    request.send(ar2 -> {
      if (ar2.succeeded()) {
        HttpClientResponse = ar2.result();
        int statusCode = response.statusCode();
        response.body(ar3 -> {
          if (ar3.succeeded()) {
            Buffer body = ar3.result();
            // Handle body entirely
          } else {
            // Handle server error, for example, connection closed
          }
        });
      } else {
        // Handle server error, for example, connection closed
      }
    });
  } else {
    // Connection error, for example, invalid server or invalid SSL certificate
  }
});

You can see that error handling is better in the new HTTP client.

The following example shows how to use future composition in a GET operation in Eclipse Vert.x 4.

Future<Buffer> fut = client.request(HttpMethod.GET, 80, "example.com", "/")
  .compose(request -> request.send().compose(response -> {
    int statusCode = response.statusCode();
    if (statusCode == 200) {
      return response.body();
    } else {
      return Future.failedFuture("Unexpectd status code");
    }
  })
});
fut.onComplete(ar -> {
  if (ar.succeeded()) {
    Buffer body = ar.result();
    // Handle body entirely
  } else {
    // Handle error
  }
});

Future composition improves exception handling. The example checks if the status code is 200, otherwise it returns an error.

Warning

When you use the HTTP client with futures, the HttpClientResponse() method starts emitting buffers as soon as it receives a response. To avoid this, ensure that the future composition occurs either on the event-loop (as shown in the example) or it should pause and resume the response.

4.6.2.2.2. Sending requests

In Eclipse Vert.x 3.x releases, you could use the end() method to send requests.

request.end();

You could also send a body in the request.

request.end(Buffer.buffer("hello world));

Since HttpClientRequest is a Writestream<Buffer>, you could also use a pipe to stream the request.

writeStream.pipeTo(request, ar -> {
  if (ar.succeeded()) {
    // Sent the stream
  }
});

In Eclipse Vert.x 4, you can perform all the operations shown in the examples using the get() method. You can also use the new send() method to perform these operations. You can pass a buffer, a string, or a ReadStream as input to the send() method. The method returns an HttpClientResponse instance.

// Send a request and process the response
request.onComplete(ar -> {
  if (ar.succeeded()) {
    HttpClientResponse response = ar.result();
    // Handle the response
  }
})
request.end();

// The new send method combines all the operations
request.send(ar -> {
  if (ar.succeeded()) {
    HttpClientResponse response = ar.result();
    // Handle the response
  }
}));
4.6.2.2.3. Handling responses

The HttpClientResponse interface has been updated and improved with the following methods:

body() method

The body() method returns an asynchronous buffer. Use the body() method instead of bodyHandler().

The following example shows how to use the bodyHandler() method to get the request body.

response.bodyHandler(body -> {
  // Process the request body
});
response.exceptionHandler(err -> {
  // Could not get the request body
});

The following example shows how to use the body() method to get the request body.

response.body(ar -> {
  if (ar.succeeded()) {
    // Process the request body
  } else {
    // Could not get the request body
  }
});
end() method

The end() method returns a future when a response is fully received successfully or failed. The method removes the response body. Use this method instead of endHandler() method.

The following example shows how to use the endHandler() method.

response.endHandler(v -> {
  // Response ended
});
response.exceptionHandler(err -> {
  // Response failed, something went wrong
});

The following example shows how to use the end() method.

response.end(ar -> {
  if (ar.succeeded()) {
    // Response ended
  } else {
    // Response failed, something went wrong
  }
});

You can also handle the response with methods such as, onSucces(), compose(), bodyHandler() and so on. The following examples demonstrate handling responses using the onSuccess() method.

The following example shows how to use HTTP client with the result() method in Eclipse Vert.x 3.x releases.

HttpClient client = vertx.createHttpClient(options);

    client.request(HttpMethod.GET, 8443, "localhost", "/")
      .onSuccess(request -> {
        request.onSuccess(resp -> {

        //Code to handle HTTP response
        });
      });

The following example shows how to use HTTP client with the result() method in Eclipse Vert.x 4.

HttpClient client = vertx.createHttpClient(options);

    client.request(HttpMethod.GET, 8443, "localhost", "/")
      .onSuccess(request -> {
        request.response().onSuccess(resp -> {

        //Code to handle HTTP response
        });
      });

4.6.2.3. Improvements in the Eclipse Vert.x HTTP client

This section describes the improvements in HTTP client.

4.6.2.3.1. HTTP client request and response methods take an asynchronous handler as input argument

The HttpClient and HttpClientRequest methods have been updated to use asynchronous handlers. The methods take Handler<AsyncResult<HttpClientResponse>> as input instead of Handler<HttpClientResponse>.

In earlier releases of Eclipse Vert.x, the HttpClient methods getNow(), optionsNow() and headNow() used to return HttpClientRequest, that you had to further send to perform a request. The getNow(), optionsNow() and headNow() methods have been removed. In Eclipse Vert.x 4, you can directly send a request with the required information using Handler<AsyncResult<HttpClientResponse>>.

The following examples show how to send a request in Eclipse Vert.x 3.x.

  • To perform a GET operation:

    Future<HttpClientResponse> f1 = client.get(8080, "localhost", "/uri", HttpHeaders.set("foo", "bar"));
  • To POST with a buffer body:

    Future<HttpClientResponse> f2 = client.post(8080, "localhost", "/uri", HttpHeaders.set("foo", "bar"), Buffer.buffer("some-data"));
  • To POST with a streaming body:

    Future<HttpClientResponse> f3 = client.post(8080, "localhost", "/uri", HttpHeaders.set("foo", "bar"), asyncFile);

In Eclipse Vert.x 4, you can use the requests methods to create an HttpClientRequest instance. These methods can be used in basic interactions such as:

  • Sending the request headers
  • HTTP/2 specific operations such as setting a push handler, setting stream priority, pings, and so on.
  • Creating a NetSocket tunnel
  • Providing fine grained write control
  • Resetting a stream
  • Handling 100 continue headers manually

The following example shows you how to create an HTTPClientRequest in Eclipse Vert.x 4.

client.request(HttpMethod.GET, 8080, "example.com", "/resource", ar -> {
  if (ar.succeeded()) {
    HttpClientRequest request = ar.result();
    request.putHeader("content-type", "application/json")
    request.send(new JsonObject().put("hello", "world"))
      .onSuccess(response -> {
      //
      }).onFailure(err -> {
      //
       });
     }
})
4.6.2.3.2. Removed the connection handler method from HTTP client request

The HttpClientRequest.connectionHandler() method has been removed. Use HttpClient.connectionHandler() method instead to call connection handlers for client requests in your application.

The following example shows how the HttpClientRequest.connectionHandler() method was used in Eclipse Vert.x 3.x releases.

client.request().connectionHandler(conn -> {
  // Connection related code
}).end();

The following example shows you how to use the new HttpClient.connectionHandler() method.

client.connectionHandler(conn -> {
// Connection related code
});
4.6.2.3.3. HTTP client tunneling using the net socket method

HTTP tunnels can be created using the HttpClientResponse.netSocket() method. In Eclipse Vert.x 4 this method has been updated.

To get a net socket for the connection of the request, send a socket handler in the request. The handler is called when the HTTP response header is received. The socket is ready for tunneling and can send and receive buffers.

The following example shows how to get net socket for a connection in Eclipse Vert.x 3.x releases.

client.request(HttpMethod.CONNECT, uri, ar -> {
  if (ar.succeeded()) {
    HttpClientResponse response = ar.result();
    if (response.statusCode() == 200) {
      NetSocket so = response.netSocket();
   }
  }
}).end();

The following example shows how to get net socket for a connection in Eclipse Vert.x 4.

client.request(HttpMethod.CONNECT, uri, ar -> {
}).netSocket(ar -> {
  if (ar.succeeded()) {
   // Got a response with a 200 status code
   NetSocket so = ar.result();
   // Go for tunneling
  }
}).end();
4.6.2.3.4. New send() method in HttpClient class

A new send() method is available in the HttpClient class.

The following code shows how to send a request in Eclipse Vert.x 4.

Future<HttpClientResponse> f1 = client.send(HttpMethod.GET, 8080, "localhost", "/uri", HttpHeaders.set("foo", "bar"));
4.6.2.3.5. HttpHeaders is an interface and contains MultiMap methods

In Eclipse Vert.x 4, HttpHeaders is an interface. In earlier releases of Eclipse Vert.x, HttpHeaders was a class.

The following new MultiMap methods have been added in the HttpHeaders interface. Use these methods to create MultiMap instances.

  • MultiMap.headers()
  • MultiMap.set(CharSequence name, CharSequence value)
  • MultiMap.set(String name, String value)

The following example shows how MultiMap instances were created in Eclipse Vert.x 3.x releases.

MultiMap headers = MultiMap.caseInsensitiveMultiMap();

The following examples show how to create MultiMap instances in Eclipse Vert.x 4.

MultiMap headers = HttpHeaders.headers();
MultiMap headers = HttpHeaders.set("content-type", "application.data");
4.6.2.3.6. CaseInsensitiveHeaders class is no longer public

The CaseInsensitiveHeaders class is no longer public. Use the MultiMap.caseInsensitiveMultiMap() method to create a multi-map implementation with case insensitive keys.

The following example shows how CaseInsensitiveHeaders method was used in Eclipse Vert.x 3.x releases.

CaseInsensitiveHeaders headers = new CaseInsensitiveHeaders();

The following examples show how MultiMap method is used in Eclipse Vert.x 4.

MultiMap multiMap = MultiMap#caseInsensitiveMultiMap();

OR

MultiMap headers = HttpHeaders.headers();
4.6.2.3.7. Checking the version of HTTP running on the server

In earlier releases of Eclipse Vert.x, the version of HTTP running on a server was checked only if the application explicitly called the HttpServerRequest.version() method. If the HTTP version was HTTP/1.x, the method would return the 501 HTTP status, and close the connection.

From Eclipse Vert.x 4 onward, before a request is sent to the server, the HTTP version on the server is automatically checked by calling the HttpServerRequest.version() method. The method returns the HTTP version instead of throwing an exception when an invalid HTTP version is found.

4.6.2.3.8. New methods in request options

In Eclipse Vert.x 4, the following new methods are available in the RequestOptions class:

  • Header
  • FollowRedirects
  • Timeout

The following example shows how to use the new methods.

client.request(HttpMethod.GET, 8080, "example.com", "/resource", ar -> {
  if (ar.succeeded()) {
    HttpClientRequest request = ar.result();
    request.putHeader("content-type", "application/json")
    request.send(new JsonObject().put("hello", "world"))
      .onSuccess(response -> {
      //
      }).onFailure(err -> {
      //
       });
     }
})

4.7. Changes in connection methods

This section explains the changes in connection methods.

4.7.1. Checking if authentication is required for client

The NetServerOptions.isClientAuthRequired() method has been removed. Use the getClientAuth() == ClientAuth.REQUIRED enumerated type to check if client authentication is required.

The following example shows how to use a switch statement to check if authentication of the client is required.

switch (options.getClientAuth()) {
case REQUIRED:
// ... behavior same as in releases prior to {VertX} {v4}
break;
default:
// fallback statement...
}

The following example shows how to use the check if authentication of the client is required in Eclipse Vert.x 4.

if (options.getClientAuth() == ClientAuth.REQUIRED) {
// behavior in releases prior to {VertX} {v4}

4.7.2. Upgrade SSL method uses asynchronous handler

The NetSocket.upgradeToSsl() method has been updated to use Handler<AsyncResult> instead of Handler. The handler is used to check if the channel has been successfully upgraded to SSL or TLS.

4.8. Changes in logging

This section explains the changes in logging.

4.8.1. Deprecated logging classes and methods

The logging classes Logger and LoggerFactory along with their methods have been deprecated. These logging classes and methods will be removed in a future release.

4.8.2. Removed Log4j 1 logger

The Log4j 1 logger is no longer available. However, if you want to use Log4j 1 logger, it is available with SLF4J.

4.9. Changes in Eclipse Vert.x Reactive Extensions (Rx)

This section describes the changes in Reactive Extensions (Rx) in Eclipse Vert.x. Eclipse Vert.x uses the RxJava library.

4.9.1. Support for RxJava 3

From Eclipse Vert.x 4.1.0, RxJava 3 is supported.

  • A new rxified API is available in the io.vertx.rxjava3 package.
  • Integration with Eclipse Vert.x JUnit5 is provided by the vertx-junit5-rx-java3 binding.

To upgrade to RxJava 3, you must make the following changes:

  • In the pom.xml file, under <dependency> change the RxJava 1 and 2 bindings from vertx-rx-java or vertx-rx-java2 to vertx-rx-java3.
  • In your application, update the imports from io.vertx.reactivex.* to io.vertx.rxjava3.*.
  • In your application, update the imports for RxJava 3 types also. For more information, see What’s new section in RxJava 3 documentation.

4.9.2. Removed onComplete callback from write stream

The WriteStreamSubscriber.onComplete() callback has been removed. This callback was invoked if WriteStream had pending streams of data to be written.

In Eclipse Vert.x 4, use the callbacks WriteStreamSubscriber.onWriteStreamEnd() and WriteStreamSubscriber.onWriteStreamError() instead. These callbacks are called after WriteStream.end() is complete.

WriteStreamSubscriber<Buffer> subscriber = writeStream.toSubscriber();

The following example shows how to create the adapter from a WriteStream in Eclipse Vert.x 3.x releases.

subscriber.onComplete(() -> {
    // Called after writeStream.end() is invoked, even if operation has not completed
});

The following examples show how to create the adapter from a WriteStream using the new callback methods in Eclipse Vert.x 4 release:

subscriber.onWriteStreamEnd(() -> {
    // Called after writeStream.end() is invoked and completes successfully
});
subscriber.onWriteStreamError(() -> {
    // Called after writeStream.end() is invoked and fails
});

4.10. Changes in Eclipse Vert.x configuration

The following section describes the changes in Eclipse Vert.x configuration.

4.10.1. New method to retrieve configuration

The method ConfigRetriever.getConfigAsFuture() has been removed. Use the method retriever.getConfig() instead.

The following example shows how configuration was retrieved in Eclipse Vert.x 3.x releases.

Future<JsonObject> fut = ConfigRetriever. getConfigAsFuture(retriever);

The following example shows how to retrieve configuration in Eclipse Vert.x 4.

fut = retriever.getConfig();

4.11. Changes in JSON

This section describes changes in JSON.

4.11.1. Encapsulation of Jackson

All the methods in the JSON class that implement Jackson types have been removed. Use the following methods instead:

Removed Fields/MethodsNew methods

Json.mapper() field

DatabindCodec.mapper()

Json.prettyMapper() field

DatabindCodec.prettyMapper()

Json.decodeValue(Buffer, TypeReference<T>)

JacksonCodec.decodeValue(Buffer, TypeReference)

Json.decodeValue(String, TypeReference<T>)

JacksonCodec.decodeValue(String, TypeReference)

For example, use the following code:

  • When using Jackson TypeReference:

    • In Eclipse Vert.x 3.x releases:

      List<Foo> foo1 = Json.decodeValue(json, new TypeReference<List<Foo>>() {});
    • In Eclipse Vert.x 4 release:

      List<Foo> foo2 = io.vertx.core.json.jackson.JacksonCodec.decodeValue(json, new TypeReference<List<Foo>>() {});
  • Referencing an ObjectMapper:

    • In Eclipse Vert.x 3.x releases:

      ObjectMapper mapper = Json.mapper;
    • In Eclipse Vert.x 4 release:

      mapper = io.vertx.core.json.jackson.DatabindCodec.mapper();
  • Setting an ObjectMapper:

    • In Eclipse Vert.x 3.x releases:

      Json.mapper = someMapper;
    • From Eclipse Vert.x 4 onward, you cannot write a mapper instance. You should use your own static mapper or configure the Databind.mapper() instance.

4.11.2. Object mapping

In earlier releases, the Jackson core and Jackson databind dependencies were required at runtime.

From Eclipse Vert.x 4 onward, only the Jackson core dependency is required.

You will require the Jackson databind dependency only if you are object mapping JSON. In this case, you must explicitly add the dependency in your project descriptor in the com.fasterxml.jackson.core:jackson-databind jar.

The following methods are supported for the mentioned types.

  • Methods

    • JsonObject.mapFrom(Object)
    • JsonObject.mapTo(Class)
    • Json.decodeValue(Buffer, Class)
    • Json.decodeValue(String, Class)
    • Json.encode(Object)
    • Json.encodePrettily(Object)
    • Json.encodeToBuffer(Object)
  • Type

    • JsonObject and JsonArray
    • Map and List
    • Number
    • Boolean
    • Enum
    • byte[] and Buffer
    • Instant

The following methods are supported only with Jackson bind:

  • JsonObject.mapTo(Object)
  • JsonObject.mapFrom(Object)

4.11.3. Base64 encoder updated to Base64URL for JSON objects and arrays

The Eclipse Vert.x JSON types implement RFC-7493. In earlier releases of Eclipse Vert.x, the implementation incorrectly used Base64 encoder instead of Base64URL. This has been fixed in Eclipse Vert.x 4, and Base64URL encoder is used in the JSON types.

If you want to continue using the Base64 encoder in Eclipse Vert.x 4, you can use the configuration flag legacy. The following example shows how to set the configuration flag in Eclipse Vert.x 4.

java -Dvertx.json.base64=legacy ...

During your migration from Eclipse Vert.x 3.x to Eclipse Vert.x 4 if you have partially migrated your applications, then you will have applications on both version 3 and 4. In such cases where you have two versions of Eclipse Vert.x you can use the following utility to convert the Base64 string to Base64URL.

public String toBase64(String base64Url) {
  return base64Url
    .replace('+', '-')
    .replace('/', '_');
}

public String toBase64Url(String base64) {
  return base64
    .replace('-', '+')
    .replace('_', '/');
}

You must use the utility methods in the following scenarios:

  • Handling integration while migrating from Eclipse Vert.x 3.x releases to Eclipse Vert.x 4.
  • Handling interoperability with other systems that use Base64 strings.

Use the following example code to convert a Base64URL to Base64 encoder.

String base64url = someJsonObject.getString("base64encodedElement")
String base64 = toBase64(base64url);

The helper functions toBase64 and toBase64Url enable only JSON migrations. If you use object mapping to automatically map JSON objects to a Java POJO in your applications, then you must create a custom object mapper to convert the Base64 string to Base64URL.

The following example shows you how to create a object mapper with custom Base64 decoder.

// simple deserializer from Base64 to byte[]
class ByteArrayDeserializer extends JsonDeserializer<byte[]> {
  ByteArrayDeserializer() {
  }

  public byte[] deserialize(JsonParser p, DeserializationContext ctxt) {
    String text = p.getText();
    return Base64.getDecoder()
      .decode(text);
  }
}

// ...

ObjectMapper mapper = new ObjectMapper();

// create a custom module to address the Base64 decoding
SimpleModule module = new SimpleModule();
module.addDeserializer(byte[].class, new ByteArrayDeserializer());
mapper.registerModule(module);

// JSON to POJO with custom deserializer
mapper.readValue(json, MyClass.class);

4.11.4. Removed the JSON converter method from trust options

The TrustOptions.toJSON method has been removed.

4.12. Changes in Eclipse Vert.x web

The following section describes the changes in Eclipse Vert.x web.

4.12.1. Combined the functionality of user session handler in session handler

In earlier releases of Eclipse Vert.x, you had to specify both the UserSessionHandler and SessionHandler handlers when working in a session.

To simplify the process, in Eclipse Vert.x 4, the UserSessionHandler class has been removed and its functionality has been added in the SessionHandler class. In Eclipse Vert.x 4, to work with sessions you must specify only one handler.

4.12.3. Favicon and error handlers use Vertx file system

The create methods in FaviconHandler and ErrorHandler have been updated. You must pass a Vertx instance object in the create methods. These methods access file system. Passing the Vertx object ensures consistent access to files using the 'Vertx' file system.

The following example shows how create methods were used in Eclipse Vert.x 3.x releases.

FaviconHandler.create();
ErrorHandler.create();

The following example shows how create methods should be used in Eclipse Vert.x 4.

FaviconHandler.create(vertx);
ErrorHandler.create(vertx);

4.12.4. Accessing the template engine

Use the method TemplateEngine.unwrap() to access the template engine. You can then apply customizations and configurations to the template.

The following methods that are used to get and set the engine configurations have been deprecated. Use the TemplateEngine.unwrap() method instead.

  • HandlebarsTemplateEngine.getHandlebars()
  • HandlebarsTemplateEngine.getResolvers()
  • HandlebarsTemplateEngine.setResolvers()
  • JadeTemplateEngine.getJadeConfiguration()
  • ThymeleafTemplateEngine.getThymeleafTemplateEngine()
  • ThymeleafTemplateEngine.setMode()

4.12.5. Removed the locale interface

The io.vertx.ext.web.Locale interface has been removed. Use the io.vertx.ext.web.LanguageHeader interface instead.

4.12.6. Removed the acceptable locales method

The RoutingContext.acceptableLocales() method has been removed. Use the RoutingContext.acceptableLanguages() method instead.

4.12.7. Updated the method for mounting sub routers

In earlier releases of Eclipse Vert.x, the Router.mountSubRouter() method incorrectly returned a Router. This has been fixed, and the method now returns a Route.

4.12.8. Removed the create method with excluded strings for JWT authentication handling

The JWTAuthHandler.create(JWTAuth authProvider, String skip) method has been removed. Use the JWTAuthHandler.create(JWTAuth authProvider) method instead.

The following example shows how JWT authentication handler was created in Eclipse Vert.x 3.x releases.

router
   // protect everything but "/excluded/path"
   .route().handler(JWTAuthHandler(jwtAuth, "/excluded/path")

The following example shows how JWT authentication handler was created in Eclipse Vert.x 4.

router
   .route("/excluded/path").handler(/* public access to "/excluded/path" */)
   // protect everything
   .route().handler(JWTAuthHandler(jwtAuth)

4.12.9. Removed the create handler method that was used in OSGi environments

In Eclipse Vert.x 4, OSGi environment is no longer supported. The StaticHandler.create(String, ClassLoader) method has been removed because the method was used in the OSGi environment.

If you have used this method in your applications, then in Eclipse Vert.x 4 you can either add the resources to the application classpath or serve resources from the file system.

4.12.10. Removed the bridge options class

The sockjs.BridgeOptions class has been removed. Use the new sockjs.SockJSBridgeOptions class instead. The sockjs.SockJSBridgeOptions class contains all the options that are required to configure the event bus bridge.

There is no change in the behavior of the new class, except that the name of the data object class has changed.

In previous releases, when you used sockjs.BridgeOptions class to add new bridges, there were a lot of duplicate configurations. The new class contains all the possible common configurations, and removes duplicate configurations.

4.12.11. SockJS socket event bus does not register a clustered event by default

SockJSSocket no longer registers a clustered event bus consumer by default. If you want to write to the socket using the event bus, you must enable the writeHandler in SockJSHandlerOptions. When you enable the writeHandler, the event bus consumer is set to local by default.

Router router = Router.router(vertx);
SockJSHandlerOptions options = new SockJSHandlerOptions()
  .setRegisterWriteHandler(true); // enable the event bus consumer registration
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, options);
router.mountSubRouter("/myapp", sockJSHandler.socketHandler(sockJSSocket -> {
  // Retrieve the writeHandlerID and store it (For example, in a local map)
  String writeHandlerID = sockJSSocket.writeHandlerID();
}));

You can configure the event bus consumer to a cluster.

SockJSHandlerOptions options = new SockJSHandlerOptions()
  .setRegisterWriteHandler(true) // enable the event bus consumer registration
  .setLocalWriteHandler(false) // register a clustered event bus consumer

4.12.12. New method for adding authentication provider

The SessionHandler.setAuthProvider(AuthProvider) method has been deprecated. Use the SessionHandler.addAuthProvider() method instead. The new method allows an application to work with multiple authentication providers and link the session objects to these authentication providers.

4.12.13. OAuth2 authentication provider create methods require vertx as constructor argument

From Eclipse Vert.x 4, OAuth2Auth.create(Vertx vertx) method requires vertx as a constructor argument. The vertx argument uses a secure non-blocking random number generator to generate nonce which ensures better security for applications.

4.13. Changes in Eclipse Vert.x Web GraphQL

The following section describes the changes in Eclipse Vert.x Web GraphQL.

Important

Eclipse Vert.x Web GraphQL is provided as Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend to use them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.

See Technology Preview Features Support Scope on the Red Hat Customer Portal for information about the support scope for Technology Preview features.

4.13.1. Updated methods to be supported on multiple language (polyglot) environments

The following methods have been updated and are now supported on polyglot environments: * UploadScalar is now a factory, use the method UploadScalar.create() instead.

  • VertxBatchLoader is now a factory, use the method io.vertx.ext.web.handler.graphql.dataloader.VertxBatchLoader.create() instead.
  • VertxDataFetcher is now a factory, use the method io.vertx.ext.web.handler.graphql.schema.VertxDataFetcher.create() instead.
  • VertxPropertyDataFetcher is now a factory, use the method io.vertx.ext.web.handler.graphql.schema.VertxPropertyDataFetcher.create() instead.

4.13.2. Handling POST requests in Eclipse Vert.x Web GraphQL

In prior releases, the Eclipse Vert.x Web GraphQL handler could process its own POST requests. It did not need Eclipse Vert.x Web BodyHandler to process the requests. However, this implementation was susceptible to DDoS attacks.

From Eclipse Vert.x 4 onward, to process POST requests BodyHandler is required. You must install BodyHandler before installing Eclipse Vert.x Web GraphQL handler.

4.14. Changes in Micrometer metrics

The following section describes the changes in Micrometer metrics.

4.14.1. TCP sent and received bytes are recorded as counters with equivalent HTTP request and response summaries

In prior releases, the following metrics were recorded as distribution summaries for sockets. From Eclipse Vert.x 4 onward, these metrics are logged as counter, which report the amount of data exchanged.

  • Net client

    • vertx_net_client_bytes_read
    • vertx_net_client_bytes_written
  • Net server

    • vertx_net_server_bytes_read
    • vertx_net_server_bytes_written

For these counters, equivalent distribution summaries have been introduced for HTTP. These summaries are used to collect information about the request and response sizes.

  • HTTP client

    • vertx_http_client_request_bytes
    • vertx_http_client_response_bytes
  • HTTP server

    • vertx_http_server_request_bytes
    • vertx_http_server_response_bytes

4.14.2. Renamed the metrics

The following metrics have been renamed.

Old metrics nameNew metrics nameUpdated in components

*_connections

*_active_connections

Net client and server

HTTP client and server

*_bytesReceived

*_bytes_read

Datagram

Net client and server

HTTP client and server

*_bytesSent

*_bytes_written

Datagram

Net client and server

HTTP client and server

*_requests

*_active_requests

HTTP client

HTTP server

*_requestCount_total

*_requests_total

HTTP client

HTTP server

*_responseTime_seconds

*_response_time_seconds

HTTP client

HTTP server

*_responseCount_total

*_responses_total

HTTP client

HTTP server

*_wsConnections

*_active_ws_connections

HTTP client

HTTP server

vertx_http_client_queue_delay_seconds

vertx_http_client_queue_time_seconds

 

vertx_http_client_queue_size

vertx_http_client_queue_pending

 

vertx_http_server_requestResetCount_total

vertx_http_server_request_resets_total

 

vertx_eventbus_bytesWritten

vertx_eventbus_bytes_written

 

vertx_eventbus_bytesRead

vertx_eventbus_bytes_read

 

vertx_eventbus_replyFailures

vertx_eventbus_reply_failures

 

vertx_pool_queue_delay_seconds

vertx_pool_queue_time_seconds

 

vertx_pool_queue_size

vertx_pool_queue_pending

 

vertx_pool_inUse

vertx_pool_in_use

 

4.15. Changes in Eclipse Vert.x OpenAPI

In Eclipse Vert.x 4, a new module vertx-web-openapi is available. Use this module alone with vertx-web to develop contract-driven applications.

The new module works well with Eclipse Vert.x Web Router. The new module requires the following Eclipse Vert.x dependencies:

  • vertx-json-schema
  • vertx-web-validation

The new module is available in the package io.vertx.ext.web.openapi.

In Eclipse Vert.x 4, the older OpenAPI module vertx-web-api-contract is supported to facilitate the migration to the new module. It is recommended that you move to the new module vertx-web-openapi to take advantage of the new functionality.

4.15.1. New module uses router builder

The vertx-web-openapi module uses RouterBuilder to build the Eclipse Vert.x Web router. This router builder is similar to the router builer OpenAPI3RouterFactory in vertx-web-api-contract module.

To start working with the vertx-web-openapi module, instantiate the RouterBuilder.

RouterBuilder.create(vertx, "petstore.yaml").onComplete(ar -> {
  if (ar.succeeded()) {
    // Spec loaded with success
    RouterBuilder routerBuilder = ar.result();
  } else {
    // Something went wrong during router builder initialization
    Throwable exception = ar.cause();
  }
});

You can also instantiate the RouterBuilder using futures.

RouterBuilder.create(vertx, "petstore.yaml")
  .onSuccess(routerBuilder -> {
    // Spec loaded with success
  })
  .onFailure(exception -> {
    // Something went wrong during router builder initialization
  });
Note

The vertx-web-openapi module uses the Eclipse Vert.x file system APIs to load the files. Therefore, you do not have to specify / for the classpath resources. For example, you can specify petstore.yaml in your application. The RouterBuilder can identify the contract from your classpath resources.

4.15.2. New router builder methods

In most cases, you can search and replace usages of old OpenAPI3RouterFactory methods with the new RouterBuilder methods. The following table lists a few examples of old and new methods.

Old OpenAPI3RouterFactory methodsNew RouterBuilder methods

routerFactory.addHandlerByOperationId("getPets", handler)

routerBuilder.operation("getPets").handler(handler)

routerFactory.addFailureHandlerByOperationId("getPets", handler)

routerBuilder.operation("getPets").failureHandler(handler)

routerFactory.mountOperationToEventBus("getPets", "getpets.myapplication")

routerBuilder.operation("getPets").routeToEventBus("getpets.myapplication")

routerFactory.addGlobalHandler(handler)

routerBuilder.rootHandler(handler)

routerFactory.addBodyHandler(handler)

routerBuilder.bodyHandler(handler)

routerFactory.getRouter()

routerBuilder.createRouter()

Use the following syntax to access the parsed request parameters:

RequestParameters parameters = routingContext.get(io.vertx.ext.web.validation.ValidationHandler.REQUEST_CONTEXT_KEY);
int aParam = parameters.queryParameter("aParam").getInteger();

4.15.3. Handling security

In Eclipse Vert.x 4, the methods RouterFactory.addSecurityHandler() and OpenAPI3RouterFactory.addSecuritySchemaScopeValidator() are no longer available.

Use the RouterBuilder.securityHandler() method instead. This method accepts io.vertx.ext.web.handler.AuthenticationHandler as an handler. The method automatically recognizes OAuth2Handler and sets up the security schema.

The new security handlers also implement the operations defined in the OpenAPI specification.

4.15.4. Handling common failures

In vertx-web-openapi module, the following failure handlers are not available. You must set up failure handlers using the Router.errorHandler(int, Handler) method.

Old methods in`vertx-web-api-contract` moduleNew methods in vertx-web-openapi module

routerFactory.setValidationFailureHandler(handler)

router.errorHandler(400, handler)

routerBuilder.setNotImplementedFailureHandler(handler)

router.errorHandler(501, handler)

4.15.5. Accessing the OpenAPI contract model

In Eclipse Vert.x 4, the OpenAPI contract is not mapped to plain old Java object (POJO). So, the additional swagger-parser dependency is no longer required. You can use the getters and resolvers to retrieve specific components of the contract.

The following example shows how to retrieve a specific component using a single operation.

JsonObject model = routerBuilder.operation("getPets").getOperationModel();

The following example shows how to retrieve the full contract.

JsonObject contract = routerBuilder.getOpenAPI().getOpenAPI();

The following example shows you how to resolve parts of the contract.

JsonObject petModel = routerBuilder.getOpenAPI().getCached(JsonPointer.from("/components/schemas/Pet"));

4.15.6. Validating web requests without OpenAPI

In the vertx-web-api-contract module, you could validate HTTP requests using HTTPRequestValidationHandler. You did not have to use OpenAPI for validations.

In Eclipse Vert.x 4, to validate HTTP requests use vertx-web-validation module. You can import this module and validate requests without using OpenAPI. Use ValidationHandler to validate requests.

4.15.7. Updates in the Eclipse Vert.x web API service

The vertx-web-api-service module has been updated and can be used with the vertx-web-validation module. If you are working with vertx-web-openapi module, there is no change in the web service functionality.

However, if you do not use OpenAPI, then to use the web service module with vertx-web-validation module you must use the RouteToEBServiceHandler class.

router.get("/api/transactions")
  .handler(
    ValidationHandlerBuilder.create(schemaParser)
      .queryParameter(optionalParam("from", stringSchema()))
      .queryParameter(optionalParam("to", stringSchema()))
      .build()
  ).handler(
    RouteToEBServiceHandler.build(eventBus, "transactions.myapplication", "getTransactionsList")
  );

The vertx-web-api-service module does not support vertx-web-api-contract. So, when you upgrade to Eclipse Vert.x 4, you must migrate your Eclipse Vert.x OpenAPI applications to vertx-web-openapi module.