Skip to content

Add support for interface only with vertx - #24655

Merged
wing328 merged 11 commits into
masterfrom
corbs9-add-support-for-interface-only-with-vertx
Aug 10, 2026
Merged

Add support for interface only with vertx#24655
wing328 merged 11 commits into
masterfrom
corbs9-add-support-for-interface-only-with-vertx

Conversation

@wing328

@wing328 wing328 commented Aug 10, 2026

Copy link
Copy Markdown
Member

based on #24497 with updated workflow

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Adds interfaceOnly support to the java-vertx-web server generator so you can generate only API interfaces and handlers, without server bootstrap files. Also hardens handler logging and multipart handling, adds tests, docs, and a new sample.

  • New Features

    • New interfaceOnly boolean for java-vertx-web; when true, generate only api + Handler (omit apiImpl and HttpServerVerticle) and adjust generated README/pom.
    • New sample at samples/server/petstore/java-vertx-web-interface-only and CI workflow updated to build it.
    • Docs updated to document interfaceOnly in docs/generators/java-vertx-web.md.
  • Bug Fixes

    • Redact sensitive data in handler logs: omit request bodies and hide password values.
    • Safer multipart handling: check empty fileUploads() and return 400 when a required file is missing.
    • Tests added for interfaceOnly template selection, redacted logging, and file upload checks.

Written for commit 759954e. Summary will update on new commits.

Review in cubic

@wing328 wing328 changed the title Corbs9 add support for interface only with vertx Add support for interface only with vertx Aug 10, 2026
@wing328
wing328 marked this pull request as ready for review August 10, 2026 04:03
@wing328 wing328 added this to the 7.25.0 milestone Aug 10, 2026

@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.

8 issues found across 32 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/java/vertx/JavaVertXWebServerCodegenTest.java">

<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/java/vertx/JavaVertXWebServerCodegenTest.java:46">
P3: This test is named "RedactCredentials" but it only asserts that a body param is logged as "(body omitted)" (`assertFileContains(..., "Parameter user is (body omitted)")`). It never exercises the `isPassword` redaction path, and the petstore spec used by `generatePetstoreServer()` contains no password-typed parameter, so the `{{#isPassword}}` branch in apiHandler.mustache is left untested despite being the core security behavior of this PR. Consider renaming the test to reflect what it covers and adding a case that generates a spec with a password parameter to verify `(redacted)` output.</violation>
</file>

<file name="samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/model/User.java">

<violation number="1" location="samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/model/User.java:144">
P2: User.toString() prints the password field in plaintext, which directly contradicts this PR's stated security goal of hiding password values in logs. If a User model is ever logged at debug level (or anywhere via toString()), the password leaks; generate the toString with the password field omitted or masked instead.</violation>
</file>

<file name="samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/api/StoreApi.java">

<violation number="1" location="samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/api/StoreApi.java:8">
P3: This generated interface imports `io.vertx.core.json.JsonObject` and `java.util.List` that are never used by any method. These are dead imports in the sample and reflect the template emitting `JsonObject`/`List` unconditionally even when no operation needs them. Consider making those imports conditional in api.mustache so generated interfaces only contain imports they actually use.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/JavaVertXWebServer/formParams.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/JavaVertXWebServer/formParams.mustache:7">
P1: Required multipart fields are validated only against any upload, so generated handlers accept a request missing one required named file and bind the first uploaded file to every file parameter. Select `FileUpload` by `baseName` and fail when that specific parameter is absent.</violation>

<violation number="2" location="modules/openapi-generator/src/main/resources/JavaVertXWebServer/formParams.mustache:8">
P2: For non-required file form params the new template produces a logically-dead empty `if` body followed by an `else`. The generated sample shows the concrete result in `PetApiHandler.uploadFile()`:

```java
FileUpload _file = null;
if (routingContext.fileUploads().isEmpty()) {
} else {
    _file = routingContext.fileUploads().iterator().next();
}

The {{#required}} gating only injects routingContext.fail(400); return; for required params, so optional file params yield an empty branch. This is awkward, easily-misread generated code. Since the whole point of the guard is to safely detect an empty upload, consider restructuring the template so optional params collapse to a single guard (or a null-safe ternary) without an empty block, e.g. FileUpload _file = routingContext.fileUploads().isEmpty() ? null : routingContext.fileUploads().iterator().next();, and for required params emit the fail/return followed by a direct assignment (no else).

P2: Debug logging exposes the caller's API-key credential when `deletePet` receives `api_key`; redact API-key/security-header parameters in the handler template as well as this generated sample. P2: The new password-redaction path only fires when a parameter is directly flagged as `isPassword`, but for form-encoded submissions those parameters are never individually flagged. In `JavaVertXWebServerCodegen.postProcessOperationsWithModels`, any operation with non-file form params has its form params collapsed into a single dummy `formBody` `JsonObject` parameter, so a form field such as a `password` never reaches the `{{#isPassword}}` branch — it is instead dumped verbatim by the fall-through `logger.debug("Parameter formBody is {}", formBody)`. As a result, the stated security goal of hiding password values in handler logs does not hold for form-encoded credentials, which are logged in full (at debug level) as part of the form payload. Consider omitting form-body contents from debug logging (or redacting known sensitive keys) rather than only suppressing individually-typed password params. P1: The loginUser() handler logs the user's password value in plaintext (`logger.debug("Parameter password is {}", password);`), which writes the credential to the debug log output. This contradicts the PR's stated goal to 'hide password values' in handler logs. The redaction branch in `apiHandler.mustache` only triggers when `isPassword` is true, which is not set for this plain query parameter, so the password is leaked here. Please extend the redaction logic so the actual password value is never logged for this endpoint (e.g. emit a redacted marker for the `password` parameter). ```

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment on lines +7 to +15
{{{dataType}}} {{paramName}} = null;
if (routingContext.fileUploads().isEmpty()) {
{{#required}}
routingContext.fail(400);
return;
{{/required}}
} else {
{{paramName}} = routingContext.fileUploads().iterator().next();
}

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.

P1: Required multipart fields are validated only against any upload, so generated handlers accept a request missing one required named file and bind the first uploaded file to every file parameter. Select FileUpload by baseName and fail when that specific parameter is absent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/JavaVertXWebServer/formParams.mustache, line 7:

<comment>Required multipart fields are validated only against any upload, so generated handlers accept a request missing one required named file and bind the first uploaded file to every file parameter. Select `FileUpload` by `baseName` and fail when that specific parameter is absent.</comment>

<file context>
@@ -4,6 +4,14 @@
 {{/isFile}}
 {{#isFile}}
-        {{{dataType}}} {{paramName}} = routingContext.fileUploads().iterator().next();
+        {{{dataType}}} {{paramName}} = null;
+        if (routingContext.fileUploads().isEmpty()) {
+{{#required}}
</file context>
Suggested change
{{{dataType}}} {{paramName}} = null;
if (routingContext.fileUploads().isEmpty()) {
{{#required}}
routingContext.fail(400);
return;
{{/required}}
} else {
{{paramName}} = routingContext.fileUploads().iterator().next();
}
{{{dataType}}} {{paramName}} = routingContext.fileUploads().stream()
.filter(upload -> "{{baseName}}".equals(upload.name()))
.findFirst()
.orElse(null);
if ({{paramName}} == null) {
{{#required}}
routingContext.fail(400);
return;
{{/required}}
}

String password = requestParameters.queryParameter("password") != null ? requestParameters.queryParameter("password").getString() : null;

logger.debug("Parameter username is {}", username);
logger.debug("Parameter password is {}", password);

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.

P1: The loginUser() handler logs the user's password value in plaintext (logger.debug("Parameter password is {}", password);), which writes the credential to the debug log output. This contradicts the PR's stated goal to 'hide password values' in handler logs. The redaction branch in apiHandler.mustache only triggers when isPassword is true, which is not set for this plain query parameter, so the password is leaked here. Please extend the redaction logic so the actual password value is never logged for this endpoint (e.g. emit a redacted marker for the password parameter).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/api/UserApiHandler.java, line 165:

<comment>The loginUser() handler logs the user's password value in plaintext (`logger.debug("Parameter password is {}", password);`), which writes the credential to the debug log output. This contradicts the PR's stated goal to 'hide password values' in handler logs. The redaction branch in `apiHandler.mustache` only triggers when `isPassword` is true, which is not set for this plain query parameter, so the password is leaked here. Please extend the redaction logic so the actual password value is never logged for this endpoint (e.g. emit a redacted marker for the `password` parameter).</comment>

<file context>
@@ -0,0 +1,224 @@
+        String password = requestParameters.queryParameter("password") != null ? requestParameters.queryParameter("password").getString() : null;
+
+        logger.debug("Parameter username is {}", username);
+        logger.debug("Parameter password is {}", password);
+
+        api.loginUser(username, password)
</file context>
Suggested change
logger.debug("Parameter password is {}", password);
logger.debug("Parameter password is (redacted)");

sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n");
sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n");
sb.append(" email: ").append(toIndentedString(email)).append("\n");
sb.append(" password: ").append(toIndentedString(password)).append("\n");

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.

P2: User.toString() prints the password field in plaintext, which directly contradicts this PR's stated security goal of hiding password values in logs. If a User model is ever logged at debug level (or anywhere via toString()), the password leaks; generate the toString with the password field omitted or masked instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/model/User.java, line 144:

<comment>User.toString() prints the password field in plaintext, which directly contradicts this PR's stated security goal of hiding password values in logs. If a User model is ever logged at debug level (or anywhere via toString()), the password leaks; generate the toString with the password field omitted or masked instead.</comment>

<file context>
@@ -0,0 +1,158 @@
+    sb.append("    firstName: ").append(toIndentedString(firstName)).append("\n");
+    sb.append("    lastName: ").append(toIndentedString(lastName)).append("\n");
+    sb.append("    email: ").append(toIndentedString(email)).append("\n");
+    sb.append("    password: ").append(toIndentedString(password)).append("\n");
+    sb.append("    phone: ").append(toIndentedString(phone)).append("\n");
+    sb.append("    userStatus: ").append(toIndentedString(userStatus)).append("\n");
</file context>
Suggested change
sb.append(" password: ").append(toIndentedString(password)).append("\n");
sb.append(" password: ").append("[REDACTED]").append("\n");

String apiKey = requestParameters.headerParameter("api_key") != null ? requestParameters.headerParameter("api_key").getString() : null;

logger.debug("Parameter petId is {}", petId);
logger.debug("Parameter apiKey is {}", apiKey);

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.

P2: Debug logging exposes the caller's API-key credential when deletePet receives api_key; redact API-key/security-header parameters in the handler template as well as this generated sample.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/api/PetApiHandler.java, line 76:

<comment>Debug logging exposes the caller's API-key credential when `deletePet` receives `api_key`; redact API-key/security-header parameters in the handler template as well as this generated sample.</comment>

<file context>
@@ -0,0 +1,232 @@
+        String apiKey = requestParameters.headerParameter("api_key") != null ? requestParameters.headerParameter("api_key").getString() : null;
+
+        logger.debug("Parameter petId is {}", petId);
+        logger.debug("Parameter apiKey is {}", apiKey);
+
+        api.deletePet(petId, apiKey)
</file context>

{{#allParams}}{{>headerParams}}{{>pathParams}}{{>queryParams}}{{>formParams}}{{>bodyParams}}{{/allParams}}
{{#allParams}}
{{#isPassword}}
logger.debug("Parameter {{paramName}} is (redacted)");

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.

P2: The new password-redaction path only fires when a parameter is directly flagged as isPassword, but for form-encoded submissions those parameters are never individually flagged. In JavaVertXWebServerCodegen.postProcessOperationsWithModels, any operation with non-file form params has its form params collapsed into a single dummy formBody JsonObject parameter, so a form field such as a password never reaches the {{#isPassword}} branch — it is instead dumped verbatim by the fall-through logger.debug("Parameter formBody is {}", formBody). As a result, the stated security goal of hiding password values in handler logs does not hold for form-encoded credentials, which are logged in full (at debug level) as part of the form payload. Consider omitting form-body contents from debug logging (or redacting known sensitive keys) rather than only suppressing individually-typed password params.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/JavaVertXWebServer/apiHandler.mustache, line 56:

<comment>The new password-redaction path only fires when a parameter is directly flagged as `isPassword`, but for form-encoded submissions those parameters are never individually flagged. In `JavaVertXWebServerCodegen.postProcessOperationsWithModels`, any operation with non-file form params has its form params collapsed into a single dummy `formBody` `JsonObject` parameter, so a form field such as a `password` never reaches the `{{#isPassword}}` branch — it is instead dumped verbatim by the fall-through `logger.debug("Parameter formBody is {}", formBody)`. As a result, the stated security goal of hiding password values in handler logs does not hold for form-encoded credentials, which are logged in full (at debug level) as part of the form payload. Consider omitting form-body contents from debug logging (or redacting known sensitive keys) rather than only suppressing individually-typed password params.</comment>

<file context>
@@ -50,7 +52,17 @@ public class {{classname}}Handler {
 {{#allParams}}{{>headerParams}}{{>pathParams}}{{>queryParams}}{{>formParams}}{{>bodyParams}}{{/allParams}}
 {{#allParams}}
+{{#isPassword}}
+        logger.debug("Parameter {{paramName}} is (redacted)");
+{{/isPassword}}
+{{^isPassword}}
</file context>

{{#isFile}}
{{{dataType}}} {{paramName}} = routingContext.fileUploads().iterator().next();
{{{dataType}}} {{paramName}} = null;
if (routingContext.fileUploads().isEmpty()) {

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.

P2: For non-required file form params the new template produces a logically-dead empty if body followed by an else. The generated sample shows the concrete result in PetApiHandler.uploadFile():

FileUpload _file = null;
if (routingContext.fileUploads().isEmpty()) {
} else {
    _file = routingContext.fileUploads().iterator().next();
}

The {{#required}} gating only injects routingContext.fail(400); return; for required params, so optional file params yield an empty branch. This is awkward, easily-misread generated code. Since the whole point of the guard is to safely detect an empty upload, consider restructuring the template so optional params collapse to a single guard (or a null-safe ternary) without an empty block, e.g. FileUpload _file = routingContext.fileUploads().isEmpty() ? null : routingContext.fileUploads().iterator().next();, and for required params emit the fail/return followed by a direct assignment (no else).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/JavaVertXWebServer/formParams.mustache, line 8:

<comment>For non-required file form params the new template produces a logically-dead empty `if` body followed by an `else`. The generated sample shows the concrete result in `PetApiHandler.uploadFile()`:

```java
FileUpload _file = null;
if (routingContext.fileUploads().isEmpty()) {
} else {
    _file = routingContext.fileUploads().iterator().next();
}

The {{#required}} gating only injects routingContext.fail(400); return; for required params, so optional file params yield an empty branch. This is awkward, easily-misread generated code. Since the whole point of the guard is to safely detect an empty upload, consider restructuring the template so optional params collapse to a single guard (or a null-safe ternary) without an empty block, e.g. FileUpload _file = routingContext.fileUploads().isEmpty() ? null : routingContext.fileUploads().iterator().next();, and for required params emit the fail/return followed by a direct assignment (no else).

@@ -4,6 +4,14 @@ {{#isFile}} - {{{dataType}}} {{paramName}} = routingContext.fileUploads().iterator().next(); + {{{dataType}}} {{paramName}} = null; + if (routingContext.fileUploads().isEmpty()) { +{{#required}} + routingContext.fail(400); ```

}

@Test
public void itShouldRedactCredentialsInBodyParams() throws IOException {

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.

P3: This test is named "RedactCredentials" but it only asserts that a body param is logged as "(body omitted)" (assertFileContains(..., "Parameter user is (body omitted)")). It never exercises the isPassword redaction path, and the petstore spec used by generatePetstoreServer() contains no password-typed parameter, so the {{#isPassword}} branch in apiHandler.mustache is left untested despite being the core security behavior of this PR. Consider renaming the test to reflect what it covers and adding a case that generates a spec with a password parameter to verify (redacted) output.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/test/java/org/openapitools/codegen/java/vertx/JavaVertXWebServerCodegenTest.java, line 46:

<comment>This test is named "RedactCredentials" but it only asserts that a body param is logged as "(body omitted)" (`assertFileContains(..., "Parameter user is (body omitted)")`). It never exercises the `isPassword` redaction path, and the petstore spec used by `generatePetstoreServer()` contains no password-typed parameter, so the `{{#isPassword}}` branch in apiHandler.mustache is left untested despite being the core security behavior of this PR. Consider renaming the test to reflect what it covers and adding a case that generates a spec with a password parameter to verify `(redacted)` output.</comment>

<file context>
@@ -0,0 +1,91 @@
+    }
+
+    @Test
+    public void itShouldRedactCredentialsInBodyParams() throws IOException {
+        Map<String, File> files = generatePetstoreServer();
+        String apiHandlerPath = files.keySet().stream()
</file context>

import org.openapitools.vertxweb.server.ApiResponse;

import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;

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.

P3: This generated interface imports io.vertx.core.json.JsonObject and java.util.List that are never used by any method. These are dead imports in the sample and reflect the template emitting JsonObject/List unconditionally even when no operation needs them. Consider making those imports conditional in api.mustache so generated interfaces only contain imports they actually use.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/api/StoreApi.java, line 8:

<comment>This generated interface imports `io.vertx.core.json.JsonObject` and `java.util.List` that are never used by any method. These are dead imports in the sample and reflect the template emitting `JsonObject`/`List` unconditionally even when no operation needs them. Consider making those imports conditional in api.mustache so generated interfaces only contain imports they actually use.</comment>

<file context>
@@ -0,0 +1,18 @@
+import org.openapitools.vertxweb.server.ApiResponse;
+
+import io.vertx.core.Future;
+import io.vertx.core.json.JsonObject;
+
+import java.util.List;
</file context>

@wing328
wing328 merged commit e8d3318 into master Aug 10, 2026
86 of 453 checks passed
@wing328
wing328 deleted the corbs9-add-support-for-interface-only-with-vertx branch August 10, 2026 04:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants