Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[csharp-netcore] Better handling of oneOf/anyOf with duplicated data type #15377

Merged
merged 5 commits into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 0 additions & 1 deletion docs/generators/csharp-netcore.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|packageVersion|C# package version.| |1.0.0|
|releaseNote|Release note, default to 'Minor update'.| |Minor update|
|returnICollection|Return ICollection<T> instead of the concrete type.| |false|
|skipOneOfAnyOfGetter|Skip the generation of getter for sub-schemas in oneOf/anyOf models.| |false|
|sourceFolder|source folder for generated code| |src|
|targetFramework|The target .NET framework version. To target multiple frameworks, use `;` as the separator, e.g. `netstandard2.1;netcoreapp3.1`|<dl><dt>**netstandard1.3**</dt><dd>.NET Standard 1.3 compatible</dd><dt>**netstandard1.4**</dt><dd>.NET Standard 1.4 compatible</dd><dt>**netstandard1.5**</dt><dd>.NET Standard 1.5 compatible</dd><dt>**netstandard1.6**</dt><dd>.NET Standard 1.6 compatible</dd><dt>**netstandard2.0**</dt><dd>.NET Standard 2.0 compatible</dd><dt>**netstandard2.1**</dt><dd>.NET Standard 2.1 compatible</dd><dt>**netcoreapp3.1**</dt><dd>.NET Core 3.1 compatible (End of Support 13 Dec 2022)</dd><dt>**net47**</dt><dd>.NET Framework 4.7 compatible</dd><dt>**net48**</dt><dd>.NET Framework 4.8 compatible</dd><dt>**net6.0**</dt><dd>.NET 6.0 compatible</dd><dt>**net7.0**</dt><dd>.NET 7.0 compatible</dd></dl>|netstandard2.0|
|useCollection|Deserialize array types to Collection&lt;T&gt; instead of List&lt;T&gt;.| |false|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8035,11 +8035,20 @@ private List<CodegenProperty> getComposedProperties(List<Schema> xOfCollection,
return null;
}
List<CodegenProperty> xOf = new ArrayList<>();
Set<String> dataTypeSet = new HashSet<>(); // to keep track of dataType
int i = 0;
for (Schema xOfSchema : xOfCollection) {
CodegenProperty cp = fromProperty(collectionName + "_" + i, xOfSchema, false);
xOf.add(cp);
i += 1;

if (dataTypeSet.contains(cp.dataType)) {
// add "x-duplicated-data-type" to indicate if the dataType already occurs before
// in other sub-schemas of allOf/anyOf/oneOf
cp.vendorExtensions.putIfAbsent("x-duplicated-data-type", true);
} else {
dataTypeSet.add(cp.dataType);
}
}
return xOf;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,6 @@ public class CSharpNetCoreClientCodegen extends AbstractCSharpCodegen {
protected boolean needsCustomHttpMethod = false;
protected boolean needsUriBuilder = false;

// skip generation of getter for oneOf/anyOf sub-schemas to avoid duplicate getter
// when the subschemas are of the same type but with different constraints (e.g. array of string)
protected boolean skipOneOfAnyOfGetter = false;

public CSharpNetCoreClientCodegen() {
super();

Expand Down Expand Up @@ -331,10 +327,6 @@ public CSharpNetCoreClientCodegen() {
CodegenConstants.CASE_INSENSITIVE_RESPONSE_HEADERS_DESC,
this.caseInsensitiveResponseHeaders);

addSwitch(CodegenConstants.SKIP_ONEOF_ANYOF_GETTER,
CodegenConstants.SKIP_ONEOF_ANYOF_GETTER_DESC,
this.skipOneOfAnyOfGetter);

regexModifiers = new HashMap<>();
regexModifiers.put('i', "IgnoreCase");
regexModifiers.put('m', "Multiline");
Expand Down Expand Up @@ -806,7 +798,6 @@ public void processOpts() {
syncBooleanProperty(additionalProperties, CodegenConstants.OPTIONAL_METHOD_ARGUMENT, this::setOptionalMethodArgumentFlag, optionalMethodArgumentFlag);
syncBooleanProperty(additionalProperties, CodegenConstants.NON_PUBLIC_API, this::setNonPublicApi, isNonPublicApi());
syncBooleanProperty(additionalProperties, CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, this::setUseOneOfDiscriminatorLookup, this.useOneOfDiscriminatorLookup);
syncBooleanProperty(additionalProperties, CodegenConstants.SKIP_ONEOF_ANYOF_GETTER, this::setSkipOneOfAnyOfGetter, this.skipOneOfAnyOfGetter);
syncBooleanProperty(additionalProperties, "supportsFileParameters", this::setSupportsFileParameters, this.supportsFileParameters);

final String testPackageName = testPackageName();
Expand Down Expand Up @@ -1187,14 +1178,6 @@ public boolean getUseOneOfDiscriminatorLookup() {
return this.useOneOfDiscriminatorLookup;
}

public void setSkipOneOfAnyOfGetter(boolean skipOneOfAnyOfGetter) {
this.skipOneOfAnyOfGetter = skipOneOfAnyOfGetter;
}

public boolean getSkipOneOfAnyOfGetter() {
return this.skipOneOfAnyOfGetter;
}

@Override
public String toEnumVarName(String value, String datatype) {
if (value.length() == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,18 @@
JsonTokenType startingTokenType = utf8JsonReader.TokenType;

{{#composedSchemas.anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
Utf8JsonReader {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader = utf8JsonReader;
bool {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized = Client.ClientUtils.TryDeserialize<{{{dataType}}}>(ref {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader, jsonSerializerOptions, out {{{dataType}}}{{^isBoolean}}{{nrt?}}{{/isBoolean}} {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}});

{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.anyOf}}
{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
Utf8JsonReader {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader = utf8JsonReader;
bool {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized = Client.ClientUtils.TryDeserialize<{{{dataType}}}>(ref {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Reader, jsonSerializerOptions, out {{{dataType}}}{{^isBoolean}}{{nrt?}}{{/isBoolean}} {{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}});

{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}
{{#composedSchemas.allOf}}
{{^isInherited}}
Expand Down Expand Up @@ -186,9 +190,11 @@
{{/-last}}
{{/nonNullableVars}}
{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
if ({{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}Deserialized)
return new {{classname}}({{#lambda.joinWithComma}}{{#lambda.camelcase_param}}{{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}{{/lambda.camelcase_param}} {{#model.composedSchemas.allOf}}{{^isInherited}}{{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}}{{/isInherited}}{{/model.composedSchemas.allOf}}{{#model.composedSchemas.anyOf}}{{#lambda.camelcase_param}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.camelcase_param}} {{/model.composedSchemas.anyOf}}{{#allVars}}{{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}} {{/allVars}}{{/lambda.joinWithComma}});

{{/vendorExtensions.x-duplicated-data-type}}
{{#-last}}
throw new JsonException();
{{/-last}}
Expand All @@ -207,8 +213,27 @@
/// <exception cref="NotImplementedException"></exception>
public override void Write(Utf8JsonWriter writer, {{classname}} {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}, JsonSerializerOptions jsonSerializerOptions)
{
{{#composedSchemas.anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
System.Text.Json.JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}}, jsonSerializerOptions);

{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.anyOf}}
{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
System.Text.Json.JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}}, jsonSerializerOptions);

{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}
{{#composedSchemas.allOf}}
{{^isInherited}}
System.Text.Json.JsonSerializer.Serialize(writer, {{#lambda.camelcase_param}}{{classname}}{{/lambda.camelcase_param}}.{{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}}, jsonSerializerOptions);

{{^composedSchemas}}
writer.WriteStartObject();

{{/isInherited}}
{{/composedSchemas.allOf}}
{{#allVars}}
{{#isString}}
{{^isMap}}
Expand Down Expand Up @@ -322,5 +347,6 @@
{{/allVars}}

writer.WriteEndObject();
{{/composedSchemas}}
}
}
wing328 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
{{>visibility}} partial class {{classname}}{{#parent}} : {{{.}}}{{/parent}}{{>ImplementsIEquatable}}{{>ImplementsValidatable}}
{
{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
/// <summary>
/// Initializes a new instance of the <see cref="{{classname}}" /> class.
/// </summary>
Expand Down Expand Up @@ -36,6 +37,7 @@
{{/allVars}}
}

{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}
{{^composedSchemas.oneOf}}
/// <summary>
Expand Down Expand Up @@ -103,6 +105,7 @@
{{/isEnum}}
{{/vars}}
{{#composedSchemas.anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
/// <summary>
/// {{description}}{{^description}}Gets or Sets {{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}}{{/description}}
/// </summary>{{#description}}
Expand All @@ -115,8 +118,10 @@
{{/deprecated}}
public {{{dataType}}}{{nrt?}} {{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}} { get; {{^isReadOnly}}set; {{/isReadOnly}}}

{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.anyOf}}
{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
/// <summary>
/// {{description}}{{^description}}Gets or Sets {{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}}{{/description}}
/// </summary>{{#description}}
Expand All @@ -129,6 +134,7 @@
{{/deprecated}}
public {{{dataType}}}{{nrt?}} {{#lambda.titlecase}}{{baseType}}{{#isArray}}{{{dataFormat}}}{{/isArray}}{{/lambda.titlecase}} { get; {{^isReadOnly}}set; {{/isReadOnly}}}

{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}
{{#composedSchemas.allOf}}
{{^isInherited}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

{{/isNullable}}
{{#composedSchemas.anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
{{^isNull}}
/// <summary>
/// Initializes a new instance of the <see cref="{{classname}}" /> class
Expand All @@ -38,6 +39,7 @@
}

{{/isNull}}
{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.anyOf}}

private Object _actualInstance;
Expand Down Expand Up @@ -66,6 +68,7 @@
}
}
{{#composedSchemas.anyOf}}
{{^vendorExtensions.x-duplicated-data-type}}
{{^isNull}}

/// <summary>
Expand All @@ -78,6 +81,7 @@
return ({{{dataType}}})this.ActualInstance;
}
{{/isNull}}
{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.anyOf}}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

{{/isNullable}}
{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
{{^isNull}}
/// <summary>
/// Initializes a new instance of the <see cref="{{classname}}" /> class
Expand All @@ -38,6 +39,7 @@
}

{{/isNull}}
{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}

private Object _actualInstance;
Expand Down Expand Up @@ -65,8 +67,8 @@
}
}
}
{{^skipOneOfAnyOfGetter}}
{{#composedSchemas.oneOf}}
{{^vendorExtensions.x-duplicated-data-type}}
{{^isNull}}

/// <summary>
Expand All @@ -79,8 +81,8 @@
return ({{{dataType}}})this.ActualInstance;
}
{{/isNull}}
{{/vendorExtensions.x-duplicated-data-type}}
{{/composedSchemas.oneOf}}
{{/skipOneOfAnyOfGetter}}

/// <summary>
/// Returns the string presentation of the object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2273,3 +2273,9 @@ components:
unescapedLiteralString:
type: string
default: C:\Users\username
OneOfString:
oneOf:
- type: string
pattern: ^a
- type: string
pattern: ^b
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ docs/NullableGuidClass.md
docs/NullableShape.md
docs/NumberOnly.md
docs/ObjectWithDeprecatedFields.md
docs/OneOfString.md
docs/Order.md
docs/OuterComposite.md
docs/OuterEnum.md
Expand Down Expand Up @@ -180,6 +181,7 @@ src/Org.OpenAPITools/Model/NullableGuidClass.cs
src/Org.OpenAPITools/Model/NullableShape.cs
src/Org.OpenAPITools/Model/NumberOnly.cs
src/Org.OpenAPITools/Model/ObjectWithDeprecatedFields.cs
src/Org.OpenAPITools/Model/OneOfString.cs
src/Org.OpenAPITools/Model/Order.cs
src/Org.OpenAPITools/Model/OuterComposite.cs
src/Org.OpenAPITools/Model/OuterEnum.cs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ Class | Method | HTTP request | Description
- [Model.NullableShape](docs/NullableShape.md)
- [Model.NumberOnly](docs/NumberOnly.md)
- [Model.ObjectWithDeprecatedFields](docs/ObjectWithDeprecatedFields.md)
- [Model.OneOfString](docs/OneOfString.md)
- [Model.Order](docs/Order.md)
- [Model.OuterComposite](docs/OuterComposite.md)
- [Model.OuterEnum](docs/OuterEnum.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2200,6 +2200,12 @@ components:
default: C:\Users\username
type: string
type: object
OneOfString:
oneOf:
- pattern: ^a
type: string
- pattern: ^b
type: string
_foo_get_default_response:
example:
string:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Org.OpenAPITools.Model.OneOfString

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* OpenAPI Petstore
*
* This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
*
* The version of the OpenAPI document: 1.0.0
* Generated by: https://github.com/openapitools/openapi-generator.git
*/


using Xunit;

using System;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using Org.OpenAPITools.Model;
using Org.OpenAPITools.Client;
using System.Reflection;
using Newtonsoft.Json;

namespace Org.OpenAPITools.Test.Model
{
/// <summary>
/// Class for testing OneOfString
/// </summary>
/// <remarks>
/// This file is automatically generated by OpenAPI Generator (https://openapi-generator.tech).
/// Please update the test case below to test the model.
/// </remarks>
public class OneOfStringTests : IDisposable
{
// TODO uncomment below to declare an instance variable for OneOfString
//private OneOfString instance;

public OneOfStringTests()
{
// TODO uncomment below to create an instance of OneOfString
//instance = new OneOfString();
}

public void Dispose()
{
// Cleanup when everything is done.
}

/// <summary>
/// Test an instance of OneOfString
/// </summary>
[Fact]
public void OneOfStringInstanceTest()
{
// TODO uncomment below to test "IsType" OneOfString
//Assert.IsType<OneOfString>(instance);
}



}

}
Loading