Skip to content

fix: (.NET) Improve json De/serialization #1138

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,60 @@ namespace {{ spec.title | caseUcfirst }}.Converters
{
public class ObjectToInferredTypesConverter : JsonConverter<object>
{
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
using (JsonDocument document = JsonDocument.ParseValue(ref reader))
{
case JsonTokenType.True:
return true;
case JsonTokenType.False:
return false;
case JsonTokenType.Number:
if (reader.TryGetInt64(out long l))
return ConvertElement(document.RootElement);
}
}

private object? ConvertElement(JsonElement element)
{
switch (element.ValueKind)
{
case JsonValueKind.Object:
var dictionary = new Dictionary<string, object?>();
foreach (var property in element.EnumerateObject())
{
return l;
dictionary[property.Name] = ConvertElement(property.Value);
}
return dictionary;

case JsonValueKind.Array:
var list = new List<object?>();
foreach (var item in element.EnumerateArray())
{
list.Add(ConvertElement(item));
}
return reader.GetDouble();
case JsonTokenType.String:
if (reader.TryGetDateTime(out DateTime datetime))
return list;

case JsonValueKind.String:
if (element.TryGetDateTime(out DateTime datetime))
{
return datetime;
}
return reader.GetString()!;
case JsonTokenType.StartObject:
return JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options)!;
case JsonTokenType.StartArray:
return JsonSerializer.Deserialize<object[]>(ref reader, options)!;
return element.GetString();

case JsonValueKind.Number:
if (element.TryGetInt64(out long l))
{
return l;
}
return element.GetDouble();

case JsonValueKind.True:
return true;

case JsonValueKind.False:
return false;

case JsonValueKind.Null:
case JsonValueKind.Undefined:
return null;

default:
return JsonDocument.ParseValue(ref reader).RootElement.Clone();
throw new JsonException($"Unsupported JsonValueKind: {element.ValueKind}");
}
}

Expand Down
17 changes: 6 additions & 11 deletions templates/dotnet/Package/Models/Model.cs.twig
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{% macro sub_schema(property) %}{% if property.sub_schema %}{% if property.type == 'array' %}List<{{property.sub_schema | caseUcfirst | overrideIdentifier}}>{% else %}{{property.sub_schema | caseUcfirst | overrideIdentifier}}{% endif %}{% else %}{{property | typeName}}{% endif %}{% if not property.required %}?{% endif %}{% endmacro %}
{% macro property_name(definition, property) %}{{ property.name | caseUcfirst | removeDollarSign | escapeKeyword }}{% endmacro %}

using System;
using System.Linq;
using System.Collections.Generic;
Expand Down Expand Up @@ -42,25 +41,21 @@ namespace {{ spec.title | caseUcfirst }}.Models
{{ property.name | caseCamel | escapeKeyword | removeDollarSign }}:{{' '}}
{%- if property.sub_schema %}
{%- if property.type == 'array' -%}
map["{{ property.name }}"] is JsonElement jsonArray{{ loop.index }} ? jsonArray{{ loop.index }}.Deserialize<List<Dictionary<string, object>>>()!.Select(it => {{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: it)).ToList() : ((IEnumerable<Dictionary<string, object>>)map["{{ property.name }}"]).Select(it => {{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: it)).ToList()
((IEnumerable<object>)map["{{ property.name }}"]).Select(it => {{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: (Dictionary<string, object>)it)).ToList()
{%- else -%}
{{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: map["{{ property.name }}"] is JsonElement jsonObj{{ loop.index }} ? jsonObj{{ loop.index }}.Deserialize<Dictionary<string, object>>()! : (Dictionary<string, object>)map["{{ property.name }}"])
{{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: (Dictionary<string, object>)map["{{ property.name }}"])
{%- endif %}
{%- else %}
{%- if property.type == 'array' -%}
map["{{ property.name }}"] is JsonElement jsonArrayProp{{ loop.index }} ? jsonArrayProp{{ loop.index }}.Deserialize<{{ property | typeName }}>()! : ({{ property | typeName }})map["{{ property.name }}"]
((IEnumerable<object>)map["{{ property.name }}"]).Select(x => {% if property.items.type == "string" %}x?.ToString(){% elseif property.items.type == "integer" %}{% if not property.required %}x == null ? (long?)null : {% endif %}Convert.ToInt64(x){% elseif property.items.type == "number" %}{% if not property.required %}x == null ? (double?)null : {% endif %}Convert.ToDouble(x){% elseif property.items.type == "boolean" %}{% if not property.required %}x == null ? (bool?)null : {% endif %}(bool)x{% else %}x{% endif %}).{% if property.items.type == "string" and property.required %}Where(x => x != null).{% endif %}ToList()!
{%- else %}
{%- if property.type == "integer" or property.type == "number" %}
{%- if not property.required -%}map["{{ property.name }}"] == null ? null :{% endif %}Convert.To{% if property.type == "integer" %}Int64{% else %}Double{% endif %}(map["{{ property.name }}"])
{%- if not property.required -%}map["{{ property.name }}"] == null ? null : {% endif %}Convert.To{% if property.type == "integer" %}Int64{% else %}Double{% endif %}(map["{{ property.name }}"])
{%- else %}
{%- if property.type == "boolean" -%}
({{ property | typeName }}{% if not property.required %}?{% endif %})map["{{ property.name }}"]
{%- else %}
{%- if not property.required -%}
map.TryGetValue("{{ property.name }}", out var {{ property.name | caseCamel | escapeKeyword | removeDollarSign }}) ? {{ property.name | caseCamel | escapeKeyword | removeDollarSign }}?.ToString() : null
{%- else -%}
map["{{ property.name }}"].ToString()
{%- endif %}
{%- else -%}
map["{{ property.name }}"]{% if not property.required %}?{% endif %}.ToString()
{%- endif %}
{%~ endif %}
{%~ endif %}
Expand Down