Skip to content

Commit df1d562

Browse files
authored
[csharp] Ensure unique property names (#21649)
* started fixing multiple issues * weather api builds * added docstring * ensure property names are unique * force pr gates to restart * force pr gates to restart * force pr gates to restart * force pr gates to restart
1 parent 302590a commit df1d562

File tree

72 files changed

+1407
-37
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1407
-37
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
629629
List<CodegenProperty> allOf = composedSchemas.getAllOf();
630630
if (allOf != null) {
631631
for (CodegenProperty property : allOf) {
632-
property.name = patchPropertyName(model, camelize(property.baseType), composedPropertyNames);
632+
property.name = patchPropertyName(model, property, camelize(property.baseType), composedPropertyNames);
633633
patchPropertyVendorExtensions(property);
634634
}
635635
}
@@ -638,7 +638,7 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
638638
if (anyOf != null) {
639639
removePropertiesDeclaredInComposedTypes(objs, model, anyOf);
640640
for (CodegenProperty property : anyOf) {
641-
property.name = patchPropertyName(model, camelize(property.baseType), composedPropertyNames);
641+
property.name = patchPropertyName(model, property, camelize(property.baseType), composedPropertyNames);
642642
property.isNullable = true;
643643
patchPropertyVendorExtensions(property);
644644
property.vendorExtensions.put("x-base-name", model.name.substring(model.name.lastIndexOf('_') + 1));
@@ -649,7 +649,7 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
649649
if (oneOf != null) {
650650
removePropertiesDeclaredInComposedTypes(objs, model, oneOf);
651651
for (CodegenProperty property : oneOf) {
652-
property.name = patchPropertyName(model, camelize(property.baseType), composedPropertyNames);
652+
property.name = patchPropertyName(model, property, camelize(property.baseType), composedPropertyNames);
653653
property.isNullable = true;
654654
patchPropertyVendorExtensions(property);
655655
property.vendorExtensions.put("x-base-name", model.name.substring(model.name.lastIndexOf('_') + 1));
@@ -716,7 +716,51 @@ private boolean modelIsMutable(CodegenModel model, Set<String> processed) {
716716
protected void removePropertiesDeclaredInComposedTypes(Map<String, ModelsMap> objs, CodegenModel model, List<CodegenProperty> composedProperties) {
717717
}
718718

719-
private String patchPropertyName(CodegenModel model, String value, Set<String> composedPropertyNames) {
719+
/**
720+
* If the model has duplicate proprety names, just make it unique
721+
* This can happen for base names like "id" and "@id"
722+
* @param model
723+
* @param property
724+
* @param value
725+
* @return
726+
*/
727+
private String setUniquePropertyName(CodegenModel model, CodegenProperty property, String value) {
728+
if (property.name.equalsIgnoreCase(property.baseName)) {
729+
return value;
730+
}
731+
732+
Optional<CodegenProperty> alreadyUpdatedProperty = model.allVars.stream()
733+
.filter(p -> !p.name.equals(property.name) && p.baseName.equals(property.baseName))
734+
.collect(Collectors.toList())
735+
.stream()
736+
.findFirst();
737+
738+
if (alreadyUpdatedProperty.isPresent()) {
739+
// above iterates allVars, which may have already been corrected
740+
return alreadyUpdatedProperty.get().name;
741+
}
742+
743+
final String tmp = value;
744+
745+
long count = model.allVars.stream()
746+
.filter(v -> v.name.equalsIgnoreCase(tmp))
747+
.count();
748+
749+
if (count > 1) {
750+
value = value + count;
751+
value = setUniquePropertyName(model, property, value);
752+
}
753+
754+
return value;
755+
}
756+
757+
/**
758+
* Fixes nested maps so the generic type is defined
759+
* Convertes List<List>> to List<List<T>>
760+
*/
761+
private String patchPropertyName(CodegenModel model, CodegenProperty property, String value, Set<String> composedPropertyNames) {
762+
value = setUniquePropertyName(model, property, value);
763+
720764
String name = escapeReservedWord(model, value);
721765

722766
if (name.startsWith(AbstractCSharpCodegen.invalidParameterNamePrefix)) {
@@ -799,7 +843,7 @@ protected void patchProperty(Map<String, CodegenModel> enumRefs, CodegenModel mo
799843

800844
patchPropertyVendorExtensions(property);
801845

802-
property.name = patchPropertyName(model, property.name, null);
846+
property.name = patchPropertyName(model, property, property.name, null);
803847

804848
patchNestedMaps(property);
805849

modules/openapi-generator/src/test/resources/3_0/csharp/petstore-with-fake-endpoints-models-for-testing-with-http-signature.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,10 @@ components:
17931793
string_formatted_as_decimal_required:
17941794
format: decimal
17951795
type: string
1796+
duplicate_property_name:
1797+
type: string
1798+
'@duplicate_property_name':
1799+
type: string
17961800
EnumClass:
17971801
type: string
17981802
default: '-efg'

samples/client/petstore/csharp/generichost/net4.7/FormModels/api/openapi.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,6 +1685,10 @@ components:
16851685
string_formatted_as_decimal_required:
16861686
format: decimal
16871687
type: string
1688+
duplicate_property_name:
1689+
type: string
1690+
'@duplicate_property_name':
1691+
type: string
16881692
required:
16891693
- byte
16901694
- date

samples/client/petstore/csharp/generichost/net4.7/FormModels/docs/models/FormatTest.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Name | Type | Description | Notes
1313
**DateTime** | **DateTime** | | [optional]
1414
**Decimal** | **decimal** | | [optional]
1515
**Double** | **double** | | [optional]
16+
**DuplicatePropertyName2** | **string** | | [optional]
17+
**DuplicatePropertyName** | **string** | | [optional]
1618
**Float** | **float** | | [optional]
1719
**Int32** | **int** | | [optional]
1820
**Int32Range** | **int** | | [optional]

samples/client/petstore/csharp/generichost/net4.7/FormModels/src/Org.OpenAPITools.Test/Model/FormatTestTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,24 @@ public void DoubleTest()
134134
// TODO unit test for the property 'Double'
135135
}
136136

137+
/// <summary>
138+
/// Test the property 'DuplicatePropertyName2'
139+
/// </summary>
140+
[Fact]
141+
public void DuplicatePropertyName2Test()
142+
{
143+
// TODO unit test for the property 'DuplicatePropertyName2'
144+
}
145+
146+
/// <summary>
147+
/// Test the property 'DuplicatePropertyName'
148+
/// </summary>
149+
[Fact]
150+
public void DuplicatePropertyNameTest()
151+
{
152+
// TODO unit test for the property 'DuplicatePropertyName'
153+
}
154+
137155
/// <summary>
138156
/// Test the property 'Float'
139157
/// </summary>

samples/client/petstore/csharp/generichost/net4.7/FormModels/src/Org.OpenAPITools/Model/FormatTest.cs

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public partial class FormatTest : IValidatableObject
4141
/// <param name="dateTime">dateTime</param>
4242
/// <param name="decimal">decimal</param>
4343
/// <param name="double">double</param>
44+
/// <param name="duplicatePropertyName2">duplicatePropertyName2</param>
45+
/// <param name="duplicatePropertyName">duplicatePropertyName</param>
4446
/// <param name="float">float</param>
4547
/// <param name="int32">int32</param>
4648
/// <param name="int32Range">int32Range</param>
@@ -59,7 +61,7 @@ public partial class FormatTest : IValidatableObject
5961
/// <param name="unsignedLong">unsignedLong</param>
6062
/// <param name="uuid">uuid</param>
6163
[JsonConstructor]
62-
public FormatTest(byte[] @byte, DateTime date, decimal number, string password, decimal stringFormattedAsDecimalRequired, Option<System.IO.Stream> binary = default, Option<DateTime?> dateTime = default, Option<decimal?> @decimal = default, Option<double?> @double = default, Option<float?> @float = default, Option<int?> int32 = default, Option<int?> int32Range = default, Option<long?> int64 = default, Option<long?> int64Negative = default, Option<long?> int64NegativeExclusive = default, Option<long?> int64Positive = default, Option<long?> int64PositiveExclusive = default, Option<int?> integer = default, Option<string> patternWithBackslash = default, Option<string> patternWithDigits = default, Option<string> patternWithDigitsAndDelimiter = default, Option<string> @string = default, Option<decimal?> stringFormattedAsDecimal = default, Option<uint?> unsignedInteger = default, Option<ulong?> unsignedLong = default, Option<Guid?> uuid = default)
64+
public FormatTest(byte[] @byte, DateTime date, decimal number, string password, decimal stringFormattedAsDecimalRequired, Option<System.IO.Stream> binary = default, Option<DateTime?> dateTime = default, Option<decimal?> @decimal = default, Option<double?> @double = default, Option<string> duplicatePropertyName2 = default, Option<string> duplicatePropertyName = default, Option<float?> @float = default, Option<int?> int32 = default, Option<int?> int32Range = default, Option<long?> int64 = default, Option<long?> int64Negative = default, Option<long?> int64NegativeExclusive = default, Option<long?> int64Positive = default, Option<long?> int64PositiveExclusive = default, Option<int?> integer = default, Option<string> patternWithBackslash = default, Option<string> patternWithDigits = default, Option<string> patternWithDigitsAndDelimiter = default, Option<string> @string = default, Option<decimal?> stringFormattedAsDecimal = default, Option<uint?> unsignedInteger = default, Option<ulong?> unsignedLong = default, Option<Guid?> uuid = default)
6365
{
6466
Byte = @byte;
6567
Date = date;
@@ -70,6 +72,8 @@ public FormatTest(byte[] @byte, DateTime date, decimal number, string password,
7072
DateTimeOption = dateTime;
7173
DecimalOption = @decimal;
7274
DoubleOption = @double;
75+
DuplicatePropertyName2Option = duplicatePropertyName2;
76+
DuplicatePropertyNameOption = duplicatePropertyName;
7377
FloatOption = @float;
7478
Int32Option = int32;
7579
Int32RangeOption = int32Range;
@@ -176,6 +180,32 @@ public FormatTest(byte[] @byte, DateTime date, decimal number, string password,
176180
[JsonPropertyName("double")]
177181
public double? Double { get { return this.DoubleOption; } set { this.DoubleOption = new Option<double?>(value); } }
178182

183+
/// <summary>
184+
/// Used to track the state of DuplicatePropertyName2
185+
/// </summary>
186+
[JsonIgnore]
187+
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
188+
public Option<string> DuplicatePropertyName2Option { get; private set; }
189+
190+
/// <summary>
191+
/// Gets or Sets DuplicatePropertyName2
192+
/// </summary>
193+
[JsonPropertyName("duplicate_property_name")]
194+
public string DuplicatePropertyName2 { get { return this.DuplicatePropertyName2Option; } set { this.DuplicatePropertyName2Option = new Option<string>(value); } }
195+
196+
/// <summary>
197+
/// Used to track the state of DuplicatePropertyName
198+
/// </summary>
199+
[JsonIgnore]
200+
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
201+
public Option<string> DuplicatePropertyNameOption { get; private set; }
202+
203+
/// <summary>
204+
/// Gets or Sets DuplicatePropertyName
205+
/// </summary>
206+
[JsonPropertyName("@duplicate_property_name")]
207+
public string DuplicatePropertyName { get { return this.DuplicatePropertyNameOption; } set { this.DuplicatePropertyNameOption = new Option<string>(value); } }
208+
179209
/// <summary>
180210
/// Used to track the state of Float
181211
/// </summary>
@@ -424,6 +454,8 @@ public override string ToString()
424454
sb.Append(" DateTime: ").Append(DateTime).Append("\n");
425455
sb.Append(" Decimal: ").Append(Decimal).Append("\n");
426456
sb.Append(" Double: ").Append(Double).Append("\n");
457+
sb.Append(" DuplicatePropertyName2: ").Append(DuplicatePropertyName2).Append("\n");
458+
sb.Append(" DuplicatePropertyName: ").Append(DuplicatePropertyName).Append("\n");
427459
sb.Append(" Float: ").Append(Float).Append("\n");
428460
sb.Append(" Int32: ").Append(Int32).Append("\n");
429461
sb.Append(" Int32Range: ").Append(Int32Range).Append("\n");
@@ -658,6 +690,8 @@ public override FormatTest Read(ref Utf8JsonReader utf8JsonReader, Type typeToCo
658690
Option<DateTime?> dateTime = default;
659691
Option<decimal?> varDecimal = default;
660692
Option<double?> varDouble = default;
693+
Option<string> duplicatePropertyName2 = default;
694+
Option<string> duplicatePropertyName = default;
661695
Option<float?> varFloat = default;
662696
Option<int?> int32 = default;
663697
Option<int?> int32Range = default;
@@ -718,6 +752,12 @@ public override FormatTest Read(ref Utf8JsonReader utf8JsonReader, Type typeToCo
718752
case "double":
719753
varDouble = new Option<double?>(utf8JsonReader.TokenType == JsonTokenType.Null ? (double?)null : utf8JsonReader.GetDouble());
720754
break;
755+
case "duplicate_property_name":
756+
duplicatePropertyName2 = new Option<string>(utf8JsonReader.GetString());
757+
break;
758+
case "@duplicate_property_name":
759+
duplicatePropertyName = new Option<string>(utf8JsonReader.GetString());
760+
break;
721761
case "float":
722762
varFloat = new Option<float?>(utf8JsonReader.TokenType == JsonTokenType.Null ? (float?)null : (float)utf8JsonReader.GetDouble());
723763
break;
@@ -817,6 +857,12 @@ public override FormatTest Read(ref Utf8JsonReader utf8JsonReader, Type typeToCo
817857
if (varDouble.IsSet && varDouble.Value == null)
818858
throw new ArgumentNullException(nameof(varDouble), "Property is not nullable for class FormatTest.");
819859

860+
if (duplicatePropertyName2.IsSet && duplicatePropertyName2.Value == null)
861+
throw new ArgumentNullException(nameof(duplicatePropertyName2), "Property is not nullable for class FormatTest.");
862+
863+
if (duplicatePropertyName.IsSet && duplicatePropertyName.Value == null)
864+
throw new ArgumentNullException(nameof(duplicatePropertyName), "Property is not nullable for class FormatTest.");
865+
820866
if (varFloat.IsSet && varFloat.Value == null)
821867
throw new ArgumentNullException(nameof(varFloat), "Property is not nullable for class FormatTest.");
822868

@@ -868,7 +914,7 @@ public override FormatTest Read(ref Utf8JsonReader utf8JsonReader, Type typeToCo
868914
if (uuid.IsSet && uuid.Value == null)
869915
throw new ArgumentNullException(nameof(uuid), "Property is not nullable for class FormatTest.");
870916

871-
return new FormatTest(varByte.Value, date.Value.Value, number.Value.Value, password.Value, stringFormattedAsDecimalRequired.Value.Value, binary, dateTime, varDecimal, varDouble, varFloat, int32, int32Range, int64, int64Negative, int64NegativeExclusive, int64Positive, int64PositiveExclusive, integer, patternWithBackslash, patternWithDigits, patternWithDigitsAndDelimiter, varString, stringFormattedAsDecimal, unsignedInteger, unsignedLong, uuid);
917+
return new FormatTest(varByte.Value, date.Value.Value, number.Value.Value, password.Value, stringFormattedAsDecimalRequired.Value.Value, binary, dateTime, varDecimal, varDouble, duplicatePropertyName2, duplicatePropertyName, varFloat, int32, int32Range, int64, int64Negative, int64NegativeExclusive, int64Positive, int64PositiveExclusive, integer, patternWithBackslash, patternWithDigits, patternWithDigitsAndDelimiter, varString, stringFormattedAsDecimal, unsignedInteger, unsignedLong, uuid);
872918
}
873919

874920
/// <summary>
@@ -904,6 +950,12 @@ public void WriteProperties(Utf8JsonWriter writer, FormatTest formatTest, JsonSe
904950
if (formatTest.BinaryOption.IsSet && formatTest.Binary == null)
905951
throw new ArgumentNullException(nameof(formatTest.Binary), "Property is required for class FormatTest.");
906952

953+
if (formatTest.DuplicatePropertyName2Option.IsSet && formatTest.DuplicatePropertyName2 == null)
954+
throw new ArgumentNullException(nameof(formatTest.DuplicatePropertyName2), "Property is required for class FormatTest.");
955+
956+
if (formatTest.DuplicatePropertyNameOption.IsSet && formatTest.DuplicatePropertyName == null)
957+
throw new ArgumentNullException(nameof(formatTest.DuplicatePropertyName), "Property is required for class FormatTest.");
958+
907959
if (formatTest.PatternWithBackslashOption.IsSet && formatTest.PatternWithBackslash == null)
908960
throw new ArgumentNullException(nameof(formatTest.PatternWithBackslash), "Property is required for class FormatTest.");
909961

@@ -942,6 +994,12 @@ public void WriteProperties(Utf8JsonWriter writer, FormatTest formatTest, JsonSe
942994
if (formatTest.DoubleOption.IsSet)
943995
writer.WriteNumber("double", formatTest.DoubleOption.Value.Value);
944996

997+
if (formatTest.DuplicatePropertyName2Option.IsSet)
998+
writer.WriteString("duplicate_property_name", formatTest.DuplicatePropertyName2);
999+
1000+
if (formatTest.DuplicatePropertyNameOption.IsSet)
1001+
writer.WriteString("@duplicate_property_name", formatTest.DuplicatePropertyName);
1002+
9451003
if (formatTest.FloatOption.IsSet)
9461004
writer.WriteNumber("float", formatTest.FloatOption.Value.Value);
9471005

samples/client/petstore/csharp/generichost/net4.7/Petstore/api/openapi.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,10 @@ components:
17261726
string_formatted_as_decimal_required:
17271727
format: decimal
17281728
type: string
1729+
duplicate_property_name:
1730+
type: string
1731+
'@duplicate_property_name':
1732+
type: string
17291733
required:
17301734
- byte
17311735
- date

samples/client/petstore/csharp/generichost/net4.7/Petstore/docs/models/FormatTest.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Name | Type | Description | Notes
1313
**DateTime** | **DateTime** | | [optional]
1414
**Decimal** | **decimal** | | [optional]
1515
**Double** | **double** | | [optional]
16+
**DuplicatePropertyName2** | **string** | | [optional]
17+
**DuplicatePropertyName** | **string** | | [optional]
1618
**Float** | **float** | | [optional]
1719
**Int32** | **int** | | [optional]
1820
**Int32Range** | **int** | | [optional]

samples/client/petstore/csharp/generichost/net4.7/Petstore/src/Org.OpenAPITools.Test/Model/FormatTestTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,24 @@ public void DoubleTest()
134134
// TODO unit test for the property 'Double'
135135
}
136136

137+
/// <summary>
138+
/// Test the property 'DuplicatePropertyName2'
139+
/// </summary>
140+
[Fact]
141+
public void DuplicatePropertyName2Test()
142+
{
143+
// TODO unit test for the property 'DuplicatePropertyName2'
144+
}
145+
146+
/// <summary>
147+
/// Test the property 'DuplicatePropertyName'
148+
/// </summary>
149+
[Fact]
150+
public void DuplicatePropertyNameTest()
151+
{
152+
// TODO unit test for the property 'DuplicatePropertyName'
153+
}
154+
137155
/// <summary>
138156
/// Test the property 'Float'
139157
/// </summary>

0 commit comments

Comments
 (0)