Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3924,9 +3924,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
if (p.getWriteOnly() != null) {
property.isWriteOnly = p.getWriteOnly();
}
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>

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>

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();
}


Expand Down Expand Up @@ -3978,9 +3976,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
}

// set isNullable using nullable or x-nullable in the schema
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>

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>

Expand Down Expand Up @@ -4083,9 +4079,7 @@ public CodegenProperty fromProperty(String name, Schema p, boolean required, boo
if (original != null) {
p = original;
// evaluate common attributes if defined in the top level
if (ModelUtils.isNullable(p)) {
property.isNullable = true;
} else if (p.getNullable() != null) {
if (p.getNullable() != null) {
property.isNullable = p.getNullable();
} else if (p.getExtensions() != null && p.getExtensions().containsKey(X_NULLABLE)) {
property.isNullable = (Boolean) p.getExtensions().get(X_NULLABLE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -998,8 +998,8 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
}
normalizeProperties(schema, visitedSchemas);
} 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>

Schema additionalProperties = (Schema) result.getAdditionalProperties();
if (getRule(NORMALIZE_31SPEC) && ModelUtils.isNullTypeSchema(openAPI, additionalProperties)) {
// OAS 3.1 allows a map value schema of `type: "null"` (e.g.
// `additionalProperties: { type: "null" }`). There's no OAS 3.0 equivalent type,
Expand All @@ -1008,15 +1008,17 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
// generated as a normal (nullable) object instead.
Schema anyTypeNullable = new Schema();
anyTypeNullable.setNullable(true);
schema.setAdditionalProperties(anyTypeNullable);
result.setAdditionalProperties(anyTypeNullable);
} else {
Schema normalized = normalizeSchema(additionalProperties, visitedSchemas);
if (getRule(NORMALIZE_31SPEC)) {
// capture the normalized value schema (e.g. an OAS 3.1 `type: [array, "null"]`
// value is rewritten to a proper array schema), which would otherwise be lost.
schema.setAdditionalProperties(normalized);
result.setAdditionalProperties(normalized);
}
}

return result;
} else if (schema instanceof BooleanSchema) {
normalizeBooleanSchema(schema, visitedSchemas);
} else if (schema instanceof IntegerSchema) {
Expand Down Expand Up @@ -1105,7 +1107,8 @@ protected Schema normalizeArraySchema(Schema schema) {
}

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>

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>

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<>());
}

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<>());

return processSetMapToNullable(result);
}

protected Schema normalizeSimpleSchema(Schema schema, Set<Schema> visitedSchemas) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2001,9 +2001,7 @@ public static boolean isNullable(Schema schema) {
if (schema.getExtensions() != null && schema.getExtensions().get(X_NULLABLE) != null) {
return Boolean.parseBoolean(schema.getExtensions().get(X_NULLABLE).toString());
}
if (schema.getTypes() != null && schema.getTypes().contains("null")) {
return true;
}

// In OAS 3.1, the recommended way to define a nullable property or object is to use oneOf.
if (isComposedSchema(schema)) {
return isNullableComposedSchema(schema);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public void testNullableAttributeInOas31_triggerWarning() {
/**
* The nullable-deprecated warning must NOT fire for an OAS 3.1 spec using the correct 3.1 null type syntax.
*/
@Test(enabled = false, description = "correct OAS 3.1 null type syntax (type: [string, null]) must NOT trigger the nullable-deprecated warning")
@Test(description = "correct OAS 3.1 null type syntax (type: [string, null]) must NOT trigger the nullable-deprecated warning")
public void testNullTypeInOas31_noWarning() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/null-types-simple.yaml");
Schema<?> stringDataOrNull = (Schema<?>) openAPI.getComponents().getSchemas().get("WithNullableType").getProperties().get("stringDataOrNull");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ paths:
additionalProperties:
format: int32
type: integer
type: object
description: successful operation
security:
- api_key: []
Expand Down
Loading