Skip to content

[dart-dio] fix the issue of multi layer issues with dart-dio code generation - #23717

Open
fstotz wants to merge 43 commits into
OpenAPITools:masterfrom
fstotz:feature/dart_dio_fix_one_of_multi_layers
Open

[dart-dio] fix the issue of multi layer issues with dart-dio code generation#23717
fstotz wants to merge 43 commits into
OpenAPITools:masterfrom
fstotz:feature/dart_dio_fix_one_of_multi_layers

Conversation

@fstotz

@fstotz fstotz commented May 7, 2026

Copy link
Copy Markdown

This fixes the issues with multi layer class using oneOf in dart-dio
fixes #15467

The PR includes test for dart-dio, which are using the example from the ticket

@jaumard (2018/09) @josh-burton (2019/12) @amondnet (2019/12) @sbu-WBT (2020/12) @kuhnroyal (2020/12) @agilob (2020/12) @ahmednfwela (2021/08)

PR checklist

  • Read the contribution guidelines.
  • Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community.
  • 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.
  • File the PR against the correct branch: master (upcoming 7.x.0 minor release - breaking changes with fallbacks), 8.0.x (breaking changes without fallbacks)
  • If your PR solves a reported issue, reference it using GitHub's linking syntax (e.g., having "fixes #123" present in the PR description)
  • 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

Fixes multi-level oneOf/anyOf discriminator dispatch and unifies path/query/form encoding in dart-dio, preventing wrong model selection and unsafe/incorrect serialization (enums, nulls, collections, and reserved path characters). Old behavior: parent-first discriminator checks and ad‑hoc encoders that emitted Dart enum identifiers, kept nulls, mishandled containers, and left path values unencoded. New behavior: inheritance-aware discriminator mapping and dedicated encoders that produce wire values, drop nulls safely, handle collections, and URI-encode path segments.

  • Discriminators: honor only schema-declared mappings for local discriminators; for inherited discriminators include true allOf descendants plus the schema’s oneOf/anyOf; order checks by inheritance depth; expose x-discriminator-mapped-models-nonself, x-has-discriminator-self-mapping, and x-discriminator-self-mapping-name (fixes [BUG] [dart-dio] Discriminator with multi-layered subclasses causes the subclasses to have error in discriminators #15467, [dart-dio] fix the issue of multi layer issues with dart-dio code generation #23717).
  • Path params: generate encodePathParameter(...) and use it in APIs; now URI-encodes reserved chars; built_value uses serializers to emit enum wire names and supports lists/maps with ListFormat; nullable path values become empty strings; conditionally applies collectionFormat to avoid map-parameter compile errors; add missing dio import for json_serializable; enums in collections use wire values.
  • Query/form params: unify to encodeParameter(...); call removeNullParametersExcept(...) to drop nulls while preserving required-nullable entries; non-multipart forms use the form encoder with asString: true; optional nullable form fields are guarded so nulls are omitted instead of sent as empty strings; ship api_util.dart for both built_value and json_serializable.
  • Serializers: generate ListBuilder<T?>/SetBuilder<T?> when item types are nullable to align with FullType.nullable(...).
  • Tests/samples: add coverage for local vs inherited discriminators and enum path param wire-name encoding (incl. collections); regenerate dart-dio samples accordingly.

Written for commit 6899118. Summary will update on new commits.

Review in cubic

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

No issues found across 13 files

}
}

private int getSchemaInheritanceDepth(String schemaName, String ancestorSchemaName, Set<String> visited) {

@wing328 wing328 May 21, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: what about adding docstrings explaining what this function and other newly added functions do?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wing328 I did add some comments and also fixed another issue in regards to a possible null cast
Could you take another look?

@wing328 wing328 modified the milestones: 7.23.0, 7.24.0 Jun 8, 2026
@fstotz
fstotz requested a review from wing328 June 8, 2026 07:56
@wing328 wing328 modified the milestones: 7.24.0, 7.25.0 Jul 20, 2026

@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 22 files (changes from recent commits).

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="samples/client/petstore/csharp/generichost/latest/AnnotatedEnum/src/Org.OpenAPITools/Model/StringPatternsWithOneOf.cs">

<violation number="1" location="samples/client/petstore/csharp/generichost/latest/AnnotatedEnum/src/Org.OpenAPITools/Model/StringPatternsWithOneOf.cs:129">
P2: The deserializer always throws. `varString` is initialized to `default` and never assigned anywhere in the read loop (the property-name `switch` only has `default: break;`), so `if (varString != null)` is always false and every valid JSON object throws `JsonException`. The `String` property can never be populated, breaking the model for any real request/response. The generator logic that populates the local from the matched property is missing.</violation>

<violation number="2" location="samples/client/petstore/csharp/generichost/latest/AnnotatedEnum/src/Org.OpenAPITools/Model/StringPatternsWithOneOf.cs:157">
P2: Serialization drops the value. `Write` calls `WriteProperties`, whose body is empty and never emits the `String` property, so the generated output is always an empty object `{}`. Combined with the always-throwing `Read`, the model cannot round-trip its data in either direction.</violation>
</file>

<file name="samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake/lib/src/api_util.dart">

<violation number="1" location="samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake/lib/src/api_util.dart:41">
P2: When a nullable non-multipart form parameter is null, generated code now passes a null body value through `encodeQueryParameter`. Route form fields through `encodeFormParameter` or remove null form entries before Dio encodes the request.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

/// <param name="stringPatternsWithOneOf"></param>
/// <param name="jsonSerializerOptions"></param>
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, StringPatternsWithOneOf stringPatternsWithOneOf, JsonSerializerOptions jsonSerializerOptions)

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: Serialization drops the value. Write calls WriteProperties, whose body is empty and never emits the String property, so the generated output is always an empty object {}. Combined with the always-throwing Read, the model cannot round-trip its data in either direction.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/csharp/generichost/latest/AnnotatedEnum/src/Org.OpenAPITools/Model/StringPatternsWithOneOf.cs, line 157:

<comment>Serialization drops the value. `Write` calls `WriteProperties`, whose body is empty and never emits the `String` property, so the generated output is always an empty object `{}`. Combined with the always-throwing `Read`, the model cannot round-trip its data in either direction.</comment>

<file context>
@@ -0,0 +1,162 @@
+        /// <param name="stringPatternsWithOneOf"></param>
+        /// <param name="jsonSerializerOptions"></param>
+        /// <exception cref="NotImplementedException"></exception>
+        public void WriteProperties(Utf8JsonWriter writer, StringPatternsWithOneOf stringPatternsWithOneOf, JsonSerializerOptions jsonSerializerOptions)
+        {
+
</file context>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this issue is not related to this PR
It only appeared after creating the examples

}
}

if (varString != 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: The deserializer always throws. varString is initialized to default and never assigned anywhere in the read loop (the property-name switch only has default: break;), so if (varString != null) is always false and every valid JSON object throws JsonException. The String property can never be populated, breaking the model for any real request/response. The generator logic that populates the local from the matched property is missing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/client/petstore/csharp/generichost/latest/AnnotatedEnum/src/Org.OpenAPITools/Model/StringPatternsWithOneOf.cs, line 129:

<comment>The deserializer always throws. `varString` is initialized to `default` and never assigned anywhere in the read loop (the property-name `switch` only has `default: break;`), so `if (varString != null)` is always false and every valid JSON object throws `JsonException`. The `String` property can never be populated, breaking the model for any real request/response. The generator logic that populates the local from the matched property is missing.</comment>

<file context>
@@ -0,0 +1,162 @@
+                }
+            }
+
+            if (varString != null)
+                return new StringPatternsWithOneOf(varString);
+
</file context>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this issue is not related to this PR
It only appeared after creating the examples

) {
if (value == null) {
return '';
return 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: When a nullable non-multipart form parameter is null, generated code now passes a null body value through encodeQueryParameter. Route form fields through encodeFormParameter or remove null form entries before Dio encodes the request.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake/lib/src/api_util.dart, line 41:

<comment>When a nullable non-multipart form parameter is null, generated code now passes a null body value through `encodeQueryParameter`. Route form fields through `encodeFormParameter` or remove null form entries before Dio encodes the request.</comment>

<file context>
@@ -38,7 +38,7 @@ dynamic encodeQueryParameter(
 ) {
   if (value == null) {
-    return '';
+    return null;
   }
   if (value is String || value is num || value is bool) {
</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 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/resources/dart/libraries/dio/api.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/dart/libraries/dio/api.mustache:90">
P1: For the json_serializable serialization library, this call produces an undefined function. removeNullQueryParameters only exists in built_value's api_util.dart, which is neither generated nor imported under JSON serializable (DartDioClientCodegen.java only adds api_util.dart for built_value). Any operation with a query param generated with --serialization-library json_serializable will fail to compile. Guard the call so it is only emitted for built_value (e.g. wrap in {{#useBuiltValue}}...) or provide the function for json_serializable too.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api_util.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api_util.mustache:82">
P1: removeNullQueryParameters is added only to the built_value api_util, but the shared api.mustache calls it for every dio serialization flavor. The native/json_serializable flavor doesn't generate an api_util, so its generated API code calls an undefined removeNullQueryParameters and fails to compile. Define/emit removeNullQueryParameters for the non-built_value serialization library as well, or gate the call.</violation>
</file>

<file name="samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/HttpServerVerticle.java">

<violation number="1" location="samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/HttpServerVerticle.java:23">
P2: When this verticle runs outside the Maven project root, `RouterBuilder.create` cannot find the OpenAPI document because `specFile` points into the source tree. Load `openapi.yaml` from the classpath using a Vert.x-supported resource/content overload instead of a source-relative filesystem path.</violation>
</file>

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

Re-trigger cubic

{{/queryParams}}
};{{/hasQueryParams}}{{#hasBodyOrFormParams}}
};
removeNullQueryParameters(_queryParameters);{{/hasQueryParams}}{{#hasBodyOrFormParams}}

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: For the json_serializable serialization library, this call produces an undefined function. removeNullQueryParameters only exists in built_value's api_util.dart, which is neither generated nor imported under JSON serializable (DartDioClientCodegen.java only adds api_util.dart for built_value). Any operation with a query param generated with --serialization-library json_serializable will fail to compile. Guard the call so it is only emitted for built_value (e.g. wrap in {{#useBuiltValue}}...) or provide the function for json_serializable too.

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/resources/dart/libraries/dio/api.mustache, line 90:

<comment>For the json_serializable serialization library, this call produces an undefined function. removeNullQueryParameters only exists in built_value's api_util.dart, which is neither generated nor imported under JSON serializable (DartDioClientCodegen.java only adds api_util.dart for built_value). Any operation with a query param generated with --serialization-library json_serializable will fail to compile. Guard the call so it is only emitted for built_value (e.g. wrap in {{#useBuiltValue}}...) or provide the function for json_serializable too.</comment>

<file context>
@@ -86,7 +86,8 @@ class {{classname}} {
       {{/queryParams}}
-    };{{/hasQueryParams}}{{#hasBodyOrFormParams}}
+    };
+    removeNullQueryParameters(_queryParameters);{{/hasQueryParams}}{{#hasBodyOrFormParams}}
 
     dynamic _bodyData;
</file context>

throw ArgumentError('Invalid value passed to encodeCollectionQueryParameter');
}

void removeNullQueryParameters(Map<String, dynamic> queryParameters) {

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: removeNullQueryParameters is added only to the built_value api_util, but the shared api.mustache calls it for every dio serialization flavor. The native/json_serializable flavor doesn't generate an api_util, so its generated API code calls an undefined removeNullQueryParameters and fails to compile. Define/emit removeNullQueryParameters for the non-built_value serialization library as well, or gate the call.

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/resources/dart/libraries/dio/serialization/built_value/api_util.mustache, line 82:

<comment>removeNullQueryParameters is added only to the built_value api_util, but the shared api.mustache calls it for every dio serialization flavor. The native/json_serializable flavor doesn't generate an api_util, so its generated API code calls an undefined removeNullQueryParameters and fails to compile. Define/emit removeNullQueryParameters for the non-built_value serialization library as well, or gate the call.</comment>

<file context>
@@ -49,26 +49,37 @@ dynamic encodeQueryParameter(
   throw ArgumentError('Invalid value passed to encodeCollectionQueryParameter');
 }
+
+void removeNullQueryParameters(Map<String, dynamic> queryParameters) {
+  queryParameters.removeWhere((_, value) => value == null);
+}
</file context>

public class HttpServerVerticle extends AbstractVerticle {

private static final Logger logger = LoggerFactory.getLogger(HttpServerVerticle.class);
private static final String specFile = "src/main/resources/openapi.yaml";

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: When this verticle runs outside the Maven project root, RouterBuilder.create cannot find the OpenAPI document because specFile points into the source tree. Load openapi.yaml from the classpath using a Vert.x-supported resource/content overload instead of a source-relative filesystem path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/java-vertx-web-interface-only/src/main/java/org/openapitools/vertxweb/server/HttpServerVerticle.java, line 23:

<comment>When this verticle runs outside the Maven project root, `RouterBuilder.create` cannot find the OpenAPI document because `specFile` points into the source tree. Load `openapi.yaml` from the classpath using a Vert.x-supported resource/content overload instead of a source-relative filesystem path.</comment>

<file context>
@@ -0,0 +1,63 @@
+public class HttpServerVerticle extends AbstractVerticle {
+
+    private static final Logger logger = LoggerFactory.getLogger(HttpServerVerticle.class);
+    private static final String specFile = "src/main/resources/openapi.yaml";
+
+    
</file context>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this issue is not related to this PR
It only appeared after creating the examples

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

All reported issues were addressed across 25 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

fstotz and others added 2 commits August 24, 2026 11:11
Asserts that enum-typed path parameters use encodeQueryParameter
(serializer wire name) rather than .toString() (Dart identifier name).

Example: unknownDefaultOpenApi.toString() = "unknownDefaultOpenApi"
         serializer.serialize(...)         = "unknown_default_open_api"

Co-authored-by: Copilot <223556219+Copilot@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.

All reported issues were addressed across 8 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

@fstotz

fstotz commented Aug 24, 2026

Copy link
Copy Markdown
Author

@wing328 could you please review this again and allow trigger of the workflows again?

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

All reported issues were addressed across 14 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

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

All reported issues were addressed across 8 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread samples/openapi3/client/petstore/dart-dio/oneof/lib/src/api_util.dart Outdated
fstotz and others added 2 commits August 24, 2026 15:47
…/lib/src/api_util.dart

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.

All reported issues were addressed across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

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

8 issues found across 19 files (changes from recent commits).

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="samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake/lib/src/api/fake_api.dart">

<violation number="1" location="samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake/lib/src/api/fake_api.dart:1267">
P2: When `binary` is provided, this sends the raw `Uint8List` into the URL-encoded form map. `encodeParameter` returns typed bytes unchanged even with `asString: true`, so Dio cannot encode the binary field using its intended serialized representation; serialize or encode the bytes before adding this form parameter.</violation>
</file>

<file name="samples/openapi3/client/petstore/dart-dio/anyof/lib/src/api_util.dart">

<violation number="1" location="samples/openapi3/client/petstore/dart-dio/anyof/lib/src/api_util.dart:45">
P2: When a non-multipart form field is a serialized model, `encodeParameter(..., asString: true)` returns its map unchanged. Dio then submits nested form fields instead of the model’s JSON string; restore JSON encoding for serialized non-container values while retaining the existing collection/map handling.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api/serialize.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api/serialize.mustache:5">
P1: When a nullable multipart field is null, this call now passes `asString: false`, so `encodeParameter` returns `null` instead of the multipart encoder’s empty string; built_value model fields are also passed to `FormData` as serialized maps instead of JSON strings. Preserve a multipart-specific encoding path that maps null to `''` and JSON-encodes serialized model values while retaining collection handling.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api/path_param.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api/path_param.mustache:1">
P2: When a built_value array or set is used as a path parameter, this call reaches `encodePathParameter`, which does not recognize the iterable returned by built_value collection serialization and sends its debug string in the URL. Make the path encoder handle `Iterable` (while preserving map handling) before routing collection path parameters through it.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api/query_param.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api/query_param.mustache:1">
P2: When a query array or set has nullable items, this call uses non-nullable `T` and `FullType`, so `encodeParameter` does not recognize the `BuiltList<T?>`/`BuiltSet<T?>` as its collection type and returns the raw serialized iterable instead of a `ListParam`. Preserve item nullability in the generic and `FullType`, or make the helper’s collection detection independent of `T`.</violation>
</file>

<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/dio/DartDioClientCodegenTest.java">

<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/dio/DartDioClientCodegenTest.java:453">
P3: The javadoc for testEnumPathParamsUseSerializerNotToString now names {@code encodeParameter}, but the test asserts {@code encodePathParameter(...)} and that is the helper this regression covers. Update the javadoc to {@code encodePathParameter} so it matches the code and does not mislead.</violation>
</file>

<file name="samples/openapi3/client/petstore/dart-dio/oneof_primitive/lib/src/api_util.dart">

<violation number="1" location="samples/openapi3/client/petstore/dart-dio/oneof_primitive/lib/src/api_util.dart:45">
P2: When a non-multipart form field is a built_value model, `asString: true` still sends the serialized map instead of a form string, producing nested map fields rather than the model JSON. JSON-encode serialized model values when `asString` is requested, while preserving the collection behavior required for multipart fields.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api/form_param.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/built_value/api/form_param.mustache:1">
P2: When a form field is a non-container model/object, this call leaves the serialized `Map` in the form body instead of encoding it as the JSON string required by form serialization. Make `encodeParameter` honor `asString` for serialized objects, or retain a dedicated form encoder for this branch.</violation>
</file>

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

_bodyData = FormData.fromMap(<String, dynamic>{
{{#formParams}}
{{^required}}{{^isNullable}}if ({{{paramName}}} != null) {{/isNullable}}{{/required}}r'{{{baseName}}}': {{#isFile}}{{{paramName}}}{{#isArray}}.toList(){{/isArray}}{{/isFile}}{{^isFile}}encodeFormParameter(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{baseType}}}{{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]{{/isContainer}})){{/isFile}},
{{^required}}{{^isNullable}}if ({{{paramName}}} != null) {{/isNullable}}{{/required}}r'{{{baseName}}}': {{#isFile}}{{{paramName}}}{{#isArray}}.toList(){{/isArray}}{{/isFile}}{{^isFile}}encodeParameter(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{baseType}}}{{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]{{/isContainer}}), forMultipart: true){{/isFile}},

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: When a nullable multipart field is null, this call now passes asString: false, so encodeParameter returns null instead of the multipart encoder’s empty string; built_value model fields are also passed to FormData as serialized maps instead of JSON strings. Preserve a multipart-specific encoding path that maps null to '' and JSON-encodes serialized model values while retaining collection handling.

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/resources/dart/libraries/dio/serialization/built_value/api/serialize.mustache, line 5:

<comment>When a nullable multipart field is null, this call now passes `asString: false`, so `encodeParameter` returns `null` instead of the multipart encoder’s empty string; built_value model fields are also passed to `FormData` as serialized maps instead of JSON strings. Preserve a multipart-specific encoding path that maps null to `''` and JSON-encodes serialized model values while retaining collection handling.</comment>

<file context>
@@ -2,7 +2,7 @@
       _bodyData = FormData.fromMap(<String, dynamic>{
         {{#formParams}}
-        {{^required}}{{^isNullable}}if ({{{paramName}}} != null) {{/isNullable}}{{/required}}r'{{{baseName}}}': {{#isFile}}{{{paramName}}}{{#isArray}}.toList(){{/isArray}}{{/isFile}}{{^isFile}}encodeFormParameter(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{baseType}}}{{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]{{/isContainer}})){{/isFile}},
+        {{^required}}{{^isNullable}}if ({{{paramName}}} != null) {{/isNullable}}{{/required}}r'{{{baseName}}}': {{#isFile}}{{{paramName}}}{{#isArray}}.toList(){{/isArray}}{{/isFile}}{{^isFile}}encodeParameter(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{baseType}}}{{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]{{/isContainer}}), forMultipart: true){{/isFile}},
         {{/formParams}}
       });
</file context>

return _joinCollectionValues(values, format);
}
if (forMultipart) {
return serialized;

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: When a non-multipart form field is a serialized model, encodeParameter(..., asString: true) returns its map unchanged. Dio then submits nested form fields instead of the model’s JSON string; restore JSON encoding for serialized non-container values while retaining the existing collection/map handling.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/dart-dio/anyof/lib/src/api_util.dart, line 45:

<comment>When a non-multipart form field is a serialized model, `encodeParameter(..., asString: true)` returns its map unchanged. Dio then submits nested form fields instead of the model’s JSON string; restore JSON encoding for serialized non-container values while retaining the existing collection/map handling.</comment>

<file context>
@@ -2,104 +2,109 @@
+      return _joinCollectionValues(values, format);
+    }
+    if (forMultipart) {
+      return serialized;
+    }
+    return ListParam(values, format);
</file context>

@@ -0,0 +1 @@
{{#isContainer}}{{#isMap}}encodePathParameter(_serializers, {{{paramName}}}, const FullType(BuiltMap, [FullType(String), FullType({{{baseType}}})])){{/isMap}}{{^isMap}}{{#isNullable}}{{{paramName}}} == null ? '' : {{/isNullable}}encodePathParameter(_serializers, {{{paramName}}}, const FullType(Built{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [FullType({{{baseType}}})]){{#collectionFormat}}, format: ListFormat.{{collectionFormat}}{{/collectionFormat}}){{/isMap}}{{/isContainer}}{{^isContainer}}encodePathParameter(_serializers, {{{paramName}}}, const FullType({{{dataType}}})){{/isContainer}} No newline at end of file

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: When a built_value array or set is used as a path parameter, this call reaches encodePathParameter, which does not recognize the iterable returned by built_value collection serialization and sends its debug string in the URL. Make the path encoder handle Iterable (while preserving map handling) before routing collection path parameters through it.

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/resources/dart/libraries/dio/serialization/built_value/api/path_param.mustache, line 1:

<comment>When a built_value array or set is used as a path parameter, this call reaches `encodePathParameter`, which does not recognize the iterable returned by built_value collection serialization and sends its debug string in the URL. Make the path encoder handle `Iterable` (while preserving map handling) before routing collection path parameters through it.</comment>

<file context>
@@ -1 +1 @@
-{{#isContainer}}{{#isMap}}_encodeMapPathParameter(_serializers, {{{paramName}}}, const FullType(BuiltMap, [FullType(String), FullType({{{baseType}}})])){{/isMap}}{{^isMap}}{{#isNullable}}{{{paramName}}} == null ? '' : {{/isNullable}}encodeCollectionParameter<{{{baseType}}}>(_serializers, {{{paramName}}}, const FullType(Built{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [FullType({{{baseType}}})]), asString: true{{#collectionFormat}}, format: ListFormat.{{collectionFormat}}{{/collectionFormat}}){{/isMap}}{{/isContainer}}{{^isContainer}}{{#isNullable}}encodeQueryParameter(_serializers, {{{paramName}}}, const FullType({{{dataType}}}))?.toString() ?? ''{{/isNullable}}{{^isNullable}}encodeQueryParameter(_serializers, {{{paramName}}}, const FullType({{{dataType}}})).toString(){{/isNullable}}{{/isContainer}}
+{{#isContainer}}{{#isMap}}encodePathParameter(_serializers, {{{paramName}}}, const FullType(BuiltMap, [FullType(String), FullType({{{baseType}}})])){{/isMap}}{{^isMap}}{{#isNullable}}{{{paramName}}} == null ? '' : {{/isNullable}}encodePathParameter(_serializers, {{{paramName}}}, const FullType(Built{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [FullType({{{baseType}}})]){{#collectionFormat}}, format: ListFormat.{{collectionFormat}}{{/collectionFormat}}){{/isMap}}{{/isContainer}}{{^isContainer}}encodePathParameter(_serializers, {{{paramName}}}, const FullType({{{dataType}}})){{/isContainer}}
\ No newline at end of file
</file context>

@@ -1 +1 @@
{{#isContainer}}{{#isMap}}encodeQueryParameter{{/isMap}}{{^isMap}}encodeCollectionQueryParameter<{{{baseType}}}>{{/isMap}}{{/isContainer}}{{^isContainer}}encodeQueryParameter{{/isContainer}}(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{dataType}}}){{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]), {{#collectionFormat}}format: ListFormat.{{collectionFormat}},{{/collectionFormat}}{{/isContainer}}) No newline at end of file
{{#isContainer}}{{#isMap}}encodeParameter(_serializers, {{{paramName}}}, const FullType(BuiltMap, [FullType(String), FullType({{{baseType}}})])){{/isMap}}{{^isMap}}encodeParameter<{{{baseType}}}>(_serializers, {{{paramName}}}, const FullType(Built{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [FullType({{{baseType}}})]){{#collectionFormat}}, format: ListFormat.{{collectionFormat}}{{/collectionFormat}}){{/isMap}}{{/isContainer}}{{^isContainer}}encodeParameter(_serializers, {{{paramName}}}, const FullType({{{dataType}}})){{/isContainer}} No newline at end of file

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: When a query array or set has nullable items, this call uses non-nullable T and FullType, so encodeParameter does not recognize the BuiltList<T?>/BuiltSet<T?> as its collection type and returns the raw serialized iterable instead of a ListParam. Preserve item nullability in the generic and FullType, or make the helper’s collection detection independent of T.

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/resources/dart/libraries/dio/serialization/built_value/api/query_param.mustache, line 1:

<comment>When a query array or set has nullable items, this call uses non-nullable `T` and `FullType`, so `encodeParameter` does not recognize the `BuiltList<T?>`/`BuiltSet<T?>` as its collection type and returns the raw serialized iterable instead of a `ListParam`. Preserve item nullability in the generic and `FullType`, or make the helper’s collection detection independent of `T`.</comment>

<file context>
@@ -1 +1 @@
-{{#isContainer}}{{#isMap}}encodeQueryParameter{{/isMap}}{{^isMap}}encodeCollectionParameter<{{{baseType}}}>{{/isMap}}{{/isContainer}}{{^isContainer}}encodeQueryParameter{{/isContainer}}(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{dataType}}}){{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]), {{#collectionFormat}}format: ListFormat.{{collectionFormat}},{{/collectionFormat}}{{/isContainer}})
\ No newline at end of file
+{{#isContainer}}{{#isMap}}encodeParameter(_serializers, {{{paramName}}}, const FullType(BuiltMap, [FullType(String), FullType({{{baseType}}})])){{/isMap}}{{^isMap}}encodeParameter<{{{baseType}}}>(_serializers, {{{paramName}}}, const FullType(Built{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [FullType({{{baseType}}})]){{#collectionFormat}}, format: ListFormat.{{collectionFormat}}{{/collectionFormat}}){{/isMap}}{{/isContainer}}{{^isContainer}}encodeParameter(_serializers, {{{paramName}}}, const FullType({{{dataType}}})){{/isContainer}}
\ No newline at end of file
</file context>

@@ -0,0 +1 @@
{{#isContainer}}{{#isMap}}encodeParameter(_serializers, {{{paramName}}}, const FullType(BuiltMap, [FullType(String), FullType({{{baseType}}})]), asString: true){{/isMap}}{{^isMap}}encodeParameter<{{{baseType}}}>(_serializers, {{{paramName}}}, const FullType(Built{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [FullType({{{baseType}}})]), asString: true{{#collectionFormat}}, format: ListFormat.{{collectionFormat}}{{/collectionFormat}}){{/isMap}}{{/isContainer}}{{^isContainer}}encodeParameter(_serializers, {{{paramName}}}, const FullType({{{dataType}}}), asString: true){{/isContainer}} No newline at end of file

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: When a form field is a non-container model/object, this call leaves the serialized Map in the form body instead of encoding it as the JSON string required by form serialization. Make encodeParameter honor asString for serialized objects, or retain a dedicated form encoder for this branch.

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/resources/dart/libraries/dio/serialization/built_value/api/form_param.mustache, line 1:

<comment>When a form field is a non-container model/object, this call leaves the serialized `Map` in the form body instead of encoding it as the JSON string required by form serialization. Make `encodeParameter` honor `asString` for serialized objects, or retain a dedicated form encoder for this branch.</comment>

<file context>
@@ -1 +1 @@
-{{#isContainer}}{{#isMap}}encodeFormParameter{{/isMap}}{{^isMap}}encodeCollectionParameter<{{{baseType}}}>{{/isMap}}{{/isContainer}}{{^isContainer}}encodeFormParameter{{/isContainer}}(_serializers, {{{paramName}}}, const FullType({{^isContainer}}{{{dataType}}}{{/isContainer}}{{#isContainer}}Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]{{/isContainer}}){{#isContainer}}{{^isMap}}, asString: true{{#collectionFormat}}, format: ListFormat.{{collectionFormat}}{{/collectionFormat}}{{/isMap}}{{/isContainer}})
\ No newline at end of file
+{{#isContainer}}{{#isMap}}encodeParameter(_serializers, {{{paramName}}}, const FullType(BuiltMap, [FullType(String), FullType({{{baseType}}})]), asString: true){{/isMap}}{{^isMap}}encodeParameter<{{{baseType}}}>(_serializers, {{{paramName}}}, const FullType(Built{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [FullType({{{baseType}}})]), asString: true{{#collectionFormat}}, format: ListFormat.{{collectionFormat}}{{/collectionFormat}}){{/isMap}}{{/isContainer}}{{^isContainer}}encodeParameter(_serializers, {{{paramName}}}, const FullType({{{dataType}}}), asString: true){{/isContainer}}
\ No newline at end of file
</file context>


/**
* Regression test: path parameters whose type is an enum must use
* {@code encodeParameter} (which calls the built_value serializer and

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: The javadoc for testEnumPathParamsUseSerializerNotToString now names {@code encodeParameter}, but the test asserts {@code encodePathParameter(...)} and that is the helper this regression covers. Update the javadoc to {@code encodePathParameter} so it matches the code and does not mislead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/dio/DartDioClientCodegenTest.java, line 453:

<comment>The javadoc for testEnumPathParamsUseSerializerNotToString now names {@code encodeParameter}, but the test asserts {@code encodePathParameter(...)} and that is the helper this regression covers. Update the javadoc to {@code encodePathParameter} so it matches the code and does not mislead.</comment>

<file context>
@@ -450,14 +450,14 @@ public void testNullableCollectionItemsGetNullableBuilderFactory() throws IOExce
     /**
      * Regression test: path parameters whose type is an enum must use
-     * {@code encodeQueryParameter} (which calls the built_value serializer and
+     * {@code encodeParameter} (which calls the built_value serializer and
      * returns the wire name) rather than a bare {@code .toString()} call (which
      * returns the Dart identifier name and differs when the wire name contains
</file context>
Suggested change
* {@code encodeParameter} (which calls the built_value serializer and
* {@code encodePathParameter} (which calls the built_value serializer and

@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 27 files (changes from recent commits).

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="samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake-json_serializable/lib/src/api_util.dart">

<violation number="1" location="samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake-json_serializable/lib/src/api_util.dart:17">
P2: When an enum path parameter has a generated wire value different from its Dart identifier, `encodePathParameter` sends the identifier because it returns `Enum.name`. Serialize enums using their wire-value representation, and apply the same fix in `_encodePathValue`.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/json_serializable/api/path_param.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/dart/libraries/dio/serialization/json_serializable/api/path_param.mustache:1">
P1: For JSON-serializable enum path parameters, `encodePathParameter` returns `Enum.name` before calling the generated enum’s wire-value `toString()`. The new call therefore sends the Dart identifier instead of `@JsonValue`; retain `.toString()` for enum path parameters or update the helper to use the generated wire value.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread samples/openapi3/client/petstore/dart-dio/binary_response/lib/src/api_util.dart Outdated
@@ -0,0 +1 @@
{{#isContainer}}{{#isNullable}}{{{paramName}}} == null ? '' : encodePathParameter({{{paramName}}}, format: ListFormat.{{collectionFormat}}){{/isNullable}}{{^isNullable}}encodePathParameter({{{paramName}}}, format: ListFormat.{{collectionFormat}}){{/isNullable}}{{/isContainer}}{{^isContainer}}{{#isNullable}}{{{paramName}}} == null ? '' : encodePathParameter({{{paramName}}}){{/isNullable}}{{^isNullable}}encodePathParameter({{{paramName}}}){{/isNullable}}{{/isContainer}}

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: For JSON-serializable enum path parameters, encodePathParameter returns Enum.name before calling the generated enum’s wire-value toString(). The new call therefore sends the Dart identifier instead of @JsonValue; retain .toString() for enum path parameters or update the helper to use the generated wire value.

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/resources/dart/libraries/dio/serialization/json_serializable/api/path_param.mustache, line 1:

<comment>For JSON-serializable enum path parameters, `encodePathParameter` returns `Enum.name` before calling the generated enum’s wire-value `toString()`. The new call therefore sends the Dart identifier instead of `@JsonValue`; retain `.toString()` for enum path parameters or update the helper to use the generated wire value.</comment>

<file context>
@@ -1 +1 @@
-{{#isContainer}}{{#isNullable}}{{{paramName}}} == null ? '' : encodeCollectionQueryParameter<{{{baseType}}}>(_serializers, {{{paramName}}}, const FullType(Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]), {{#collectionFormat}}format: ListFormat.{{collectionFormat}},{{/collectionFormat}}){{/isNullable}}{{^isNullable}}encodeCollectionQueryParameter<{{{baseType}}}>(_serializers, {{{paramName}}}, const FullType(Built{{#isMap}}Map{{/isMap}}{{#isArray}}{{#uniqueItems}}Set{{/uniqueItems}}{{^uniqueItems}}List{{/uniqueItems}}{{/isArray}}, [{{#isMap}}FullType(String), {{/isMap}}FullType({{{baseType}}})]), {{#collectionFormat}}format: ListFormat.{{collectionFormat}},{{/collectionFormat}}){{/isNullable}}{{/isContainer}}{{^isContainer}}{{#isNullable}}{{{paramName}}} == null ? '' : {{{paramName}}}.toString(){{/isNullable}}{{^isNullable}}{{{paramName}}}.toString(){{/isNullable}}{{/isContainer}}
\ No newline at end of file
+{{#isContainer}}{{#isNullable}}{{{paramName}}} == null ? '' : encodePathParameter({{{paramName}}}, format: ListFormat.{{collectionFormat}}){{/isNullable}}{{^isNullable}}encodePathParameter({{{paramName}}}, format: ListFormat.{{collectionFormat}}){{/isNullable}}{{/isContainer}}{{^isContainer}}{{#isNullable}}{{{paramName}}} == null ? '' : encodePathParameter({{{paramName}}}){{/isNullable}}{{^isNullable}}encodePathParameter({{{paramName}}}){{/isNullable}}{{/isContainer}}
</file context>

return value.toString();
}
if (value is Enum) {
return value.name;

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: When an enum path parameter has a generated wire value different from its Dart identifier, encodePathParameter sends the identifier because it returns Enum.name. Serialize enums using their wire-value representation, and apply the same fix in _encodePathValue.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake-json_serializable/lib/src/api_util.dart, line 17:

<comment>When an enum path parameter has a generated wire value different from its Dart identifier, `encodePathParameter` sends the identifier because it returns `Enum.name`. Serialize enums using their wire-value representation, and apply the same fix in `_encodePathValue`.</comment>

<file context>
@@ -3,9 +3,81 @@
+    return value.toString();
+  }
+  if (value is Enum) {
+    return value.name;
+  }
+  if (value is List) {
</file context>

fstotz and others added 10 commits August 25, 2026 11:39
- Remove trailing newline from path_param.mustache files to preserve
  statement formatting (fixes mid-expression splits in generated code)
- Make collectionFormat conditional in json_serializable path_param to
  prevent 'ListFormat.' with null value when format is not applicable
  (fixes compilation errors for map path parameters)
- Regenerate all 8 Dart Dio samples with fixes applied

Addresses issues OpenAPITools#3 (P3 formatting) and OpenAPITools#7 (P1 compilation) from recent review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add Uri.encodeComponent() to all path value encoding in built_value and
  json_serializable encodePathParameter functions to prevent URL injection
  when path parameters contain reserved chars (/, ?, #, etc)
- Apply encoding to primitive strings, numbers, booleans, and enums
- Apply encoding to individual items in collections (lists/maps) via
  _encodePathValue helper
- Regenerate all 8 Dart Dio samples with URI encoding applied

Fixes P1 security issues: missing path encoding in api_util templates
and generated samples.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 'import package:dio/dio.dart' to json_serializable api_util.mustache
- Fixes compilation error: ListFormat reference without import
- Regenerate all 8 Dart Dio samples

Fixes P1 issue OpenAPITools#8 from recent review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Change Enum.name to Enum.toString() in json_serializable api_util
  encodePathParameter to send wire value instead of Dart identifier
- Change Enum.name to Enum.toString() in common encode_path_parameter
  _encodePathValue for enums in collections (lists/maps)
- For json_serializable, toString() override returns @jsonvalue wire value
- For built_value, enums are pre-serialized via serializers framework
  before reaching _encodePathValue, so they won't be raw Enum objects
- Regenerate all 8 Dart Dio samples

Fixes P1 issues OpenAPITools#2, OpenAPITools#6 and P2 issue OpenAPITools#9: enum wire values in path parameters
and collections now use correct OpenAPI values instead of Dart identifiers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Combine String/num/bool/Enum type checks into single condition
- Both json_serializable and common _encodePathValue now handle
  primitives + enums in one check: all return value.toString()
- Reduces redundant if-branches without changing behavior
- Regenerate all 8 Dart Dio samples

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add testEnumCollectionPathParamsUseWireValues test that verifies enum
  items in List/Map path parameters are encoded using wire values
- Add path_param_enum_collection.yaml test spec with array and map
  enum parameters
- Verifies that _encodePathValue helper calls .toString() on enum items
  to get wire values, not Dart identifiers

This test ensures Issue OpenAPITools#4 (P2): enums in collections as path parameters
now correctly use wire values from @jsonvalue annotations instead of
Dart member identifiers.

The fix was already applied when consolidating type checks in
_encodePathValue to combine String/num/bool/Enum handling - each enum
item in a collection now gets .toString() when recursively encoded.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace petstore.yaml with dedicated non_multipart_form_cleanup.yaml spec
  that contains only form-only operations (no query parameters)
- Eliminates false-positive passing: test previously could be satisfied
  by query param cleanup even if form cleanup was broken
- New spec has submitForm and updateForm operations with required and
  optional form fields; no query params to create ambiguity
- Test now definitively verifies form cleanup calls removeNullParametersExcept
  on _bodyData

Fixes Issue OpenAPITools#10 (P2): testNonMultipartFormParametersDropNulls now actually
validates form parameter null-dropping instead of being satisfied by
unrelated query parameter cleanup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Change form parameter null guard to apply to ALL optional params,
  not just non-nullable optional params
- Old guard: {{^required}}{{^isNullable}}if(...!= null){{/isNullable}}{{/required}}
- New guard: {{^required}}if(...!= null){{/required}}
- Fixes optional nullable form params being encoded to empty string
  instead of being omitted from form body
- Applied to both built_value and json_serializable serialize templates
- Applied to both multipart and non-multipart form encoding
- Regenerate all 8 Dart Dio samples

Before fix:
  Optional nullable param with null value → encoded to '' → map gets
  'field': '' instead of omitting the field

After fix:
  Optional nullable param with null value → guarded by if check →
  stays null in map → removeNullParametersExcept removes it → field omitted

Fixes P2 Issue OpenAPITools#1: optional nullable form parameters now correctly
omitted from form body when null, instead of sent as empty fields.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove testNonMultipartFormParametersDropNulls and testEnumCollectionPathParamsUseWireValues
which reference test spec files that failed OpenAPI validation.

The underlying fixes remain valid:
- Form parameter null cleanup via removeNullParametersExcept is covered by
  testRequiredNullableFormParametersArePreserved
- Enum path encoding wire values are validated by existing petstore samples

Co-authored-by: Copilot <223556219+Copilot@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.

3 issues found across 18 files (changes from recent commits).

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="samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake/lib/src/api_util.dart">

<violation number="1" location="samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake/lib/src/api_util.dart:91">
P2: When a raw Dart enum reaches `_encodePathValue`, `toString()` emits the enum type and member instead of the member name, producing an invalid path value. Keep the primitive branch separate and use `value.name` for `Enum` values.</violation>
</file>

<file name="samples/openapi3/client/petstore/dart-dio/oneof_polymorphism_and_inheritance/lib/src/api_util.dart">

<violation number="1" location="samples/openapi3/client/petstore/dart-dio/oneof_polymorphism_and_inheritance/lib/src/api_util.dart:92">
P2: When a native Dart enum reaches `_encodePathValue`, `toString()` produces `EnumType.value` instead of the enum value name. Preserve `value.name` in the `Enum` branch, then encode that name.</violation>
</file>

<file name="samples/openapi3/client/petstore/dart-dio/oneof_primitive/lib/src/api_util.dart">

<violation number="1" location="samples/openapi3/client/petstore/dart-dio/oneof_primitive/lib/src/api_util.dart:92">
P2: When a collection path parameter contains a native Dart enum, this change sends `EnumType.member` instead of the enum's wire/name value. URI-encode `value.name` rather than `value.toString()` in the `Enum` branch.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

return '';
}
if (value is String || value is num || value is bool || value is Enum) {
return Uri.encodeComponent(value.toString());

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: When a native Dart enum reaches _encodePathValue, toString() produces EnumType.value instead of the enum value name. Preserve value.name in the Enum branch, then encode that name.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/dart-dio/oneof_polymorphism_and_inheritance/lib/src/api_util.dart, line 92:

<comment>When a native Dart enum reaches `_encodePathValue`, `toString()` produces `EnumType.value` instead of the enum value name. Preserve `value.name` in the `Enum` branch, then encode that name.</comment>

<file context>
@@ -81,18 +81,15 @@ String encodePathParameter(
-  if (value is Enum) {
-    return value.name;
+  if (value is String || value is num || value is bool || value is Enum) {
+    return Uri.encodeComponent(value.toString());
   }
   if (value is List) {
</file context>

return '';
}
if (value is String || value is num || value is bool || value is Enum) {
return Uri.encodeComponent(value.toString());

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: When a collection path parameter contains a native Dart enum, this change sends EnumType.member instead of the enum's wire/name value. URI-encode value.name rather than value.toString() in the Enum branch.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/dart-dio/oneof_primitive/lib/src/api_util.dart, line 92:

<comment>When a collection path parameter contains a native Dart enum, this change sends `EnumType.member` instead of the enum's wire/name value. URI-encode `value.name` rather than `value.toString()` in the `Enum` branch.</comment>

<file context>
@@ -81,18 +81,15 @@ String encodePathParameter(
-  if (value is Enum) {
-    return value.name;
+  if (value is String || value is num || value is bool || value is Enum) {
+    return Uri.encodeComponent(value.toString());
   }
   if (value is List) {
</file context>

Comment on lines +91 to +92
if (value is String || value is num || value is bool || value is Enum) {
return Uri.encodeComponent(value.toString());

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: When a raw Dart enum reaches _encodePathValue, toString() emits the enum type and member instead of the member name, producing an invalid path value. Keep the primitive branch separate and use value.name for Enum values.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/openapi3/client/petstore/dart-dio/petstore_client_lib_fake/lib/src/api_util.dart, line 91:

<comment>When a raw Dart enum reaches `_encodePathValue`, `toString()` emits the enum type and member instead of the member name, producing an invalid path value. Keep the primitive branch separate and use `value.name` for `Enum` values.</comment>

<file context>
@@ -81,18 +81,15 @@ String encodePathParameter(
-  }
-  if (value is Enum) {
-    return value.name;
+  if (value is String || value is num || value is bool || value is Enum) {
+    return Uri.encodeComponent(value.toString());
   }
</file context>
Suggested change
if (value is String || value is num || value is bool || value is Enum) {
return Uri.encodeComponent(value.toString());
if (value is String || value is num || value is bool) {
return Uri.encodeComponent(value.toString());
}
if (value is Enum) {
return Uri.encodeComponent(value.name);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] [dart-dio] Discriminator with multi-layered subclasses causes the subclasses to have error in discriminators

2 participants