Skip to content

fix: propagate @Schema(description, example) on DTO fields to query parameter descriptions#397

Open
vcfee wants to merge 1 commit into
kbuntrock:devfrom
vcfee:fix/schema-description-on-modelattribute
Open

fix: propagate @Schema(description, example) on DTO fields to query parameter descriptions#397
vcfee wants to merge 1 commit into
kbuntrock:devfrom
vcfee:fix/schema-description-on-modelattribute

Conversation

@vcfee

@vcfee vcfee commented Jun 16, 2026

Copy link
Copy Markdown

Summary

When a DTO is bound as query parameters of a @GetMapping endpoint (via Spring's
implicit @ModelAttribute binding), the plugin only honored the field's Javadoc
for the parameter description. Field-level @Schema(description = "...") /
@Schema(example = "...") annotations were ignored.

The same @Schema(description = "...") is correctly read on the
components.schemas.X.properties.Y.description path, so the behavior was
inconsistent across the two paths.

Before

public class WirelessBzTargetDetailFilterDTO {

    @Schema(description = "Typhoon level (1/2/3)", example = "1")
    private Integer typhoonLevel;

    @Schema(description = "Target day count (1/3/7)", example = "1")
    private Integer targetDayNum;
}

Generated OpenAPI:

- name: typhoonLevel
  in: query
  required: false
  schema:
    type: integer            # <-- no description / example
- name: targetDayNum
  in: query
  required: false
  schema:
    type: integer            # <-- no description / example

After

- name: typhoonLevel
  description: Typhoon level (1/2/3)
  example: '1'
  in: query
  required: false
  schema:
    type: integer
- name: targetDayNum
  description: Target day count (1/3/7)
  example: '1'
  in: query
  required: false
  schema:
    type: integer

Changes

  1. SpringMvcReader.bindDtoToQueryParams — when binding a DTO field to a
    query parameter, now also reads @Schema(description, example) from the
    field and getter. The lookup logic mirrors what is already used in
    components.schemas so the two paths stay consistent.

  2. YamlWriter (line 339-345) — when applying the Javadoc fallback for a
    parameter that came from a DTO field, only override
    description/summary if Javadoc provides a non-empty value. Previously
    an empty Javadoc would erase a description that was correctly set from
    @Schema.

Precedence (unchanged)

When both Javadoc and @Schema exist on the same DTO field, Javadoc still
wins — this preserves the existing behavior for users who rely on Javadoc.

Tests

Added SpringClassAnalyserTest#schema_description_on_dto_query_param and
SchemaDescriptionDtoController / SchemaDescriptionDto. The DTO covers
four scenarios:

field Schema desc Javadoc Schema example expected
fieldFromSchemaOnly yes no yes desc + example from @Schema
fieldFromJavadocOnly no yes no desc from Javadoc, no example
fieldFromBothJavadocWins yes yes yes desc from Javadoc, example from @Schema
fieldWithExampleFromSchemaOnly no no yes no desc, example from @Schema

The new approved YAML is committed alongside the test.
All 147 existing unit tests still pass:

[INFO] Tests run: 147, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS

Real-world driver

Many existing codebases (Spring + Swagger v3) only annotate DTOs with
@Schema, especially when using @Data from Lombok which discourages writing
Javadoc on the field. Today, every such DTO field shows up as an undocumented
query parameter in the generated OpenAPI / in any downstream tool (Apifox /
Swagger UI / Postman).

A quick scan on one of our internal services showed 540 out of 1556 query
parameters (~35%) missing descriptions purely because of this gap, even though
the source DTOs were fully annotated with @Schema.

Notes

  • Followed Coding Guidelines and mvn formatter:format reports no diff.
  • Java 8 source compatibility preserved.
  • No new dependency introduced (swagger-annotations is already a test-scope
    dependency that was used in this PR; main source uses Spring's
    MergedAnnotation mechanism that the plugin already relies on).

…arameter descriptions

When a DTO is bound as query parameters via Spring's implicit @ModelAttribute
binding, the plugin only honored the field's Javadoc and ignored
@Schema(description / example). The same @Schema(description) is correctly
read on the components.schemas path, so the behavior was inconsistent.

* SpringMvcReader.bindDtoToQueryParams now also reads @Schema(description, example)
  from the field and getter (mirrors the components.schemas lookup logic).
* YamlWriter no longer overrides description/summary when the Javadoc fallback
  is empty, so a missing Javadoc cannot erase a description set from @Schema.

Javadoc still wins when both exist (precedence preserved).

Tests: SchemaDescriptionDtoController + SchemaDescriptionDto cover four
scenarios (Schema only / Javadoc only / both / Schema example only). All 147
existing unit tests still pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kbuntrock

Copy link
Copy Markdown
Owner

Hello @vcfee

Thank you very much for this contribution. The description is detailed and clear.

I'm curently abroad away from my computer and I'll be able to look the details of this PR after June 20.

Kind regards,
Kevin

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.

2 participants