1. Introduction

RESTEasy Vert.x provides integration between RESTEasy and Eclipse Vert.x, bringing Jakarta RESTful Web Services to Vert.x’s reactive, event-driven architecture. The project consists of several modules:

  • resteasy-vertx-embedded-server — An embedded HTTP server using Vert.x Web and the standard SeBootstrap API

  • resteasy-vertx-client — A RESTEasy client HTTP engine backed by the Vert.x HTTP client

  • resteasy-vertx-api — Shared API types for managing the Vertx instance and configuration

  • resteasy-vertx-cdi — CDI integration for automatic dependency injection in Jakarta REST resources

1.1. Version Information

This guide is for RESTEasy Vert.x version 2.0.0.Beta2.

2. Getting Started

2.1. Maven Dependencies

Add the BOM to your project’s dependency management section to align all RESTEasy Vert.x module versions:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>dev.resteasy.vertx</groupId>
            <artifactId>resteasy-vertx-bom</artifactId>
            <version>2.0.0.Beta2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Then add the modules you need:

<dependencies>
    <!-- Embedded server -->
    <dependency>
        <groupId>dev.resteasy.vertx</groupId>
        <artifactId>resteasy-vertx-embedded-server</artifactId>
    </dependency>

    <!-- Client engine -->
    <dependency>
        <groupId>dev.resteasy.vertx</groupId>
        <artifactId>resteasy-vertx-client</artifactId>
    </dependency>

    <!-- CDI support (optional) -->
    <dependency>
        <groupId>dev.resteasy.vertx</groupId>
        <artifactId>resteasy-vertx-cdi</artifactId>
    </dependency>
</dependencies>

2.2. Quick Start

Start an embedded server using the standard Jakarta REST SeBootstrap API:

@ApplicationPath("/api")
public class MyApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        return Set.of(GreetingResource.class);
    }
}

SeBootstrap.Configuration config = SeBootstrap.Configuration.builder()
    .host("localhost")
    .port(8080)
    .build();

SeBootstrap.Instance instance = SeBootstrap.start(MyApplication.class, config)
    .toCompletableFuture()
    .join();

URI uri = instance.configuration().baseUri();
// Server running at http://localhost:8080/api

Create a client to call the running server:

Client client = ClientBuilder.newClient();
String result = client.target("http://localhost:8080/api/greeting")
    .request(MediaType.TEXT_PLAIN)
    .get(String.class);
client.close();

The Vert.x client engine is automatically discovered via ServiceLoader. Both client and server share a single managed Vertx instance that is created lazily and shut down automatically.

2.3. Custom Vertx Instance

By default, a Vertx instance is created and managed automatically. To provide your own Vertx instance (for example, to reuse one from your existing application), implement the VertxFactory interface and register it via ServiceLoader:

public class MyVertxFactory implements VertxFactory {
    @Override
    public Vertx create() {
        return MyApplication.getSharedVertx();
    }
}

Register in META-INF/services/dev.resteasy.vertx.spi.VertxFactory:

com.example.MyVertxFactory

3. Embedded Server

The embedded server module integrates RESTEasy with the Vert.x HTTP server and Vert.x Web Router. It implements the EmbeddedServer interface for SeBootstrap integration and is automatically discovered via ServiceLoader.

3.1. SeBootstrap Usage

The recommended way to start the server is through the standard Jakarta REST SeBootstrap API:

SeBootstrap.Configuration config = SeBootstrap.Configuration.builder()
    .host("localhost")
    .port(8080)
    .rootPath("/api")
    .build();

SeBootstrap.Instance instance = SeBootstrap.start(MyApplication.class, config)
    .toCompletableFuture()
    .join();

// Stop the server
instance.stop().toCompletableFuture().join();

3.2. SSL/TLS

HTTPS is enabled by setting the protocol to "HTTPS" and providing an SSLContext:

SSLContext sslContext = SSLContext.getInstance("TLS");
// ... initialize with KeyManager/TrustManager ...

SeBootstrap.Configuration config = SeBootstrap.Configuration.builder()
    .protocol("HTTPS")
    .sslContext(sslContext)
    .sslClientAuthentication(SSLClientAuthentication.OPTIONAL)
    .host("localhost")
    .port(8443)
    .build();

SeBootstrap.start(MyApplication.class, config);

Client authentication maps to Vert.x ClientAuth values:

  • MANDATORYClientAuth.REQUIRED

  • OPTIONALClientAuth.REQUEST

  • NONE (default) → ClientAuth.NONE

If no SSLContext is provided, SSLContext.getDefault() is used.

3.3. Vert.x Context Injection

The server makes several Vert.x types available via @Context injection:

  • io.vertx.core.Vertx — the shared Vert.x instance

  • io.vertx.ext.web.RoutingContext — the routing context for the current request

  • io.vertx.ext.web.Router — the Vert.x Web router

@GET
@Path("/info")
@Produces(MediaType.TEXT_PLAIN)
public String info(@Context io.vertx.core.Vertx vertx,
                   @Context io.vertx.ext.web.RoutingContext routingContext,
                   @Context io.vertx.ext.web.Router router) {
    return "Running on Vert.x";
}

3.4. Async Support

Jakarta REST async responses are fully supported. The Vertx instance can be injected via @Context to use idiomatic Vert.x async patterns:

@GET
@Path("/async")
@Produces(MediaType.TEXT_PLAIN)
public void asyncGet(@Context Vertx vertx, @Suspended AsyncResponse asyncResponse) {
    vertx.executeBlocking(() -> {
        // Perform blocking work off the event loop
        return "async result";
    }).onSuccess(asyncResponse::resume)
      .onFailure(asyncResponse::resume);
}

3.5. Custom Router Factory

The server uses a Vert.x Web Router for request handling. You can customize the router to add Vert.x Web middleware such as CORS handlers, session management, or authentication by providing a RouterFactory.

3.5.1. Via SeBootstrap Configuration

SeBootstrap.Configuration config = SeBootstrap.Configuration.builder()
    .property(RouterFactory.PROPERTY, (RouterFactory) vertx -> {
        Router router = Router.router(vertx);
        router.route().handler(CorsHandler.create());
        return router;
    })
    .build();

SeBootstrap.start(MyApplication.class, config);

3.5.2. Via ServiceLoader

Create a global default factory by implementing RouterFactory and registering it in META-INF/services/dev.resteasy.vertx.server.spi.RouterFactory:

public class MyRouterFactory implements RouterFactory {
    @Override
    public Router create(Vertx vertx) {
        Router router = Router.router(vertx);
        router.route().handler(CorsHandler.create());
        return router;
    }
}

The resolution order is:

  1. RouterFactory set on SeBootstrap.Configuration via the RouterFactory.PROPERTY property

  2. RouterFactory discovered via ServiceLoader

  3. Default factory that creates a plain Router via Router.router(Vertx)

3.6. Request Forwarding

Requests can be forwarded to a different path within the same server:

@GET
@Path("/old-path")
public void forward(@Context HttpRequest request) {
    request.forward("/new-path");
}

The request body is preserved across forwards for POST and other methods with a body.

3.7. Request Size Limits

The maximum allowed request body size defaults to 10 MB. Requests exceeding this limit are rejected with HTTP 413 (Payload Too Large). This can be configured via the dev.resteasy.vertx.server.max.request.size system property. Set to -1 to disable the limit.

4. Client Engine

The client module provides a Vert.x-backed HTTP engine for the RESTEasy client. It implements AsyncClientHttpEngine and supports both synchronous and asynchronous invocations.

4.1. Auto-Discovery

The Vert.x client engine is automatically discovered via ServiceLoader when the resteasy-vertx-client artifact is on the classpath. No additional configuration is needed:

Client client = ClientBuilder.newClient();
String result = client.target("http://localhost:8080/api/greeting")
    .request(MediaType.TEXT_PLAIN)
    .get(String.class);
client.close();

4.2. Features

The Vert.x client engine provides:

  • HTTP/1.1 and HTTP/2 support

  • SSL/TLS (including native SSL engine)

  • Chunked transfer encoding for streaming request bodies

  • Connection pooling

  • Async invocations with CompletableFuture

  • Proxy support

4.3. Async Invocations

The engine supports reactive invocations via CompletionStageRxInvoker:

Client client = ClientBuilder.newClient();
CompletionStage<String> future = client.target("http://localhost:8080/api/greeting")
    .request(MediaType.TEXT_PLAIN)
    .rx()
    .get(String.class);

future.thenAccept(result -> System.out.println("Got: " + result));

4.4. Request Timeout

A per-request timeout can be set using the VertxClientProperties.REQUEST_TIMEOUT property. The value can be a Duration, a Number (milliseconds), or a string parseable as a long:

Client client = ClientBuilder.newClient();
client.target("http://localhost:8080/api/slow")
    .request()
    .property(VertxClientProperties.REQUEST_TIMEOUT, Duration.ofSeconds(5))
    .get(String.class);

4.5. SSL/TLS

SSL is configured through the standard ClientBuilder API:

SSLContext sslContext = SSLContext.getInstance("TLS");
// ... initialize with KeyManager/TrustManager ...

Client client = ClientBuilder.newBuilder()
    .sslContext(sslContext)
    .build();

4.6. Configuration via ClientBuilder

When the engine is created via auto-discovery, the VertxClientHttpEngineFactory configures the Vert.x HttpClientOptions automatically from the ClientBuilder settings:

  • Connect timeout

  • Idle timeout

  • Read timeout

  • Proxy settings (HTTP proxy type)

  • SSL context

Client client = ClientBuilder.newBuilder()
    .connectTimeout(5, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build();

4.7. Custom HttpClientOptions

For full control over the Vert.x HTTP client configuration, pass custom HttpClientOptions via the VertxClientProperties.HTTP_CLIENT_OPTIONS property.

When custom HttpClientOptions are provided, standard ClientBuilder settings (timeouts, SSL context, proxy) are not applied. All configuration must be set directly on the provided options.
HttpClientOptions options = new HttpClientOptions()
    .setProtocolVersion(HttpVersion.HTTP_2)
    .setUseAlpn(true)
    .setConnectTimeout(5000)
    .setSsl(true);

Client client = ClientBuilder.newBuilder()
    .property(VertxClientProperties.HTTP_CLIENT_OPTIONS, options)
    .build();

5. CDI Integration

The CDI module enables Jakarta Contexts and Dependency Injection for Jakarta REST resources running on the Vert.x embedded server. Adding the resteasy-vertx-cdi dependency to the classpath is all that is needed — it is automatically activated via ServiceLoader.

5.1. Dependency

The CDI module requires Weld as the CDI implementation for request context management. Weld is included as a transitive dependency.

<dependency>
    <groupId>dev.resteasy.vertx</groupId>
    <artifactId>resteasy-vertx-cdi</artifactId>
</dependency>

5.2. Features

When the CDI module is active:

  • Jakarta REST resources are managed as CDI beans with full injection support

  • @ApplicationScoped, @RequestScoped, and other CDI scopes work as expected

  • CDI interceptors and decorators are supported

  • Vert.x types are available for injection with @Inject:

    • Vertx — @Singleton, the shared Vert.x instance

    • RoutingContext — @RequestScoped, the routing context for the current request

    • Router — @RequestScoped, the Vert.x Web router

  • The CDI request context is automatically activated and deactivated per HTTP request

  • CDI context is propagated to Vert.x worker threads for @Suspended async processing

5.3. Usage with SeBootstrap

@ApplicationScoped
public class GreetingService {
    public String greet(String name) {
        return "Hello, " + name + "!";
    }
}

@Path("/greeting")
@RequestScoped
public class GreetingResource {
    @Inject
    GreetingService service;

    @Inject
    Vertx vertx;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String greet(@QueryParam("name") String name) {
        return service.greet(name);
    }
}

// Start with SeBootstrap -- CDI container is automatically initialized
SeBootstrap.Instance instance = SeBootstrap.start(MyApplication.class, config)
    .toCompletableFuture()
    .join();

5.4. CDI Container Lifecycle

The CDI module manages the CDI container automatically:

  • If an existing CDI container is already running (e.g., started by the application or test framework), it is reused

  • If no container is running, a new one is created with bean-defining annotations for @Path, @Provider, and @ApplicationPath

  • The container is shut down when the server stops, but only if it was created by the module

5.5. Standalone Usage

For manual control, the CDI container can be initialized before the server:

// Boot CDI
try (SeContainer container = new Weld().skipShutdownHook().initialize()) {

    SeBootstrap.Configuration config = SeBootstrap.Configuration.builder()
        .host("localhost")
        .port(8080)
        .build();
    SeBootstrap.Instance server = SeBootstrap.start(GreetingApplication.class, config)
        .toCompletableFuture().join();
    // ... use the server ...

    server.stop().toCompletableFuture().join();
}

5.6. Context Injection

In addition to standard Jakarta REST context types, CDI resources can inject Vert.x types using @Inject:

@Path("/info")
@RequestScoped
public class InfoResource {
    @Inject
    Vertx vertx;

    @Inject
    RoutingContext routingContext;

    @Inject
    Router router;

    @Inject
    UriInfo uriInfo;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String info() {
        return uriInfo.getRequestUri().toString();
    }
}

5.7. Running on the Java Module Path

On the class path no extra configuration is required. On the Java module path, however, injecting the Vert.x RoutingContext and Router types requires additional JVM options.

RoutingContext and Router are produced as @RequestScoped beans, which is a normal scope, so Weld generates a CDI client proxy for each of them. On the module path Weld defines that proxy class into the package of the proxied type — io.vertx.ext.web, which is owned by the io.vertx.web module. Two things are needed for this to succeed:

  • the target package must be opened to Weld so it can define the generated class into it, and

  • the target module must read the Weld modules so the generated proxy can link the Weld interfaces it implements.

The following JVM options are required to allow injection of these types into your resources or providers:

--add-opens io.vertx.web/io.vertx.ext.web=weld.core.impl
--add-reads io.vertx.web=weld.core.impl
--add-reads io.vertx.web=weld.api

The Vertx producer is @Singleton, so it is not proxied and requires no additional options.

6. Configuration Reference

6.1. System Properties

Configuration options can be set via system properties or other configuration sources supported by RESTEasy’s Options framework.

Table 1. RESTEasy Vert.x configuration options
System Property Type Default Description

dev.resteasy.vertx.timeout

Long

30

Timeout value for blocking operations such as shutting down the Vertx instance.

dev.resteasy.vertx.timeout.unit

TimeUnit

SECONDS

Time unit for the timeout value.

dev.resteasy.vertx.server.max.request.size

Long

10485760 (10 MB)

Maximum allowed request body size in bytes. Requests exceeding this limit are rejected with HTTP 413. Set to -1 to disable.

6.2. SeBootstrap Configuration Properties

Table 2. Properties recognized on SeBootstrap.Configuration
Property Type Description

dev.resteasy.vertx.server.router.factory

RouterFactory

Custom RouterFactory instance to create the Vert.x Web Router. See Embedded Server for details.

6.3. Client Configuration Properties

Table 3. Properties recognized on ClientBuilder and Invocation.Builder (constants on VertxClientProperties)
Property Type Description

dev.resteasy.vertx.client.request.timeout

Duration, Number, or String

Per-request timeout in milliseconds.

dev.resteasy.vertx.client.http.options

HttpClientOptions

Custom Vert.x HttpClientOptions. Standard ClientBuilder settings are applied on top.

6.4. ServiceLoader Extension Points

The following interfaces can be implemented and registered via ServiceLoader to customize behavior:

Table 4. ServiceLoader extension points
Interface Description

dev.resteasy.vertx.spi.VertxFactory

Factory for creating the Vertx instance. Used by the default VertxManager implementation.

dev.resteasy.vertx.server.spi.RouterFactory

Factory for creating the Vert.x Web Router. Also configurable per-startup via SeBootstrap.Configuration.

7. Migrating from 1.x to 2.x

RESTEasy Vert.x 2.0 is a major release with significant architectural changes. This guide covers the key changes and how to update your code.

7.1. Package Rename

All packages have been renamed to align with the new group ID dev.resteasy.vertx:

Table 5. Package name changes
Old Package New Package

org.jboss.resteasy.client.jaxrs.engines.vertx

dev.resteasy.vertx.client

org.jboss.resteasy.plugins.server.vertx

dev.resteasy.vertx.server

Update all import statements in your code accordingly.

7.2. Server: SeBootstrap Replaces VertxJaxrsServer

The VertxJaxrsServer class and the deprecated EmbeddedJaxrsServer interface have been removed. Use the standard Jakarta REST SeBootstrap API instead:

Old (1.x)
VertxJaxrsServer server = new VertxJaxrsServer();
server.setPort(8080);
server.setRootResourcePath("/api");
server.setSecurityDomain(domain);
ResteasyDeployment deployment = server.getDeployment();
deployment.getRegistry().addPerRequestResource(MyResource.class);
server.start();
New (2.x)
SeBootstrap.Configuration config = SeBootstrap.Configuration.builder()
    .host("localhost")
    .port(8080)
    .rootPath("/api")
    .build();

SeBootstrap.Instance instance = SeBootstrap.start(MyApplication.class, config)
    .toCompletableFuture()
    .join();

7.3. Server: Vert.x Web Router

The embedded server now uses a Vert.x Web Router internally. This adds io.vertx:vertx-web as a required transitive dependency.

You can customize the router to add middleware (CORS, sessions, authentication) by providing a RouterFactory. See Embedded Server for details.

7.4. Server: Authentication

The SecurityDomain interface is no longer used. Use Vert.x Web authentication handlers on the Router via a RouterFactory instead:

Old (1.x)
SecurityDomain domain = new SimpleSecurityDomain(...);
new VertxRequestHandler(vertx, deployment, contextPath, domain);
New (2.x)
SeBootstrap.Configuration config = SeBootstrap.Configuration.builder()
    .property(RouterFactory.PROPERTY, (RouterFactory) vertx -> {
        Router router = Router.router(vertx);
        router.route().handler(BasicAuthHandler.create(authProvider));
        return router;
    })
    .build();

SeBootstrap.start(MyApplication.class, config);

7.5. Server: Removed Classes

The following classes have been removed in 2.x:

  • VertxJaxrsServer — replaced by SeBootstrap API

  • VertxResteasyDeployment — standard ResteasyDeploymentImpl is used directly

  • RequestDispatcher — logic merged into request handler

  • VertxContainer — test utility replaced by resteasy-junit-extension / SeBootstrap

  • VertxRegistry, VertxResourceFactory — no longer needed

7.6. Client: Custom Vertx Instance

Constructors that accepted a Vertx instance or HttpClient have been removed. To provide a custom Vertx instance, implement VertxFactory and register it via ServiceLoader:

public class MyVertxFactory implements VertxFactory {
    @Override
    public Vertx create() {
        return Vertx.vertx(new VertxOptions().setWorkerPoolSize(20));
    }
}

Register in META-INF/services/dev.resteasy.vertx.spi.VertxFactory.

7.7. Client: Property Constants Moved to VertxClientProperties

Client configuration property constants have been moved from VertxClientHttpEngine to the new VertxClientProperties class. The request timeout property has also been renamed:

Table 6. Client property changes
Old New

VertxClientHttpEngine.REQUEST_TIMEOUT_MS
(io.vertx.core.Vertx$RequestTimeout)

VertxClientProperties.REQUEST_TIMEOUT
(dev.resteasy.vertx.client.request.timeout)

A new VertxClientProperties.HTTP_CLIENT_OPTIONS property allows passing custom Vert.x HttpClientOptions via the standard ClientBuilder API without casting to ResteasyClientBuilder.

7.8. Shared Vertx Instance

Both client and server now share a single managed Vertx instance via VertxManager. The instance is created lazily and shut down automatically. To customize instance creation, implement VertxFactory as described above.

7.9. Vert.x Upgrade

Vert.x has been upgraded from 4.x/5.0.x to 5.1.x. Netty dependencies are now managed transitively by Vert.x — explicit Netty dependency declarations can be removed.

7.10. CDI Support

A new resteasy-vertx-cdi module provides CDI integration. See CDI Integration for details.