Skip to content

Commit 7142235

Browse files
authored
fix: csharp enum de/serializer (#356)
1 parent 30249e3 commit 7142235

File tree

3 files changed

+197
-115
lines changed

3 files changed

+197
-115
lines changed

src/generators/csharp/presets/JsonSerializerPreset.ts

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
import { CSharpRenderer } from '../CSharpRenderer';
22
import { CSharpPreset } from '../CSharpPreset';
3-
import { getUniquePropertyName, DefaultPropertyNames, FormatHelpers } from '../../../helpers';
4-
import { CommonModel } from '../../../models';
3+
import { getUniquePropertyName, DefaultPropertyNames, FormatHelpers, TypeHelpers, ModelKind } from '../../../helpers';
4+
import { CommonInputModel, CommonModel } from '../../../models';
55

6-
function renderSerializeAdditionalProperties(model: CommonModel, renderer: CSharpRenderer) {
6+
function renderSerializeProperty(modelInstanceVariable: string, model: CommonModel, inputModel: CommonInputModel) {
7+
let value = modelInstanceVariable;
8+
if (model.$ref) {
9+
const resolvedModel = inputModel.models[model.$ref];
10+
const propertyModelKind = TypeHelpers.extractKind(resolvedModel);
11+
//Referenced enums is the only one who need custom serialization
12+
if (propertyModelKind === ModelKind.ENUM) {
13+
value = `${value}.GetValue()`;
14+
}
15+
}
16+
return `JsonSerializer.Serialize(writer, ${value});`;
17+
}
18+
19+
function renderSerializeAdditionalProperties(model: CommonModel, renderer: CSharpRenderer, inputModel: CommonInputModel) {
720
const serializeAdditionalProperties = '';
821
if (model.additionalProperties !== undefined) {
922
let additionalPropertyName = getUniquePropertyName(model, DefaultPropertyNames.additionalProperties);
@@ -19,28 +32,29 @@ if (value.AdditionalProperties != null) {
1932
}
2033
// write property name and let the serializer serialize the value itself
2134
writer.WritePropertyName(additionalProperty.Key);
22-
JsonSerializer.Serialize(writer, additionalProperty.Value);
35+
${renderSerializeProperty('additionalProperty.Value', model.additionalProperties, inputModel)}
2336
}
2437
}`;
2538
}
2639
return serializeAdditionalProperties;
2740
}
2841

29-
function renderSerializeProperties(model: CommonModel, renderer: CSharpRenderer) {
42+
function renderSerializeProperties(model: CommonModel, renderer: CSharpRenderer, inputModel: CommonInputModel) {
3043
let serializeProperties = '';
3144
if (model.properties !== undefined) {
3245
for (const [propertyName, propertyModel] of Object.entries(model.properties)) {
3346
const formattedPropertyName = FormatHelpers.upperFirst(renderer.nameProperty(propertyName, propertyModel));
34-
serializeProperties += `if(value.${formattedPropertyName} != null) {
47+
const modelInstanceVariable = `value.${formattedPropertyName}`;
48+
serializeProperties += `if(${modelInstanceVariable} != null) {
3549
// write property name and let the serializer serialize the value itself
3650
writer.WritePropertyName("${propertyName}");
37-
JsonSerializer.Serialize(writer, value.${formattedPropertyName});
51+
${renderSerializeProperty(modelInstanceVariable, propertyModel, inputModel)}
3852
}\n`;
3953
}
4054
}
4155
return serializeProperties;
4256
}
43-
function renderSerializePatternProperties(model: CommonModel, renderer: CSharpRenderer) {
57+
function renderSerializePatternProperties(model: CommonModel, renderer: CSharpRenderer, inputModel: CommonInputModel) {
4458
let serializePatternProperties = '';
4559
if (model.patternProperties !== undefined) {
4660
for (const [pattern, patternModel] of Object.entries(model.patternProperties)) {
@@ -57,7 +71,7 @@ if(value.${patternPropertyName} != null) {
5771
}
5872
// write property name and let the serializer serialize the value itself
5973
writer.WritePropertyName(patternProp.Key);
60-
JsonSerializer.Serialize(writer, patternProp.Value);
74+
${renderSerializeProperty('patternProp.Value', patternModel, inputModel)}
6175
}
6276
}`;
6377
}
@@ -87,14 +101,15 @@ function renderPropertiesList(model: CommonModel, renderer: CSharpRenderer) {
87101
/**
88102
* Render `serialize` function based on model
89103
*/
90-
function renderSerialize({ renderer, model }: {
104+
function renderSerialize({ renderer, model, inputModel }: {
91105
renderer: CSharpRenderer,
92106
model: CommonModel,
107+
inputModel: CommonInputModel
93108
}): string {
94109
const formattedModelName = renderer.nameType(model.$id);
95-
const serializeProperties = renderSerializeProperties(model, renderer);
96-
const serializePatternProperties = renderSerializePatternProperties(model, renderer);
97-
const serializeAdditionalProperties = renderSerializeAdditionalProperties(model, renderer);
110+
const serializeProperties = renderSerializeProperties(model, renderer, inputModel);
111+
const serializePatternProperties = renderSerializePatternProperties(model, renderer, inputModel);
112+
const serializeAdditionalProperties = renderSerializeAdditionalProperties(model, renderer, inputModel);
98113
const propertiesList = renderPropertiesList(model, renderer);
99114

100115
return `public override void Write(Utf8JsonWriter writer, ${formattedModelName} value, JsonSerializerOptions options)
@@ -118,22 +133,34 @@ ${renderer.indent(serializeAdditionalProperties)}
118133
}`;
119134
}
120135

121-
function renderDeserializeProperties(model: CommonModel, renderer: CSharpRenderer) {
136+
function renderDeserializeProperty(type: string, model: CommonModel, inputModel: CommonInputModel) {
137+
if (model.$ref) {
138+
const resolvedModel = inputModel.models[model.$ref];
139+
const propertyModelKind = TypeHelpers.extractKind(resolvedModel);
140+
//Referenced enums is the only one who need custom serialization
141+
if (propertyModelKind === ModelKind.ENUM) {
142+
return `${type}Extension.To${type}(JsonSerializer.Deserialize<dynamic>(ref reader, options))`;
143+
}
144+
}
145+
return `JsonSerializer.Deserialize<${type}>(ref reader, options)`;
146+
}
147+
148+
function renderDeserializeProperties(model: CommonModel, renderer: CSharpRenderer, inputModel: CommonInputModel) {
122149
const propertyEntries = Object.entries(model.properties || {});
123150
const deserializeProperties = propertyEntries.map(([prop, propModel]) => {
124151
const formattedPropertyName = FormatHelpers.upperFirst(renderer.nameProperty(prop, propModel));
125152
const propertyModelType = renderer.renderType(propModel);
126153
return `if (propertyName == "${prop}")
127154
{
128-
var value = JsonSerializer.Deserialize<${propertyModelType}>(ref reader, options);
155+
var value = ${renderDeserializeProperty(propertyModelType, propModel, inputModel)};
129156
instance.${formattedPropertyName} = value;
130157
continue;
131158
}`;
132159
});
133160
return deserializeProperties.join('\n');
134161
}
135162

136-
function renderDeserializePatternProperties(model: CommonModel, renderer: CSharpRenderer) {
163+
function renderDeserializePatternProperties(model: CommonModel, renderer: CSharpRenderer, inputModel: CommonInputModel) {
137164
if (model.patternProperties === undefined) {
138165
return '';
139166
}
@@ -145,38 +172,39 @@ function renderDeserializePatternProperties(model: CommonModel, renderer: CSharp
145172
var match = Regex.Match(propertyName, @"${pattern}");
146173
if (match.Success)
147174
{
148-
var deserializedValue = JsonSerializer.Deserialize<${patternPropertyType}>(ref reader, options);
175+
var deserializedValue = ${renderDeserializeProperty(patternPropertyType, patternModel, inputModel)};
149176
instance.${patternPropertyName}.Add(propertyName, deserializedValue);
150177
continue;
151178
}`;
152179
});
153180
return patternProperties.join('\n');
154181
}
155182

156-
function renderDeserializeAdditionalProperties(model: CommonModel, renderer: CSharpRenderer) {
183+
function renderDeserializeAdditionalProperties(model: CommonModel, renderer: CSharpRenderer, inputModel: CommonInputModel) {
157184
if (model.additionalProperties === undefined) {
158185
return '';
159186
}
160187
let additionalPropertyName = getUniquePropertyName(model, DefaultPropertyNames.additionalProperties);
161188
additionalPropertyName = FormatHelpers.upperFirst(renderer.nameProperty(additionalPropertyName, model.additionalProperties));
162189
const additionalPropertyType = renderer.renderType(model.additionalProperties);
163190
return `if(instance.${additionalPropertyName} == null) { instance.${additionalPropertyName} = new Dictionary<string, ${additionalPropertyType}>(); }
164-
var deserializedValue = JsonSerializer.Deserialize<${additionalPropertyType}>(ref reader, options);
191+
var deserializedValue = ${renderDeserializeProperty(additionalPropertyType, model.additionalProperties, inputModel)};
165192
instance.${additionalPropertyName}.Add(propertyName, deserializedValue);
166193
continue;`;
167194
}
168195

169196
/**
170197
* Render `deserialize` function based on model
171198
*/
172-
function renderDeserialize({ renderer, model }: {
199+
function renderDeserialize({ renderer, model, inputModel }: {
173200
renderer: CSharpRenderer,
174201
model: CommonModel,
202+
inputModel: CommonInputModel
175203
}): string {
176204
const formattedModelName = renderer.nameType(model.$id);
177-
const deserializeProperties = renderDeserializeProperties(model, renderer);
178-
const deserializePatternProperties = renderDeserializePatternProperties(model, renderer);
179-
const deserializeAdditionalProperties = renderDeserializeAdditionalProperties(model, renderer);
205+
const deserializeProperties = renderDeserializeProperties(model, renderer, inputModel);
206+
const deserializePatternProperties = renderDeserializePatternProperties(model, renderer, inputModel);
207+
const deserializeAdditionalProperties = renderDeserializeAdditionalProperties(model, renderer, inputModel);
180208
return `public override ${formattedModelName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
181209
{
182210
if (reader.TokenType != JsonTokenType.StartObject)
@@ -218,14 +246,14 @@ ${renderer.indent(deserializeAdditionalProperties, 4)}
218246
*/
219247
export const CSHARP_JSON_SERIALIZER_PRESET: CSharpPreset = {
220248
class: {
221-
self({ renderer, model, content }) {
249+
self({ renderer, model, content, inputModel}) {
222250
renderer.addDependency('using System.Text.Json;');
223251
renderer.addDependency('using System.Text.Json.Serialization;');
224252
renderer.addDependency('using System.Text.RegularExpressions;');
225253

226254
const formattedModelName = renderer.nameType(model.$id);
227-
const deserialize = renderDeserialize({renderer, model});
228-
const serialize = renderSerialize({renderer, model});
255+
const deserialize = renderDeserialize({renderer, model, inputModel});
256+
const serialize = renderSerialize({renderer, model, inputModel});
229257

230258
return `[JsonConverter(typeof(${formattedModelName}Converter))]
231259
${content}

test/generators/csharp/presets/JsonSerializerPreset.spec.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const doc = {
77
properties: {
88
'string prop': { type: 'string' },
99
numberProp: { type: 'number' },
10+
enumProp: { $id: 'EnumTest', enum: ['Some enum String', true, {test: 'test'}, 2]},
1011
objectProp: { type: 'object', $id: 'NestedTest', properties: {stringProp: { type: 'string' }}}
1112
},
1213
patternProperties: {
@@ -23,13 +24,15 @@ describe('JSON serializer preset', () => {
2324
]
2425
});
2526
const inputModel = await generator.process(doc);
26-
const testModel = inputModel.models['Test'];
2727
const nestedTestModel = inputModel.models['NestedTest'];
28+
const testModel = inputModel.models['Test'];
29+
const enumModel = inputModel.models['EnumTest'];
2830

29-
const testClass = await generator.renderClass(testModel, inputModel);
3031
const nestedTestClass = await generator.renderClass(nestedTestModel, inputModel);
31-
32-
expect(testClass.result).toMatchSnapshot();
32+
const testClass = await generator.renderClass(testModel, inputModel);
33+
const enumEnum = await generator.renderEnum(enumModel, inputModel);
3334
expect(nestedTestClass.result).toMatchSnapshot();
35+
expect(testClass.result).toMatchSnapshot();
36+
expect(enumEnum.result).toMatchSnapshot();
3437
});
3538
});

0 commit comments

Comments
 (0)