From d563d8fb7d351704425d5e0677b9bd445cb917f5 Mon Sep 17 00:00:00 2001 From: Edwin Nyawoli Date: Wed, 22 Jul 2026 13:22:27 +0000 Subject: [PATCH 1/2] Fix Dart native nullable number deserialization (#20238) --- .../serialization/native/native_class.mustache | 4 +++- .../codegen/dart/DartClientCodegenTest.java | 16 ++++++++++++++++ .../dart/dart-native-deserialization-bugs.yaml | 5 +++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache b/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache index 10defcbae9d8..33ae2497f2d1 100644 --- a/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache +++ b/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache @@ -361,7 +361,9 @@ class {{{classname}}} { {{^vendorExtensions.x-is-optional}} {{{name}}}: {{#isNullable}}json[r'{{{baseName}}}'] == null ? {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}} - : {{/isNullable}}{{{datatypeWithEnum}}}.parse('${json[r'{{{baseName}}}']}'), + : {{/isNullable}}{{^isNullable}}{{^required}}{{^defaultValue}}json[r'{{{baseName}}}'] == null + ? {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}} + : {{/defaultValue}}{{/required}}{{/isNullable}}{{{datatypeWithEnum}}}.parse('${json[r'{{{baseName}}}']}'), {{/vendorExtensions.x-is-optional}} {{/isNumber}} {{^isNumber}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/DartClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/DartClientCodegenTest.java index 99211638302c..357f6a9a72f5 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/DartClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/DartClientCodegenTest.java @@ -170,6 +170,22 @@ public void testRequiredNullableFieldsDoNotAssertNonNull() throws Exception { "json[r'nickname'] != null"); } + @Test(description = "Optional numeric fields should guard against null values before parsing") + public void testOptionalNumericFieldsGuardAgainstNull() throws Exception { + List files = generateDartNativeFromSpec( + "src/test/resources/3_0/dart/dart-native-deserialization-bugs.yaml"); + + File modelFile = files.stream() + .filter(f -> f.getName().equals("optional_number_model.dart")) + .findFirst() + .orElseThrow(() -> new AssertionError("optional_number_model.dart not found in generated files")); + + TestUtils.assertFileContains(modelFile.toPath(), + "problem: json[r'problem'] == null"); + TestUtils.assertFileContains(modelFile.toPath(), + ": num.parse('${json[r'problem']}')"); + } + @Test(description = "Nullable nested arrays of complex types should preserve null entries") public void testNullableNestedComplexArraysPreserveNullEntries() throws Exception { List files = generateDartNativeFromSpec( diff --git a/modules/openapi-generator/src/test/resources/3_0/dart/dart-native-deserialization-bugs.yaml b/modules/openapi-generator/src/test/resources/3_0/dart/dart-native-deserialization-bugs.yaml index 981378a5254d..53f2172adee4 100644 --- a/modules/openapi-generator/src/test/resources/3_0/dart/dart-native-deserialization-bugs.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/dart/dart-native-deserialization-bugs.yaml @@ -32,6 +32,11 @@ components: nickname: type: string nullable: true + OptionalNumberModel: + type: object + properties: + problem: + type: number ComplexNestedArrayNullableModel: type: object properties: From 662902c63ac6c453de1540902c75f2dea01a7aa6 Mon Sep 17 00:00:00 2001 From: Edwin Nyawoli Date: Fri, 24 Jul 2026 11:46:58 +0000 Subject: [PATCH 2/2] Update modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache This is actually valid Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --- .../dart2/serialization/native/native_class.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache b/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache index 33ae2497f2d1..ecae5ef6e026 100644 --- a/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache +++ b/modules/openapi-generator/src/main/resources/dart2/serialization/native/native_class.mustache @@ -361,9 +361,9 @@ class {{{classname}}} { {{^vendorExtensions.x-is-optional}} {{{name}}}: {{#isNullable}}json[r'{{{baseName}}}'] == null ? {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}} - : {{/isNullable}}{{^isNullable}}{{^required}}{{^defaultValue}}json[r'{{{baseName}}}'] == null + : {{/isNullable}}{{^isNullable}}{{^required}}json[r'{{{baseName}}}'] == null ? {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}} - : {{/defaultValue}}{{/required}}{{/isNullable}}{{{datatypeWithEnum}}}.parse('${json[r'{{{baseName}}}']}'), + : {{/required}}{{/isNullable}}{{{datatypeWithEnum}}}.parse('${json[r'{{{baseName}}}']}'), {{/vendorExtensions.x-is-optional}} {{/isNumber}} {{^isNumber}}