Skip to content

[Java][vertx] Apply Vert.x pool defaults in buildWebClient for useVertx5 (#24015)#24017

Merged
wing328 merged 1 commit into
OpenAPITools:masterfrom
seonwooj0810:fix/issue-24015-vertx5-pooloptions-defaults
Jun 13, 2026
Merged

[Java][vertx] Apply Vert.x pool defaults in buildWebClient for useVertx5 (#24015)#24017
wing328 merged 1 commit into
OpenAPITools:masterfrom
seonwooj0810:fix/issue-24015-vertx5-pooloptions-defaults

Conversation

@seonwooj0810

@seonwooj0810 seonwooj0810 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #24015

Problem

With `library=vertx` and `useVertx5=true`, the generated client throws a `NullPointerException` on the first API call when the `ApiClient` is built with the documented two-arg constructor:

ApiClient client = new ApiClient(vertx, new JsonObject()); // 2-arg ctor
new DefaultApiImpl(client).someOperation(request);         // -> NPE
java.lang.NullPointerException: Cannot invoke "java.util.concurrent.TimeUnit.toMillis(long)" because "sourceUnit" is null
	at io.vertx.core.http.impl.HttpClientImpl.<init>(HttpClientImpl.java:72)
	...
	at ...ApiClient.buildWebClient(ApiClient.java:644)

Root cause

The two-arg constructor delegates with an empty pool config, and buildWebClient turned it into new PoolOptions(poolConfig). Unlike its no-arg constructor (and unlike WebClientOptions(JsonObject), which calls init() first), Vert.x 5's PoolOptions(JsonObject) constructor does not initialize defaults before applying the JSON. So new PoolOptions(new JsonObject()) yields maxLifetimeUnit = null (plus pool sizes 0), and HttpClientImpl NPEs on the null time unit.

This path was introduced by #23829 (merged for 7.23.0).

Fix

In Java/libraries/vertx/ApiClient.mustache, overlay poolConfig on the serialized no-arg defaults so absent keys keep their documented values while explicit pool settings still apply:

PoolOptions poolOptions = new PoolOptions(new PoolOptions().toJson().mergeIn(poolConfig));
return WebClient.create(vertx, new WebClientOptions(config), poolOptions);

PoolOptionsConverter is package-private (@JsonGen(publicConverter = false)), so the overlay goes through the public PoolOptions.toJson(). This also handles partially-populated pool configs correctly (unlike a simple poolConfig.isEmpty() guard).

Test evidence

Standalone runtime check against io.vertx:vertx-core:5.0.11:

BEFORE  maxLifetimeUnit=null     http1MaxSize=0   (-> NPE in WebClient.create)
AFTER   maxLifetimeUnit=SECONDS  http1MaxSize=5
PARTIAL http1MaxSize=20 (user override applied)   maxLifetimeUnit=SECONDS (default kept)

Regenerated the vertx5 and vertx5-supportVertxFuture samples (bin/generate-samples.sh); both compile (mvn compile, JDK 21). Regenerating the non-vertx5 vertx samples produces no diff (the {{^useVertx5}} branch is unchanged).

Verification done

  1. No in-flight PR — gh pr list --search "vertx PoolOptions" only shows the merged [Java] [vertx] Allow PoolOptions configuration when vertx 5 #23829 that introduced the code; 2. no self-claim comments (0 comments); 3. code-focused (.mustache template + regenerated .java); 4. grepped master — new PoolOptions(poolConfig) still present in template line 734; 5. not a closed sub-issue.

Summary by cubic

Fixes #24015: Prevents a NullPointerException on the first API call in Vert.x 5 clients by applying default PoolOptions values in buildWebClient when the two-arg ApiClient constructor is used. Defaults are merged with poolConfig so missing fields are initialized and user overrides still apply.

  • Bug Fixes
    • For library=vertx with useVertx5=true, avoid NPE caused by new PoolOptions(poolConfig) when the JSON is empty/partial (Vert.x 5 doesn’t init defaults in PoolOptions(JsonObject)).
    • Create PoolOptions via new PoolOptions().toJson().mergeIn(poolConfig) and pass to WebClient.create(...).
    • No change for non-useVertx5; regenerated vertx5 samples compile.

Written for commit 4e7eaac. Summary will update on new commits.

Review in cubic

…tx5 (OpenAPITools#24015)

PoolOptions(JsonObject) does not initialize defaults first, unlike its
no-arg constructor and unlike WebClientOptions(JsonObject). The vertx
template's two-arg ApiClient constructor delegates with an empty pool
config, so buildWebClient built PoolOptions(new JsonObject()), leaving
maxLifetimeUnit null (and pool sizes 0). The first API call then threw
a NullPointerException from HttpClientImpl via WebClient.create.

Overlay poolConfig on the serialized no-arg defaults so absent keys keep
their documented values while explicit pool settings still apply.
Regenerated the vertx5 and vertx5-supportVertxFuture samples.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Re-trigger cubic

@wing328

wing328 commented Jun 13, 2026

Copy link
Copy Markdown
Member

cc @RickyRister who is the author of #23829

@wing328

wing328 commented Jun 13, 2026

Copy link
Copy Markdown
Member

thanks for the fix, which looks good to me

cc @bbdouglas (2017/07) @sreeshas (2017/08) @jfiala (2017/08) @lukoyanov (2017/09) @cbornet (2017/09) @jeff9finger (2018/01) @karismann (2019/03) @Zomzog (2019/04) @lwlee2608 (2019/10) @martin-mfg (2023/08)

@wing328 wing328 added this to the 7.24.0 milestone Jun 13, 2026
@wing328 wing328 merged commit 6e30ad0 into OpenAPITools:master Jun 13, 2026
84 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants