Skip to content

Normalize map schema (3.1 spec) - #24558

Merged
wing328 merged 5 commits into
masterfrom
fix-test-nullable
Aug 1, 2026
Merged

Normalize map schema (3.1 spec)#24558
wing328 merged 5 commits into
masterfrom
fix-test-nullable

Conversation

@wing328

@wing328 wing328 commented Aug 1, 2026

Copy link
Copy Markdown
Member

a follow up PR to #23778

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Normalize OAS 3.1 map schemas and centralize nullable handling via ModelUtils.isNullable to avoid false warnings and ensure correct codegen behavior. Tests and samples updated to verify 3.1 null types and map objects.

  • Bug Fixes
    • In OpenAPINormalizer, run processNormalize31Spec before processSetMapToNullable for map schemas, and return the updated schema so additionalProperties changes persist.
    • In DefaultCodegen, use ModelUtils.isNullable for models, properties, and parameters; for request bodies, parse x-nullable safely and fall back to ModelUtils.isNullable.
    • In ModelUtils.isNullable, remove type: ["...", "null"] inference; rely on composed schemas or x-nullable.
    • Enable the OAS 3.1 test so type: [string, null] does not trigger the nullable-deprecated warning.
    • Update petstore 3.1 sample: add type: object to map response schema to match normalization.

Written for commit 671ad55. Summary will update on new commits.

Review in cubic

@wing328 wing328 added Issue: Bug OpenAPI Normalizer Normalize the spec for easier processing labels Aug 1, 2026
@wing328 wing328 added this to the 7.25.0 milestone Aug 1, 2026
@wing328 wing328 changed the title Normalize 3.1 spec map schema Normalize map schema (3.1 spec) Aug 1, 2026
@wing328
wing328 marked this pull request as ready for review August 1, 2026 13:37

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

2 issues found and verified against the latest diff

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/OpenAPINormalizer.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java:1108">
P3: normalizeMapSchema now returns a possibly-replaced schema from processNormalize31Spec, but the map branch at normalizeSchema() discards that return value (`normalizeMapSchema(schema);`), unlike the array branch which consumes it. If processNormalize31Spec returns a replacement schema (e.g. the empty `new Schema()` it produces for a type-less JsonSchema), that normalized replacement is silently lost and all later map handling keeps using the original object. Consider consuming the returned schema at the call site or documenting that the map case must intentionally keep the original; this makes the behavior consistent with normalizeArraySchema and avoids a latent bug.</violation>
</file>

<file name="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java:3927">
P2: Removing the ModelUtils.isNullable checks from fromProperty means a property declared with OAS 3.1 `type: [string, null]` (or `oneOf` containing `type: 'null'`) will no longer be marked nullable unless `nullable`/`x-nullable` is set on the schema. The `type: [..., null]` inference was also removed from ModelUtils.isNullable, so those properties are now generated as non-nullable whenever the spec is not run through the opt-in `NORMALIZE_31SPEC` normalizer (and that normalizer does not handle composed oneOf-null schemas at all). For users with a 3.1 spec who don't enable the normalizer, this is a behavior regression — nullable fields that were previously generated as nullable will now lose the nullable marker. Consider preserving a fallback that sets isNullable from the schema type union / composed oneOf-null, or gating this change on the normalizer being active, so codegen doesn't silently drop nullability for un-normalized specs.</violation>
</file>

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

Re-trigger cubic

if (ModelUtils.isNullable(p)) {
property.isNullable = true;
} else if (p.getNullable() != null) {
if (p.getNullable() != null) {

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: Removing the ModelUtils.isNullable checks from fromProperty means a property declared with OAS 3.1 type: [string, null] (or oneOf containing type: 'null') will no longer be marked nullable unless nullable/x-nullable is set on the schema. The type: [..., null] inference was also removed from ModelUtils.isNullable, so those properties are now generated as non-nullable whenever the spec is not run through the opt-in NORMALIZE_31SPEC normalizer (and that normalizer does not handle composed oneOf-null schemas at all). For users with a 3.1 spec who don't enable the normalizer, this is a behavior regression — nullable fields that were previously generated as nullable will now lose the nullable marker. Consider preserving a fallback that sets isNullable from the schema type union / composed oneOf-null, or gating this change on the normalizer being active, so codegen doesn't silently drop nullability for un-normalized specs.

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/DefaultCodegen.java, line 3927:

<comment>Removing the ModelUtils.isNullable checks from fromProperty means a property declared with OAS 3.1 `type: [string, null]` (or `oneOf` containing `type: 'null'`) will no longer be marked nullable unless `nullable`/`x-nullable` is set on the schema. The `type: [..., null]` inference was also removed from ModelUtils.isNullable, so those properties are now generated as non-nullable whenever the spec is not run through the opt-in `NORMALIZE_31SPEC` normalizer (and that normalizer does not handle composed oneOf-null schemas at all). For users with a 3.1 spec who don't enable the normalizer, this is a behavior regression — nullable fields that were previously generated as nullable will now lose the nullable marker. Consider preserving a fallback that sets isNullable from the schema type union / composed oneOf-null, or gating this change on the normalizer being active, so codegen doesn't silently drop nullability for un-normalized specs.</comment>

<file context>
@@ -3924,9 +3924,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
-        if (ModelUtils.isNullable(p)) {
-            property.isNullable = true;
-        } else if (p.getNullable() != null) {
+        if (p.getNullable() != null) {
             property.isNullable = p.getNullable();
         }
</file context>


protected Schema normalizeMapSchema(Schema schema) {
return processSetMapToNullable(schema);
Schema result = processNormalize31Spec(schema, new HashSet<>());

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.

P3: normalizeMapSchema now returns a possibly-replaced schema from processNormalize31Spec, but the map branch at normalizeSchema() discards that return value (normalizeMapSchema(schema);), unlike the array branch which consumes it. If processNormalize31Spec returns a replacement schema (e.g. the empty new Schema() it produces for a type-less JsonSchema), that normalized replacement is silently lost and all later map handling keeps using the original object. Consider consuming the returned schema at the call site or documenting that the map case must intentionally keep the original; this makes the behavior consistent with normalizeArraySchema and avoids a latent bug.

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/OpenAPINormalizer.java, line 1108:

<comment>normalizeMapSchema now returns a possibly-replaced schema from processNormalize31Spec, but the map branch at normalizeSchema() discards that return value (`normalizeMapSchema(schema);`), unlike the array branch which consumes it. If processNormalize31Spec returns a replacement schema (e.g. the empty `new Schema()` it produces for a type-less JsonSchema), that normalized replacement is silently lost and all later map handling keeps using the original object. Consider consuming the returned schema at the call site or documenting that the map case must intentionally keep the original; this makes the behavior consistent with normalizeArraySchema and avoids a latent bug.</comment>

<file context>
@@ -1105,7 +1105,8 @@ protected Schema normalizeArraySchema(Schema schema) {
 
     protected Schema normalizeMapSchema(Schema schema) {
-        return processSetMapToNullable(schema);
+        Schema result = processNormalize31Spec(schema, new HashSet<>());
+        return processSetMapToNullable(result);
     }
</file context>

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

3 issues 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/java/org/openapitools/codegen/DefaultCodegen.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java:3927">
P2: OAS 2/3 properties using `x-nullable: true`, and inline OAS 3.1 `oneOf` nullable schemas, are now emitted as non-nullable. This branch bypasses `ModelUtils.isNullable(p)`, which handled both forms, so preserving that helper before the explicit `getNullable()` assignment would retain existing behavior.</violation>

<violation number="2" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java:3979">
P2: A `$ref` to an OAS 3.1 component represented as `oneOf` with a `null` member now loses nullability in generated properties. Keeping the composed-schema check before `getNullable()` would preserve the referenced schema's nullable semantics.</violation>
</file>

<file name="modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java:1108">
P2: normalizeMapSchema now wraps processNormalize31Spec, which can return a brand-new Schema instance (the empty-JsonSchema branch returns `new Schema()`, dropping sibling data). But the map branch of normalizeSchema calls `normalizeMapSchema(schema)` and ignores its return value, so any replacement-schema normalization from the new line is silently lost. For consistency with the array branch (which captures `normalizeArraySchema`'s result and uses it), consider capturing the returned schema in the map branch so the 3.1 normalization actually takes effect.</violation>
</file>

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

Re-trigger cubic

Comment on lines 3979 to 3982
if (referencedSchema.getNullable() != null) {
property.isNullable = referencedSchema.getNullable();
} else if (referencedSchema.getExtensions() != null &&
referencedSchema.getExtensions().containsKey(X_NULLABLE)) {

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: A $ref to an OAS 3.1 component represented as oneOf with a null member now loses nullability in generated properties. Keeping the composed-schema check before getNullable() would preserve the referenced schema's nullable semantics.

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/DefaultCodegen.java, line 3979:

<comment>A `$ref` to an OAS 3.1 component represented as `oneOf` with a `null` member now loses nullability in generated properties. Keeping the composed-schema check before `getNullable()` would preserve the referenced schema's nullable semantics.</comment>

<file context>
@@ -3978,9 +3976,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
-        if (ModelUtils.isNullable(referencedSchema)) {
-            property.isNullable = true;
-        } else if (referencedSchema.getNullable() != null) {
+        if (referencedSchema.getNullable() != null) {
             property.isNullable = referencedSchema.getNullable();
         } else if (referencedSchema.getExtensions() != null &&
</file context>

Comment on lines 3927 to 3929
if (p.getNullable() != null) {
property.isNullable = p.getNullable();
}

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: OAS 2/3 properties using x-nullable: true, and inline OAS 3.1 oneOf nullable schemas, are now emitted as non-nullable. This branch bypasses ModelUtils.isNullable(p), which handled both forms, so preserving that helper before the explicit getNullable() assignment would retain existing behavior.

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/DefaultCodegen.java, line 3927:

<comment>OAS 2/3 properties using `x-nullable: true`, and inline OAS 3.1 `oneOf` nullable schemas, are now emitted as non-nullable. This branch bypasses `ModelUtils.isNullable(p)`, which handled both forms, so preserving that helper before the explicit `getNullable()` assignment would retain existing behavior.</comment>

<file context>
@@ -3924,9 +3924,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
-        if (ModelUtils.isNullable(p)) {
-            property.isNullable = true;
-        } else if (p.getNullable() != null) {
+        if (p.getNullable() != null) {
             property.isNullable = p.getNullable();
         }
</file context>
Suggested change
if (p.getNullable() != null) {
property.isNullable = p.getNullable();
}
if (ModelUtils.isNullable(p)) {
property.isNullable = true;
} else if (p.getNullable() != null) {
property.isNullable = p.getNullable();
}


protected Schema normalizeMapSchema(Schema schema) {
return processSetMapToNullable(schema);
Schema result = processNormalize31Spec(schema, new HashSet<>());

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: normalizeMapSchema now wraps processNormalize31Spec, which can return a brand-new Schema instance (the empty-JsonSchema branch returns new Schema(), dropping sibling data). But the map branch of normalizeSchema calls normalizeMapSchema(schema) and ignores its return value, so any replacement-schema normalization from the new line is silently lost. For consistency with the array branch (which captures normalizeArraySchema's result and uses it), consider capturing the returned schema in the map branch so the 3.1 normalization actually takes effect.

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/OpenAPINormalizer.java, line 1108:

<comment>normalizeMapSchema now wraps processNormalize31Spec, which can return a brand-new Schema instance (the empty-JsonSchema branch returns `new Schema()`, dropping sibling data). But the map branch of normalizeSchema calls `normalizeMapSchema(schema)` and ignores its return value, so any replacement-schema normalization from the new line is silently lost. For consistency with the array branch (which captures `normalizeArraySchema`'s result and uses it), consider capturing the returned schema in the map branch so the 3.1 normalization actually takes effect.</comment>

<file context>
@@ -1105,7 +1105,8 @@ protected Schema normalizeArraySchema(Schema schema) {
 
     protected Schema normalizeMapSchema(Schema schema) {
-        return processSetMapToNullable(schema);
+        Schema result = processNormalize31Spec(schema, new HashSet<>());
+        return processSetMapToNullable(result);
     }
</file context>

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

3 issues 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/java/org/openapitools/codegen/OpenAPINormalizer.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java:1110">
P1: Maps whose parent omits `type` lose their declared value schema when `NORMALIZE_31SPEC` is enabled. `processNormalize31Spec` replaces a typeless `JsonSchema` with a new empty schema, so preserve the original map when normalizing a parent with no explicit type.</violation>
</file>

<file name="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java:3927">
P2: OAS 3.1 properties written as `oneOf: [<type>, {type: null}]` can now be generated as non-null because this fallback only reads the nullable keyword. Preserving the `ModelUtils.isNullable(p)` branch (or guaranteeing this composition is normalized before `fromProperty`) would retain nullability for unsimplified schemas.</violation>

<violation number="2" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java:3979">
P2: A `$ref` to an unsimplified nullable `oneOf` schema is now generated as non-null for the same reason. Retaining the composed-schema check before the explicit nullable value keeps referenced OAS 3.1 null unions correct.</violation>
</file>

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

Re-trigger cubic


protected Schema normalizeMapSchema(Schema schema) {
return processSetMapToNullable(schema);
Schema result = processNormalize31Spec(schema, new HashSet<>());

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.

P1: Maps whose parent omits type lose their declared value schema when NORMALIZE_31SPEC is enabled. processNormalize31Spec replaces a typeless JsonSchema with a new empty schema, so preserve the original map when normalizing a parent with no explicit type.

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/OpenAPINormalizer.java, line 1110:

<comment>Maps whose parent omits `type` lose their declared value schema when `NORMALIZE_31SPEC` is enabled. `processNormalize31Spec` replaces a typeless `JsonSchema` with a new empty schema, so preserve the original map when normalizing a parent with no explicit type.</comment>

<file context>
@@ -1105,7 +1107,8 @@ protected Schema normalizeArraySchema(Schema schema) {
 
     protected Schema normalizeMapSchema(Schema schema) {
-        return processSetMapToNullable(schema);
+        Schema result = processNormalize31Spec(schema, new HashSet<>());
+        return processSetMapToNullable(result);
     }
</file context>
Suggested change
Schema result = processNormalize31Spec(schema, new HashSet<>());
Schema result = schema;
if (schema.getType() != null || schema.getTypes() != null) {
result = processNormalize31Spec(schema, new HashSet<>());
}

if (ModelUtils.isNullable(referencedSchema)) {
property.isNullable = true;
} else if (referencedSchema.getNullable() != null) {
if (referencedSchema.getNullable() != null) {

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: A $ref to an unsimplified nullable oneOf schema is now generated as non-null for the same reason. Retaining the composed-schema check before the explicit nullable value keeps referenced OAS 3.1 null unions correct.

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/DefaultCodegen.java, line 3979:

<comment>A `$ref` to an unsimplified nullable `oneOf` schema is now generated as non-null for the same reason. Retaining the composed-schema check before the explicit nullable value keeps referenced OAS 3.1 null unions correct.</comment>

<file context>
@@ -3978,9 +3976,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
-        if (ModelUtils.isNullable(referencedSchema)) {
-            property.isNullable = true;
-        } else if (referencedSchema.getNullable() != null) {
+        if (referencedSchema.getNullable() != null) {
             property.isNullable = referencedSchema.getNullable();
         } else if (referencedSchema.getExtensions() != null &&
</file context>

if (ModelUtils.isNullable(p)) {
property.isNullable = true;
} else if (p.getNullable() != null) {
if (p.getNullable() != null) {

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: OAS 3.1 properties written as oneOf: [<type>, {type: null}] can now be generated as non-null because this fallback only reads the nullable keyword. Preserving the ModelUtils.isNullable(p) branch (or guaranteeing this composition is normalized before fromProperty) would retain nullability for unsimplified schemas.

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/DefaultCodegen.java, line 3927:

<comment>OAS 3.1 properties written as `oneOf: [<type>, {type: null}]` can now be generated as non-null because this fallback only reads the nullable keyword. Preserving the `ModelUtils.isNullable(p)` branch (or guaranteeing this composition is normalized before `fromProperty`) would retain nullability for unsimplified schemas.</comment>

<file context>
@@ -3924,9 +3924,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
-        if (ModelUtils.isNullable(p)) {
-            property.isNullable = true;
-        } else if (p.getNullable() != null) {
+        if (p.getNullable() != null) {
             property.isNullable = p.getNullable();
         }
</file context>

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

2 issues 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/java/org/openapitools/codegen/OpenAPINormalizer.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java:1110">
P1: Schemas that omit an explicit `type` but define `additionalProperties` lose the map and its value type during 3.1 normalization. `processNormalize31Spec` replaces that `JsonSchema` with an empty `Schema`, so the map's `additionalProperties` is discarded; retaining the original map for type-less schemas (or copying all map metadata when replacing it) preserves the generated map type.</violation>
</file>

<file name="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java:8054">
P2: Request-body parameters can remain nullable despite an explicit `nullable: false` on the top-level `allOf`/`$ref` wrapper because this restoration now only handles true values. Retaining explicit `nullable`/`x-nullable` false values before the normalized check would prevent the generated request parameter from accepting null incorrectly.</violation>
</file>

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

Re-trigger cubic


protected Schema normalizeMapSchema(Schema schema) {
return processSetMapToNullable(schema);
Schema result = processNormalize31Spec(schema, new HashSet<>());

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.

P1: Schemas that omit an explicit type but define additionalProperties lose the map and its value type during 3.1 normalization. processNormalize31Spec replaces that JsonSchema with an empty Schema, so the map's additionalProperties is discarded; retaining the original map for type-less schemas (or copying all map metadata when replacing it) preserves the generated map type.

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/OpenAPINormalizer.java, line 1110:

<comment>Schemas that omit an explicit `type` but define `additionalProperties` lose the map and its value type during 3.1 normalization. `processNormalize31Spec` replaces that `JsonSchema` with an empty `Schema`, so the map's `additionalProperties` is discarded; retaining the original map for type-less schemas (or copying all map metadata when replacing it) preserves the generated map type.</comment>

<file context>
@@ -1105,7 +1107,8 @@ protected Schema normalizeArraySchema(Schema schema) {
 
     protected Schema normalizeMapSchema(Schema schema) {
-        return processSetMapToNullable(schema);
+        Schema result = processNormalize31Spec(schema, new HashSet<>());
+        return processSetMapToNullable(result);
     }
</file context>
Suggested change
Schema result = processNormalize31Spec(schema, new HashSet<>());
Schema result = schema.getType() == null && schema.getTypes() == null
? schema
: processNormalize31Spec(schema, new HashSet<>());

…en/DefaultCodegen.java

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@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.

2 issues 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/java/org/openapitools/codegen/OpenAPINormalizer.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java:1001">
P2: A type-less OAS 3.1 map schema (declared only via `additionalProperties:` with no `type: object`) can lose its value schema during normalization. The map branch now routes through `normalizeMapSchema` -> `processNormalize31Spec`, which replaces a type-less `JsonSchema` with an empty `Schema`, dropping `additionalProperties` and producing a null value schema at `result.getAdditionalProperties()`. The very same hazard is explicitly guarded against a few lines up for the object-with-properties case (the comment notes processNormalize31Spec 'can replace a JsonSchema with properties (but no explicit type) with an empty schema, discarding all properties'), so the map case should receive the same protection.</violation>
</file>

<file name="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java">

<violation number="1" location="modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java:2927">
P2: Removing the `getTypes().contains("null")` check from `ModelUtils.isNullable` silently changes behavior for OAS 3.1 `type: [X, "null"]` unions that have not gone through normalization: they are no longer detected as nullable (only the oneOf composed path still is). This also makes the implementation inconsistent with the method's own Javadoc, which still describes the `null` type as the 3.1 way to mark a schema nullable. The added `ModelUtils.isNullable(...)` usages in DefaultCodegen now depend on this behavior, so callers operating on raw/un-normalized 3.1 schemas may no longer mark such properties/parameters as nullable. Consider updating the Javadoc and confirming that every relevant path is normalized before relying on the reduced detection.</violation>
</file>

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

Re-trigger cubic

} else if (schema.getAdditionalProperties() instanceof Schema) { // map
normalizeMapSchema(schema);
Schema additionalProperties = (Schema) schema.getAdditionalProperties();
Schema result = normalizeMapSchema(schema);

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: A type-less OAS 3.1 map schema (declared only via additionalProperties: with no type: object) can lose its value schema during normalization. The map branch now routes through normalizeMapSchema -> processNormalize31Spec, which replaces a type-less JsonSchema with an empty Schema, dropping additionalProperties and producing a null value schema at result.getAdditionalProperties(). The very same hazard is explicitly guarded against a few lines up for the object-with-properties case (the comment notes processNormalize31Spec 'can replace a JsonSchema with properties (but no explicit type) with an empty schema, discarding all properties'), so the map case should receive the same protection.

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/OpenAPINormalizer.java, line 1001:

<comment>A type-less OAS 3.1 map schema (declared only via `additionalProperties:` with no `type: object`) can lose its value schema during normalization. The map branch now routes through `normalizeMapSchema` -> `processNormalize31Spec`, which replaces a type-less `JsonSchema` with an empty `Schema`, dropping `additionalProperties` and producing a null value schema at `result.getAdditionalProperties()`. The very same hazard is explicitly guarded against a few lines up for the object-with-properties case (the comment notes processNormalize31Spec 'can replace a JsonSchema with properties (but no explicit type) with an empty schema, discarding all properties'), so the map case should receive the same protection.</comment>

<file context>
@@ -998,8 +998,8 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
         } else if (schema.getAdditionalProperties() instanceof Schema) { // map
-            normalizeMapSchema(schema);
-            Schema additionalProperties = (Schema) schema.getAdditionalProperties();
+            Schema result = normalizeMapSchema(schema);
+            Schema additionalProperties = (Schema) result.getAdditionalProperties();
             if (getRule(NORMALIZE_31SPEC) && ModelUtils.isNullTypeSchema(openAPI, additionalProperties)) {
</file context>

}

if (Boolean.TRUE.equals(schema.getNullable())) {
if (ModelUtils.isNullable(schema)) {

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: Removing the getTypes().contains("null") check from ModelUtils.isNullable silently changes behavior for OAS 3.1 type: [X, "null"] unions that have not gone through normalization: they are no longer detected as nullable (only the oneOf composed path still is). This also makes the implementation inconsistent with the method's own Javadoc, which still describes the null type as the 3.1 way to mark a schema nullable. The added ModelUtils.isNullable(...) usages in DefaultCodegen now depend on this behavior, so callers operating on raw/un-normalized 3.1 schemas may no longer mark such properties/parameters as nullable. Consider updating the Javadoc and confirming that every relevant path is normalized before relying on the reduced detection.

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/DefaultCodegen.java, line 2927:

<comment>Removing the `getTypes().contains("null")` check from `ModelUtils.isNullable` silently changes behavior for OAS 3.1 `type: [X, "null"]` unions that have not gone through normalization: they are no longer detected as nullable (only the oneOf composed path still is). This also makes the implementation inconsistent with the method's own Javadoc, which still describes the `null` type as the 3.1 way to mark a schema nullable. The added `ModelUtils.isNullable(...)` usages in DefaultCodegen now depend on this behavior, so callers operating on raw/un-normalized 3.1 schemas may no longer mark such properties/parameters as nullable. Consider updating the Javadoc and confirming that every relevant path is normalized before relying on the reduced detection.</comment>

<file context>
@@ -2924,7 +2924,7 @@ protected void updateModelForComposedSchema(CodegenModel m, Schema schema, Map<S
         }
 
-        if (Boolean.TRUE.equals(schema.getNullable())) {
+        if (ModelUtils.isNullable(schema)) {
             m.isNullable = Boolean.TRUE;
         }
</file context>

@wing328
wing328 merged commit 5731eb3 into master Aug 1, 2026
91 checks passed
@wing328
wing328 deleted the fix-test-nullable branch August 1, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Issue: Bug OpenAPI Normalizer Normalize the spec for easier processing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant