Skip to content

Fix #3275: prevent @Nullable $ref field from mutating shared component schema type - #3295

Closed
s-chan-o wants to merge 1 commit into
springdoc:spring-boot-3from
s-chan-o:fix/nullable-ref-schema-mutation
Closed

Fix #3275: prevent @Nullable $ref field from mutating shared component schema type#3295
s-chan-o wants to merge 1 commit into
springdoc:spring-boot-3from
s-chan-o:fix/nullable-ref-schema-mutation

Conversation

@s-chan-o

Copy link
Copy Markdown

Problem

When a record field is annotated with @Nullable and its type resolves to a $ref (i.e. another component schema), swagger-core 2.2.44 mutates the shared Schema instance stored in the components map by setting types = {"null"}. This causes the referenced schema (e.g. Inner) to lose its original type: "object" declaration and appear as type: "null" in the final OpenAPI output.

Reproducer (OAS 3.1):

public record Inner(int lines, long bytes, String bucket, String key) {}
public record Outer(String id, @Nullable Inner result) {}

Before fix – Inner schema in components:

"Inner": { "type": "null", "properties": { ... } }

Fix

In AbstractOpenApiResource.handleComponentSchemaTypes(), call the new helper SpringDocUtils.fixNullMutatedObjectSchema() which restores any component schema whose types was wrongly reduced to {"null"} when it still has properties (i.e. it is clearly an object).

After fix:

"Inner": { "type": "object", "properties": { ... } }

Test

Added regression test SpringDocApp175Test (OAS 3.1, javadoc variant) with:

  • Inner record (the referenced schema)
  • Outer record with @Nullable Inner result
  • NullableRefController exposing GET /outer
  • Expected snapshot results/3.1.0/app175.json asserting Inner has type: "object"

Also bumped test sub-module pom.xml versions from 2.8.17-SNAPSHOT2.8.18-SNAPSHOT to match the root pom after the maven-release-plugin iteration bump.

Fixes #3275

… component schema type

When swagger-core 2.2.44 processes a @nullable field whose type resolves to
a $ref, it mutates the shared Schema instance in the components map by
setting types = {"null"}. This causes the referenced schema (e.g. Inner) to
lose its original type:"object" and appear as type:"null" in the final output.

Fix: in handleComponentSchemaTypes(), call
SpringDocUtils.fixNullMutatedObjectSchema() which restores any component
schema whose type was wrongly reduced to "null"-only when it still has
properties (i.e. it is an object).

Also fix test sub-module pom.xml versions from 2.8.17-SNAPSHOT to
2.8.18-SNAPSHOT to match the root pom after the maven-release-plugin bump.
@Mattias-Sehlstedt

Mattias-Sehlstedt commented May 28, 2026

Copy link
Copy Markdown
Contributor

Note: I am only a contributor to this project, and not associated with it


I strongly disagree with this PR being merged. The issue is entirely tied to swagger-core, and there is a suggested fix there.

Rather than merging temporary logic to this repository and having to manage the lifecycle and removal of it, I would suggest that you instead inject the fix locally on your end while waiting for the upstream adjustment (with a custom Resolver bean for example).

@s-chan-o

Copy link
Copy Markdown
Author

Thank you for the context, @Mattias-Sehlstedt — that's a fair point architecturally.

I checked swagger-api/swagger-core#5124 and it is currently labeled backlog with no assigned reviewer or milestone, so the timeline for an upstream fix is unclear.

In the meantime, users on Spring Boot 4 + swagger-core 2.2.44 are hitting this silently — component schemas resolve to type: null with no obvious error, which is hard to diagnose.

I'll leave the final call to the maintainer: if a temporary guard in handleComponentSchemaTypes is acceptable until the upstream fix lands, I'm happy to iterate on the implementation. If the preference is to wait for swagger-core, I'll close this PR accordingly.

@Mattias-Sehlstedt

Copy link
Copy Markdown
Contributor

The upstream change has been merged so I believe this can be closed.

@bnasslahsen bnasslahsen closed this Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants