fix(csharp): use enum rendering functions for array-of-enum properties in JSON converter#23375
fix(csharp): use enum rendering functions for array-of-enum properties in JSON converter#23375Neokil wants to merge 2 commits intoOpenAPITools:masterfrom
Conversation
…s in JSON converter
Array-typed properties whose items are enums fell through to the generic
JsonSerializer.Serialize/Deserialize path, which ignored the defined
*ValueConverter.ToJsonValue/*FromStringOrDefault functions and serialized
enum values using the default .NET JSON behaviour (PascalCase names).
Add explicit {{#items.isEnum}} branches in both the read (Deserialize) and
write (Serialize) paths of the generated JsonConverter so that each item in
an enum array is processed via the same converter functions used for scalar
enum properties.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
FYI: @mandrean (2017/08) @shibayan (2020/02) @Blackclaws (2021/03) @lucamazzanti (2021/05) @iBicha (2023/07) |
There was a problem hiding this comment.
1 issue found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="modules/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache:256">
P1: Enum-array deserialization lacks token-type/null guard before manual array loop, risking reader desynchronization and invalid token reads.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
...les/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache
Outdated
Show resolved
Hide resolved
…lues Without the null check, a JSON null value for an array-of-enum property caused the reader to advance past the null token and attempt to read the next property as array content, desynchronizing the Utf8JsonReader.
There was a problem hiding this comment.
1 issue found across 1 file (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="modules/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache:255">
P2: Enum-array null handling now skips setting the Option property when the JSON token is Null, so explicit nulls are treated as “not set.” This can cause required-property checks to throw and omit explicit nulls on re-serialization.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| {{^isDate}} | ||
| {{^isDateTime}} | ||
| {{#items.isEnum}} | ||
| if (utf8JsonReader.TokenType != JsonTokenType.Null) |
There was a problem hiding this comment.
P2: Enum-array null handling now skips setting the Option property when the JSON token is Null, so explicit nulls are treated as “not set.” This can cause required-property checks to throw and omit explicit nulls on re-serialization.
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/csharp/libraries/generichost/JsonConverter.mustache, line 255:
<comment>Enum-array null handling now skips setting the Option property when the JSON token is Null, so explicit nulls are treated as “not set.” This can cause required-property checks to throw and omit explicit nulls on re-serialization.</comment>
<file context>
@@ -252,16 +252,19 @@
{{#items.isEnum}}
- var {{#lambda.camelcase_sanitize_param}}{{name}}{{/lambda.camelcase_sanitize_param}}Items = new List<{{#items.isInnerEnum}}{{classname}}.{{/items.isInnerEnum}}{{{items.datatypeWithEnum}}}>();
- while (utf8JsonReader.Read())
+ if (utf8JsonReader.TokenType != JsonTokenType.Null)
{
- if (utf8JsonReader.TokenType == JsonTokenType.EndArray)
</file context>
|
Good find, please keep working this. cubic-dev-ai seems to be raising a good point. Also consider exploring the isContainer property and moving your code out of the fallback. Also, a new yaml sample for this isn't really necessary. You can append to the existing Petstore. |
Description
Array-typed properties whose items are enums were serialized and deserialized
using the generic
JsonSerializer.Serialize/Deserializepath in the generatedJsonConverter. This ignored the*ValueConverter.ToJsonValue/*ValueConverter.FromStringOrDefaultfunctions that are used correctly forscalar enum properties, and caused enum values to be written using the default
.NET JSON behaviour — which outputs the PascalCase enum member name — instead
of the casing defined in the OpenAPI spec.
Example: An OpenAPI spec defining
ShippingMethodwith valueexpresswouldbe serialized as
"Express"instead of"express"when that enum appeared asan array item.
Root cause
JsonConverter.mustachehad no{{#items.isEnum}}branches in either the reador write path. Scalar enum properties (
{{#isEnum}}) were handled correctly, butarray-of-enum properties fell through to the generic
JsonSerializerpath.Changes
modules/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache{{#items.isEnum}}branch inside the fallbackdeserialize block — iterates the JSON array and calls
*ValueConverter.FromStringOrDefault(external enum) or*FromStringOrDefault(inner enum) per item.{{#items.isEnum}}branch in all fourrequired/optional × nullable/non-nullable write cases — emits
WriteStartArray, calls*ValueConverter.ToJsonValue/*ToJsonValueper item (usingWriteStringValuefor string enums andWriteNumberValuefor numeric enums), thenWriteEndArray.modules/openapi-generator/src/test/resources/3_0/csharp/enum-array.yaml— new OpenAPI spec with a model containing both a scalar enum property
(
preferredMethod) and an array-of-enum property (allowedMethods) toexercise both the working and previously broken cases.
How to reproduce
Generate a C# client from an OpenAPI spec that contains a model with an
array property whose items are a string enum. Serialize an instance of that
model and observe that the enum values in the array are written in PascalCase
(
"Express") rather than the value defined in the spec ("express").Generator
csharp)generichostlibraries/generichost/JsonConverter.mustachePR checklist
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.
master(upcoming7.x.0minor release - breaking changes with fallbacks),8.0.x(breaking changes without fallbacks)"fixes #123"present in the PR description)Summary by cubic
Fixes C#
generichostJSON converter to handle array-of-enum properties using the enum rendering functions, so clients honor OpenAPI casing (e.g., "express" not "Express"). Also guards JSON null values for enum arrays to keep the reader in sync.items.isEnumhandling in the read path to iterate arrays and use*ValueConverter.FromStringOrDefault(or inner enum equivalent); skip processing when the token isNullto avoidUtf8JsonReaderdesync.items.isEnumhandling in the write path for all required/optional and nullable cases, emitting arrays and using*ValueConverter.ToJsonValueper item (string or numeric).3_0/csharp/enum-array.yamlcovering scalar enum and array-of-enum serialization/deserialization.Written for commit d0ba616. Summary will update on new commits.