fix: recognize {type: object, nullable: true} as null-type schema in OpenAPI 3.0.x#23621
Open
ericdriggs wants to merge 1 commit intoOpenAPITools:masterfrom
Open
Conversation
…OpenAPI 3.0.x
The SIMPLIFY_ONEOF_ANYOF normalizer failed to simplify anyOf schemas
where the nullable branch uses {type: "object", nullable: true} instead
of an untyped schema or {type: "null"}. This caused Java (and likely
other) code generators to produce Object or synthetic wrapper classes
instead of the intended typed nullable field.
This pattern is a valid OpenAPI 3.0.x idiom for expressing nullability
alongside a $ref in anyOf/oneOf. It is produced by apispec >= 6.7.1
(the most widely used OpenAPI spec generator for Python/Flask/Marshmallow)
and potentially other spec generators.
Root cause: isNullTypeSchema() did not recognize an empty nullable object
({type: "object", nullable: true} with no properties and no $ref) as a
null-type schema. The fix adds a check for this pattern, scoped to 3.0.x
only via !(schema instanceof JsonSchema), since OpenAPI 3.1 expresses
nullability differently via type arrays.
Test coverage:
- isNullTypeSchemaTest: 3.0 sentinel (true), sentinel with properties (false)
- isNullTypeSchemaTestWith31Spec: 3.1 sentinel correctly returns false
- isNullTypeSchemaInlineAnyOfSentinelTest: inline anyOf sub-schema recognized
- testAnyOfNullableObjectSentinelResolvesToTypedField: end-to-end Java
codegen produces Address field, no synthetic OrderShippingAddress wrapper
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
1 issue found across 6 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/java/org/openapitools/codegen/utils/ModelUtils.java">
<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java:2368">
P2: `isNullTypeSchema` over-broadly treats nullable object schemas as null sentinels, which can remove valid object branches during oneOf/anyOf simplification.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
|
||
| // OpenAPI 3.0.x: empty nullable object is a null-type schema | ||
| if (!(schema instanceof JsonSchema) // 3.0.x only | ||
| && "object".equals(schema.getType()) |
Contributor
There was a problem hiding this comment.
P2: isNullTypeSchema over-broadly treats nullable object schemas as null sentinels, which can remove valid object branches during oneOf/anyOf simplification.
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/java/org/openapitools/codegen/utils/ModelUtils.java, line 2368:
<comment>`isNullTypeSchema` over-broadly treats nullable object schemas as null sentinels, which can remove valid object branches during oneOf/anyOf simplification.</comment>
<file context>
@@ -2363,6 +2363,14 @@ public static boolean isNullTypeSchema(OpenAPI openAPI, Schema schema) {
+ // OpenAPI 3.0.x: empty nullable object is a null-type schema
+ if (!(schema instanceof JsonSchema) // 3.0.x only
+ && "object".equals(schema.getType())
+ && Boolean.TRUE.equals(schema.getNullable())
+ && schema.get$ref() == null) {
</file context>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
isNullTypeSchema()does not recognize{type: "object", nullable: true}(with no properties) as a null-type schema. This causes theSIMPLIFY_ONEOF_ANYOFnormalizer to fail to simplifyanyOfschemas where this pattern is used as the nullable branch, producingObjector synthetic wrapper classes instead of typed nullable fields.This is a valid OpenAPI 3.0.x idiom for expressing nullability alongside a
$refinanyOf/oneOf. It is produced by apispec >= 6.7.1 (PR #953) and potentially other spec generators.Root cause
isNullTypeSchema()checks for null-type schemas by looking for:typefield at alltype: "null"(OpenAPI 3.1)nullenumIt did not check for
{type: "object", nullable: true}with no properties and no$ref— an empty nullable object whose only purpose is to express "this value can be null" in OpenAPI 3.0.x.Fix
Add a check to
isNullTypeSchema()for empty nullable objects, scoped to OpenAPI 3.0.x only via!(schema instanceof JsonSchema). This follows the same 3.0/3.1 discrimination pattern used elsewhere in the same method.Once
isNullTypeSchema()recognizes this pattern, the existingSIMPLIFY_ONEOF_ANYOFlogic insimplifyOneOfAnyOfWithOnlyOneNonNullSubSchemacorrectly identifies theanyOfas containing one real schema and one null sentinel, and simplifies it to a typed nullable field.Before (input spec)
Before (generated Java)
After (generated Java)
Why this pattern is spec-correct
The OpenAPI 3.0.3 spec states that
nullable: trueonly takes effect whentypeis "explicitly defined within the same Schema Object." Since$refresolves to a different Schema Object,nullable: truealongsideallOf: [{$ref: ...}]is technically ineffective. TheanyOfapproach with a nullable empty object is the correct OpenAPI 3.0.x idiom — see analysis by Dan Ott (cited by apispec maintainers).Test coverage
isNullTypeSchemaTesttrue; sentinel with properties →falseisNullTypeSchemaTestWith31Specfalse(not a null sentinel in 3.1)isNullTypeSchemaInlineAnyOfSentinelTesttestAnyOfNullableObjectSentinelResolvesToTypedFieldAddressfield, noOrderShippingAddresswrapperImpact
Affects any OpenAPI 3.0.x spec using
anyOf/oneOfwith{type: "object", nullable: true}as the nullable branch, including all specs generated by apispec >= 6.7.1 (current latest: 6.10.0). All language targets that rely onSIMPLIFY_ONEOF_ANYOFshould benefit.Related issues
isNullTypeSchemaincorrectly equates missingtypewith nullableanyOfsimplificationSIMPLIFY_ONEOF_ANYOFskips valid single-subschema casesallOf+nullabletoanyOfwith nullable sentinelTest plan
ModelUtilsTest#isNullTypeSchemaTestpassesModelUtilsTest#isNullTypeSchemaTestWith31Specpasses (no 3.1 regression)ModelUtilsTest#isNullTypeSchemaInlineAnyOfSentinelTestpassesJavaClientCodegenTest#testAnyOfNullableObjectSentinelResolvesToTypedFieldpasses🤖 Generated with Claude Code
Summary by cubic
Fixes null-type detection for OpenAPI 3.0.x when anyOf/oneOf uses
{type: object, nullable: true}as the null branch, common in specs fromapispec6.7.1+. Generators now produce typed nullable fields instead ofObjector wrapper classes.ModelUtils.isNullTypeSchema()to treat an empty nullable object as a null sentinel in 3.0.x only (!(schema instanceof JsonSchema)).SIMPLIFY_ONEOF_ANYOFto collapse$ref+ null sentinel into a single nullable type; no synthetic wrapper classes.Written for commit f651452. Summary will update on new commits.