Skip to content

Escape JavaDoc default values safely - #24890

Open
Kunal8954 wants to merge 5 commits into
OpenAPITools:masterfrom
Kunal8954:fix/java-javadoc-default-values
Open

Escape JavaDoc default values safely#24890
Kunal8954 wants to merge 5 commits into
OpenAPITools:masterfrom
Kunal8954:fix/java-javadoc-default-values

Conversation

@Kunal8954

@Kunal8954 Kunal8954 commented Sep 7, 2026

Copy link
Copy Markdown

Description

Generated Java clients fail to compile when an OpenAPI parameter default value contains */, such as */*. The value is currently interpolated directly into a JavaDoc comment, prematurely closing the comment block.

Register a Java-specific Mustache lambda and apply it at the JavaDoc interpolation site. The lambda replaces the slash in */ with the HTML entity /, preserving the rendered documentation value without changing the generated Java semantics.

A regression test covers comment terminators and leaves ordinary values unchanged.

Fixes #24852

Validation

  • ./mvnw -B -pl modules/openapi-generator -am -Dtest=org.openapitools.codegen.templating.mustache.EscapeJavaDocLambdaTest -Dsurefire.failIfNoSpecifiedTests=false test
Was generative AI tooling used to co-author this PR?
  • Yes — Copilot

Generated-by: Copilot following the guidelines in the project contribution documentation.


Drafted-by: Copilot (no human review before posting)


Summary by cubic

Fixes generated Java clients failing to compile when a default value contains */ (for example */*), which prematurely closed the JavaDoc comment. Default values in JavaDoc are now escaped to */, preserving rendered text and generated behavior, and string example values like */* are no longer mangled in generated source.

  • Registers an escapeJavaDoc lambda in the codegen lambda map and invokes it as {{#lambda.escapeJavaDoc}} in templates; the bare {{#escapeJavaDoc}} reference never resolves and silently drops default values.
  • Applies the escaping to JavaDoc comments across Java library API templates, leaving regular line comments literal.
  • Escapes string example values for Java string literals without escapeUnsafeCharacters, so wildcard media types stay intact.
  • Adds regression tests and a wildcard-accept-header sample covering comment terminators and ordinary values.

Written for commit f9a9903. Summary will update on new commits.

Review in cubic

Prevent generated Java clients from becoming invalid when OpenAPI default values contain a JavaDoc comment terminator.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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

1 issue found across 5 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/main/resources/Java/api.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/Java/api.mustache:48">
P2: The `*/` escape is only applied to the base `api.mustache` and okhttp-gson; 12 other Java library templates (apache-httpclient, feign, jersey2/jersey3, microprofile, native, rest-assured, resteasy, resttemplate, retrofit2 and its play variants) still interpolate `default to {{.}}` into a JavaDoc comment unescaped. Generators using those libraries will still fail to compile when a default value contains `*/`. Apply `{{#escapeJavaDoc}}{{.}}{{/escapeJavaDoc}}` at every Javadoc default-value site for consistency.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

* {{notes}}
{{#allParams}}
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{#escapeJavaDoc}}{{.}}{{/escapeJavaDoc}}{{/defaultValue}}{{/isContainer}}){{/required}}

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 */ escape is only applied to the base api.mustache and okhttp-gson; 12 other Java library templates (apache-httpclient, feign, jersey2/jersey3, microprofile, native, rest-assured, resteasy, resttemplate, retrofit2 and its play variants) still interpolate default to {{.}} into a JavaDoc comment unescaped. Generators using those libraries will still fail to compile when a default value contains */. Apply {{#escapeJavaDoc}}{{.}}{{/escapeJavaDoc}} at every Javadoc default-value site for consistency.

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/Java/api.mustache, line 48:

<comment>The `*/` escape is only applied to the base `api.mustache` and okhttp-gson; 12 other Java library templates (apache-httpclient, feign, jersey2/jersey3, microprofile, native, rest-assured, resteasy, resttemplate, retrofit2 and its play variants) still interpolate `default to {{.}}` into a JavaDoc comment unescaped. Generators using those libraries will still fail to compile when a default value contains `*/`. Apply `{{#escapeJavaDoc}}{{.}}{{/escapeJavaDoc}}` at every Javadoc default-value site for consistency.</comment>

<file context>
@@ -45,7 +45,7 @@ public class {{classname}} {
    * {{notes}}
    {{#allParams}}
-   * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{.}}{{/defaultValue}}{{/isContainer}}){{/required}}
+   * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{^isContainer}}{{#defaultValue}}, default to {{#escapeJavaDoc}}{{.}}{{/escapeJavaDoc}}{{/defaultValue}}{{/isContainer}}){{/required}}
    {{/allParams}}
    {{#returnType}}
</file context>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in commit 7d8795b. All remaining JavaDoc default-value interpolations across the Java library templates are now wrapped with escapeJavaDoc, including the four okhttp-gson sites.\n\n---\nDrafted-by: Copilot (no human review before posting)

Ensure every Java library template protects generated comments from default values containing a comment terminator.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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

All reported issues were addressed across 16 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread modules/openapi-generator/src/main/resources/Java/libraries/native/api.mustache Outdated
Avoid applying JavaDoc escaping to a regular source comment where it changes the displayed default value unnecessarily.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Kunal8954

Copy link
Copy Markdown
Author

Fixed the latest review issue in commit 00f801c. The native template line comment no longer uses JavaDoc escaping; all actual JavaDoc default-value sites remain protected.\n\n---\nDrafted-by: Copilot (no human review before posting)

@Mattias-Sehlstedt

Copy link
Copy Markdown
Contributor

Do we see any particular benefit with doing this as a mustache-lamba rather than doing it in the generator itself? Given that comments is an attack vector, and the it most likely something that should be heavily sanitized, I believe having it in code might make more sense.

@Kunal8954

Kunal8954 commented Sep 7, 2026

Copy link
Copy Markdown
Author

Thanks for raising this. I considered moving the escaping into the generator, but kept it as a Mustache lambda intentionally because the same defaultValue is also used as generated Java source, where replacing */ with an HTML entity would change the actual value/code. The security-sensitive context here is specifically JavaDoc, so escaping at that output sink keeps the raw value intact everywhere else.

The lambda is registered once in AbstractJavaCodegen, and every Java template JavaDoc default-value interpolation now passes through it. This also keeps the protection explicit at each JavaDoc sink and avoids silently changing non-comment output. The lambda has focused tests for */ and unchanged ordinary values, and the generated Java templates are covered by the existing test suite.

If you prefer a generator-side implementation, I can introduce a separate defaultValueForJavaDoc field rather than mutating defaultValue, but that would require changing every affected template and would still need the same sink-specific distinction.

@Mattias-Sehlstedt

Copy link
Copy Markdown
Contributor

I think the best approach would be some sort of "sanitizedDefaultValue" that was shared for all generators, and then that each language is expected to override it. But as you say it is a very large change given how coupled the current defaultValue is to both the value representation and the documentation representation. So most likely more suitable as something that is handled in a separate issue.

@Kunal8954

Copy link
Copy Markdown
Author

@Mattias-Sehlstedt That makes sense. I agree that introducing a shared sanitized default value would expand the scope significantly given the current coupling. Let's keep this PR focused and handle the broader approach in a separate issue.

The escapeJavaDoc lambda is registered in the codegen lambda map, so
templates must invoke it as {{#lambda.escapeJavaDoc}}. The bare
{{#escapeJavaDoc}} reference never resolves in the render context,
silently dropping every default value from @PARAM Javadoc lines and
breaking the "Samples up-to-date" check.

Add a minimal wildcard-accept-header spec (Accept header defaulting to
*/*) and its generated okhttp-gson sample so the escaping is visible:
the value now renders as *&OpenAPITools#47;* instead of prematurely closing the
Javadoc block.

Also tighten EscapeJavaDocLambdaTest to exercise the lambda through the
lambda map in a nested defaultValue section, the real codegen pattern.

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

1 issue found across 60 files (changes from recent commits).

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="samples/client/wildcard-accept-header/java/.travis.yml">

<violation number="1" location="samples/client/wildcard-accept-header/java/.travis.yml:20">
P2: The script chmods `./gradlew` in before_install but then runs `gradle test` (system Gradle) instead of the wrapper. This bypasses the pinned Gradle 8.14.5 in gradle/wrapper/gradle-wrapper.properties, and the build's spotless 6.11.0 requires Gradle 7+, so an older system Gradle on Travis will fail. Use `./gradlew test`.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

# test using maven
#- mvn test
# test using gradle
- gradle test

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 script chmods ./gradlew in before_install but then runs gradle test (system Gradle) instead of the wrapper. This bypasses the pinned Gradle 8.14.5 in gradle/wrapper/gradle-wrapper.properties, and the build's spotless 6.11.0 requires Gradle 7+, so an older system Gradle on Travis will fail. Use ./gradlew test.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/wildcard-accept-header/java/.travis.yml, line 20:

<comment>The script chmods `./gradlew` in before_install but then runs `gradle test` (system Gradle) instead of the wrapper. This bypasses the pinned Gradle 8.14.5 in gradle/wrapper/gradle-wrapper.properties, and the build's spotless 6.11.0 requires Gradle 7+, so an older system Gradle on Travis will fail. Use `./gradlew test`.</comment>

<file context>
@@ -0,0 +1,22 @@
+  # test using maven
+  #- mvn test
+  # test using gradle
+  - gradle test
+  # test using sbt
+  # - sbt test
</file context>
Suggested change
- gradle test
- ./gradlew test

Comment thread samples/client/wildcard-accept-header/java/README.md Outdated
String example values are escaped for use inside a double-quoted Java string
literal. Avoid mangling '*/' and '/*' (e.g. the '*/*' media type) by not
applying escapeUnsafeCharacters, which is only needed for javadoc comment
contexts. Also remove the unused HashMap import in EscapeJavaDocLambdaTest.
@Kunal8954

Copy link
Copy Markdown
Author

Addressed the latest review items:

#2 — unused HashMap import (EscapeJavaDocLambdaTest.java): removed in commit f9a9903.

#3 — corrupted example "*_/_*" (README.md / DefaultApi.md): root cause was AbstractJavaCodegen.setParameterExampleValue, which escaped the String example via escapeText() and thereby applied escapeUnsafeCharacters() (replacing */*_/, /*/_*). That comment-safety escaping makes sense for javadoc/comment output but corrupts legitimate string literals like the */* media type. String example values are only emitted inside double-quoted Java literals (README docs, @Schema/@ApiModelProperty), never in comments, so they now use quoted-string-only escaping and correctly render "*/*". The sample was regenerated; no other Java sample output changed (verified by rebuilding the petstore okhttp-gson sample clean).

#1.travis.yml uses gradle test instead of ./gradlew test: valid point, but this is pre-existing shared-template behavior, not specific to this PR. The file is generated from modules/openapi-generator/src/main/resources/Java/travis.mustache, which all 60+ committed Java samples use. Changing it would regenerate every Java sample (large unrelated churn). I’d suggest tracking that in a separate issue/PR rather than expanding this javadoc-escaping change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Java generator: parameter defaultValue not escaped in @param Javadoc, breaks compilation for values containing "*/"

2 participants