[Java][vertx] Apply Vert.x pool defaults in buildWebClient for useVertx5 (#24015)
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
- No in-flight PR —
gh pr list --search "vertx PoolOptions"only shows the merged #23829 that introduced the code; 2. no self-claim comments (0 comments); 3. code-focused (.mustachetemplate + 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=vertxwithuseVertx5=true, avoid NPE caused bynew PoolOptions(poolConfig)when the JSON is empty/partial (Vert.x 5 doesn’t init defaults inPoolOptions(JsonObject)). - Create
PoolOptionsvianew PoolOptions().toJson().mergeIn(poolConfig)and pass toWebClient.create(...). - No change for non-
useVertx5; regeneratedvertx5samples compile.
- For