Skip to content

Commit b808644

Browse files
committed
Tolerate schema properties named AdditionalProperties
1 parent 63ee615 commit b808644

File tree

4 files changed

+61
-17
lines changed

4 files changed

+61
-17
lines changed

src/NJsonSchema.CodeGeneration.CSharp.Tests/GeneralGeneratorTests.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
using Newtonsoft.Json;
1414
using Newtonsoft.Json.Converters;
1515
using NJsonSchema.Annotations;
16-
using NJsonSchema.Generation;
1716
using NJsonSchema.NewtonsoftJson.Generation;
1817
using Xunit;
1918

@@ -1890,6 +1889,35 @@ public async Task When_schema_has_AdditionProperties_schema_then_JsonExtensionDa
18901889

18911890
//// Assert
18921891
Assert.Contains("JsonExtensionData", output);
1892+
Assert.Contains("IDictionary<string, object> AdditionalProperties\n", output);
1893+
}
1894+
1895+
1896+
public class ClassWithAdditionalProperties
1897+
{
1898+
public string AdditionalProperties { get; set; }
1899+
1900+
[JsonExtensionData]
1901+
public IDictionary<string, object> ExtensionData { get; set; }
1902+
}
1903+
1904+
[Fact]
1905+
public async Task When_schema_has_AdditionProperties_schema_and_type_has_member_with_same_name()
1906+
{
1907+
//// Arrange
1908+
var schema = NewtonsoftJsonSchemaGenerator.FromType<ClassWithAdditionalProperties>(new NewtonsoftJsonSchemaGeneratorSettings { SchemaType = SchemaType.OpenApi3 });
1909+
var json = schema.ToJson();
1910+
1911+
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings
1912+
{
1913+
ClassStyle = CSharpClassStyle.Poco
1914+
});
1915+
1916+
//// Act
1917+
var output = generator.GenerateFile("PersonAddress");
1918+
1919+
//// Assert
1920+
Assert.Contains("IDictionary<string, object> AdditionalProperties2\n", output);
18931921
}
18941922

18951923
[Fact]

src/NJsonSchema.CodeGeneration.CSharp/CSharpGenerator.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using System.Collections.Generic;
1010
using System.Linq;
1111
using NJsonSchema.CodeGeneration.CSharp.Models;
12-
using NJsonSchema.CodeGeneration.Models;
1312

1413
namespace NJsonSchema.CodeGeneration.CSharp
1514
{
@@ -116,17 +115,16 @@ private CodeArtifact GenerateClass(JsonSchema schema, string typeName)
116115
{
117116
var model = new ClassTemplateModel(typeName, Settings, _resolver, schema, RootObject);
118117

119-
RenamePropertyWithSameNameAsClass(typeName, model.Properties);
118+
RenamePropertyWithSameNameAsClass(typeName, model._properties);
120119

121120
var template = Settings.TemplateFactory.CreateTemplate("CSharp", "Class", model);
122121
return new CodeArtifact(typeName, model.BaseClassName, CodeArtifactType.Class, CodeArtifactLanguage.CSharp, CodeArtifactCategory.Contract, template);
123122
}
124123

125-
private static void RenamePropertyWithSameNameAsClass(string typeName, IEnumerable<PropertyModel> properties)
124+
private static void RenamePropertyWithSameNameAsClass(string typeName, List<PropertyModel> properties)
126125
{
127-
var propertyModels = properties as PropertyModel[] ?? properties.ToArray();
128126
PropertyModel? propertyWithSameNameAsClass = null;
129-
foreach (var p in propertyModels)
127+
foreach (var p in properties)
130128
{
131129
if (p.PropertyName == typeName)
132130
{
@@ -139,12 +137,12 @@ private static void RenamePropertyWithSameNameAsClass(string typeName, IEnumerab
139137
{
140138
var number = 1;
141139
var candidate = typeName + number;
142-
while (propertyModels.Any(p => p.PropertyName == candidate))
140+
while (properties.Exists(p => p.PropertyName == candidate))
143141
{
144142
number++;
145143
}
146144

147-
propertyWithSameNameAsClass.PropertyName = propertyWithSameNameAsClass.PropertyName + number;
145+
propertyWithSameNameAsClass.PropertyName += number;
148146
}
149147
}
150148

src/NJsonSchema.CodeGeneration.CSharp/Models/ClassTemplateModel.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public class ClassTemplateModel : ClassTemplateModelBase
1818
private readonly CSharpTypeResolver _resolver;
1919
private readonly JsonSchema _schema;
2020
private readonly CSharpGeneratorSettings _settings;
21+
internal readonly List<PropertyModel> _properties;
22+
private readonly List<PropertyModel> _allProperties;
2123

2224
/// <summary>Initializes a new instance of the <see cref="ClassTemplateModel"/> class.</summary>
2325
/// <param name="typeName">Name of the type.</param>
@@ -34,19 +36,32 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings,
3436
_settings = settings;
3537

3638
ClassName = typeName;
37-
Properties = _schema.ActualProperties.Values
38-
.Where(p => !p.IsInheritanceDiscriminator)
39-
.Select(property => new PropertyModel(this, property, _resolver, _settings))
40-
.ToArray();
39+
40+
AdditionalPropertiesPropertyName = "AdditionalProperties";
41+
var actualProperties = _schema.ActualProperties;
42+
_properties = new List<PropertyModel>(actualProperties.Count);
43+
foreach (var property in actualProperties.Values)
44+
{
45+
if (!property.IsInheritanceDiscriminator)
46+
{
47+
_properties.Add(new PropertyModel(this, property, _resolver, _settings));
48+
if (property.Name == AdditionalPropertiesPropertyName)
49+
{
50+
AdditionalPropertiesPropertyName += "2";
51+
}
52+
}
53+
}
4154

4255
if (schema.InheritedSchema != null)
4356
{
4457
BaseClass = new ClassTemplateModel(BaseClassName!, settings, resolver, schema.InheritedSchema, rootObject);
45-
AllProperties = Properties.Concat(BaseClass.AllProperties).ToArray();
58+
_allProperties = new List<PropertyModel>(_properties.Count + BaseClass._allProperties.Count);
59+
_allProperties.AddRange(_properties);
60+
_allProperties.AddRange(BaseClass._allProperties);
4661
}
4762
else
4863
{
49-
AllProperties = Properties;
64+
_allProperties = _properties;
5065
}
5166
}
5267

@@ -85,11 +100,14 @@ public ClassTemplateModel(string typeName, CSharpGeneratorSettings settings,
85100
// _schema.AdditionalPropertiesSchema.IsNullable(_settings.SchemaType),
86101
// string.Empty) : null;
87102

103+
/// <summary>Gets property name for the additional properties.</summary>
104+
public string? AdditionalPropertiesPropertyName { get; private set; }
105+
88106
/// <summary>Gets the property models.</summary>
89-
public IEnumerable<PropertyModel> Properties { get; }
107+
public IEnumerable<PropertyModel> Properties => _properties;
90108

91109
/// <summary>Gets the property models with inherited properties.</summary>
92-
public IEnumerable<PropertyModel> AllProperties { get; }
110+
public IEnumerable<PropertyModel> AllProperties => _allProperties;
93111

94112
/// <summary>Gets a value indicating whether the class has description.</summary>
95113
public bool HasDescription => !(_schema is JsonSchemaProperty) &&

src/NJsonSchema.CodeGeneration.CSharp/Templates/Class.liquid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@
130130
{%- else -%}
131131
[Newtonsoft.Json.JsonExtensionData]
132132
{%- endif -%}
133-
public System.Collections.Generic.IDictionary<string, {{ AdditionalPropertiesType }}> AdditionalProperties
133+
public System.Collections.Generic.IDictionary<string, {{ AdditionalPropertiesType }}> {{ AdditionalPropertiesPropertyName }}
134134
{
135135
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, {{ AdditionalPropertiesType }}>()); }
136136
{{PropertySetterAccessModifier}}set { _additionalProperties = value; }

0 commit comments

Comments
 (0)