OpenAPITools / OpenAPITools/openapi-generator

[BUG] [CSHARP] [GENERICHOST] JsonConverter.mustache template broken for `anyOf` and `oneOf` with generic collections

Open
#23,529 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

https://github.com/OpenAPITools/openapi-generator/blob/d11d0efaf096da702d9640bf8ac86b12d8d62a73/modules/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache#L398

For example the following yaml

 '202':
          description: Foo desc
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/Foo'
                  - type: array
                    items:
                      $ref: '#/components/schemas/Foo'

Generates following code, with incorrect < and > symbols emitted.

List<Foo>JsonConverter listltFoogtJsonConverter = (List<Foo>JsonConverter) jsonSerializerOptions.Converters.First(c => c.CanConvert(fooSendPost202Response.ListOption.Value.GetType()));
listltFoogtJsonConverter.WriteProperties(writer, fooSendPost202Response.ListOption.Value, jsonSerializerOptions);

GPt-5.4 and Claude proposed the following fix to the template - looks correct and generation works also correctly, but as I am no templating expert and mustache skills are also questionable, then would be great if someone takes a look into this.

 {{#composedSchemas}}
            {{#oneOf}}
            // oneOf block
            if ({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}} != null)
            {
                {{#isArray}}
                // isArray
                JsonSerializer.Serialize(writer, {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}, jsonSerializerOptions);
                return;
                {{/isArray}}
                {{#isMap}}
                // isMap
                JsonSerializer.Serialize(writer, {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}, jsonSerializerOptions);
                return;
                {{/isMap}}
            }

            {{/oneOf}}
            {{#anyOf}}
            // anyOf block
            {{#isArray}}
            // isArray
            if ({{#lambda.joinWithAmpersand}}{{^required}}{{#lambda.camelcase_sanitize_param}}{{model.classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option.IsSet  {{/required}}{{#lambda.camelcase_sanitize_param}}{{model.classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{/required}} != null{{/lambda.joinWithAmpersand}})
            {
                JsonSerializer.Serialize(writer, {{#lambda.camelcase_sanitize_param}}{{model.classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{#vendorExtensions.x-is-value-type}}.Value{{/vendorExtensions.x-is-value-type}}{{/required}}, jsonSerializerOptions);
                return;
            }
            {{/isArray}}
            {{#isMap}}
            // isMap
            if ({{#lambda.joinWithAmpersand}}{{^required}}{{#lambda.camelcase_sanitize_param}}{{model.classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option.IsSet  {{/required}}{{#lambda.camelcase_sanitize_param}}{{model.classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{/required}} != null{{/lambda.joinWithAmpersand}})
            {
                JsonSerializer.Serialize(writer, {{#lambda.camelcase_sanitize_param}}{{model.classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}{{^required}}Option.Value{{#vendorExtensions.x-is-value-type}}.Value{{/vendorExtensions.x-is-value-type}}{{/required}}, jsonSerializerOptions);
                return;
            }
            {{/isMap}}
            {{/anyOf}}
            {{/composedSchemas}}
            {{/model.discriminator}}
            writer.WriteStartObject();

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at modules/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache around line 398 and reproduce the issue with the provided anyOf schema. Compare the generated C# for generic collections with the expected type syntax, then verify generation no longer emits encoded angle brackets or the incorrect converter variable names.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.