swagger-api / swagger-api/swagger-core
Proposal: introduce Schema.NullableMode enum to mirror RequiredMode / AccessMode pattern
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 7.5k
- Forks
- 2.3k
- Avg merge
- 18h 1m
- Merged PRs (30d)
- 10
Description
Background
swagger-core has twice introduced enum-based "Mode" replacements for boolean fields on @Schema whose default false made it impossible to distinguish "user explicitly set false" from "not specified":
- 2018 —
AccessMode { AUTO, READ_ONLY, WRITE_ONLY, READ_WRITE }introduced (#2675, #2677), deprecatingreadOnlyandwriteOnly. - 2022 —
RequiredMode { AUTO, REQUIRED, NOT_REQUIRED }introduced (#4221, #4286, commit b1729fcf1), deprecatingrequired. Commit message rationale: "so we can have a property annotated @NotNull but still have required = false in the openapi spec."
The nullable field has the same shape — boolean nullable() default false — and is now hitting the same problem class as required did pre-2022.
Why now
Auto-detection of nullable has expanded substantially in the last year:
- #5018 (Nov 2025) added native auto-detection of
@Nullableannotations (Jakarta / Spring / JetBrains / JSR-305) with OAS 3.1 type-array translation. - Downstream, springdoc-openapi added auto-detection of Kotlin
T?types in springdoc/springdoc-openapi#3256 (Apr 2026), which has now been reverted in springdoc/springdoc-openapi#3276 due to the same missing-override problem this proposal addresses. - Recent bug iterations on the auto-detection edges: #5077, #5158, upcoming #5124.
Both auto-detection paths feed the same Schema.nullable boolean and have no way to express "user explicitly opts this property out of being marked nullable, regardless of heuristics." Users who try @Schema(nullable = false) find it has no effect (it's the default value and reflection can't distinguish it from absence). See springdoc/springdoc-openapi#3138 and the discussion under springdoc/springdoc-openapi#3256 for concrete user reports.
Proposal
Add to Schema:
/**
* Allows specifying the nullable mode (NullableMode.AUTO, NULLABLE, NOT_NULLABLE).
*
* NullableMode.AUTO: lets the library decide based on heuristics (e.g. @Nullable
* annotations, downstream Kotlin T? detection in springdoc).
* NullableMode.NULLABLE: forces the item to be considered nullable regardless
* of heuristics.
* NullableMode.NOT_NULLABLE: forces the item to be considered not nullable
* regardless of heuristics.
*/
NullableMode nullableMode() default NullableMode.AUTO;
enum NullableMode {
AUTO,
NULLABLE,
NOT_NULLABLE;
}
Deprecate boolean nullable() in favor of nullableMode(), mirroring the deprecation pattern used for required and readOnly/writeOnly.
Precedence
Following the precedent set in #4533 ("give precedence to requiredMode annotation"), nullableMode should take precedence over the legacy nullable boolean and over auto-detection heuristics. Suggested precedence:
nullableMode = NULLABLEorNOT_NULLABLE→ use that- Legacy
nullable = true(deprecated path) → treat asNULLABLE nullableMode = AUTO(default) → run heuristics (@Nullableannotations, downstream Kotlin reflection, etc.)
OAS 3.0 vs 3.1 mapping
Same as the existing handling for nullable: true:
- OAS 3.0: sets
nullable: trueon simple types; for$ref, wraps inallOfwithnullable: truesibling. - OAS 3.1: adds
"null"to thetypearray; for$ref, wraps inoneOfwith{ "type": "null" }.
NOT_NULLABLE simply suppresses any of the above, regardless of what heuristics would otherwise have applied.
Impact on downstream auto-detection
The @Nullable auto-detection added in #5018 should defer to nullableMode != AUTO. Likewise, downstream libraries (springdoc's planned re-introduction of KotlinNullablePropertyCustomizer) can defer to the same field. This gives users a single, uniform escape hatch across all auto-detection sources.
Happy to follow up with a PR
If this direction is acceptable, I'm willing to put up a PR following the pattern of #4221 (RequiredMode introduction) and #4533 (precedence handling). Confirming intent here first since this is an annotation-surface change.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the Schema annotation and the existing RequiredMode and AccessMode implementations referenced in the proposal. Trace how nullable is consumed for OAS 3.0 and 3.1, then compare the precedence handling described in #4533. Done means NullableMode, legacy deprecation, heuristic overrides, and both OAS mappings are covered consistently.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100