mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-07-22 09:25:26 +00:00
Added System.Text.Json ArrayConverter Write implementation
This commit is contained in:
parent
917d060827
commit
94cb2caf0b
@ -5,6 +5,8 @@ using NUnit.Framework;
|
|||||||
using System;
|
using System;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using NUnit.Framework.Legacy;
|
using NUnit.Framework.Legacy;
|
||||||
|
using CryptoExchange.Net.Converters;
|
||||||
|
using CryptoExchange.Net.Testing.Comparers;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.UnitTests
|
namespace CryptoExchange.Net.UnitTests
|
||||||
{
|
{
|
||||||
@ -242,6 +244,44 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
var result = JsonSerializer.Deserialize<STJDecimalObject>("{ \"test\": " + value + "}");
|
var result = JsonSerializer.Deserialize<STJDecimalObject>("{ \"test\": " + value + "}");
|
||||||
Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected));
|
Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test()]
|
||||||
|
public void TestArrayConverter()
|
||||||
|
{
|
||||||
|
var data = new Test()
|
||||||
|
{
|
||||||
|
Prop1 = 2,
|
||||||
|
Prop2 = null,
|
||||||
|
Prop3 = "123",
|
||||||
|
Prop3Again = "123",
|
||||||
|
Prop4 = null,
|
||||||
|
Prop5 = new Test2
|
||||||
|
{
|
||||||
|
Prop21 = 3,
|
||||||
|
Prop22 = "456"
|
||||||
|
},
|
||||||
|
Prop6 = new Test3
|
||||||
|
{
|
||||||
|
Prop31 = 4,
|
||||||
|
Prop32 = "789"
|
||||||
|
},
|
||||||
|
Prop7 = TestEnum.Two
|
||||||
|
};
|
||||||
|
|
||||||
|
var serialized = JsonSerializer.Serialize(data);
|
||||||
|
var deserialized = JsonSerializer.Deserialize<Test>(serialized);
|
||||||
|
|
||||||
|
Assert.That(deserialized.Prop1, Is.EqualTo(2));
|
||||||
|
Assert.That(deserialized.Prop2, Is.Null);
|
||||||
|
Assert.That(deserialized.Prop3, Is.EqualTo("123"));
|
||||||
|
Assert.That(deserialized.Prop3Again, Is.EqualTo("123"));
|
||||||
|
Assert.That(deserialized.Prop4, Is.Null);
|
||||||
|
Assert.That(deserialized.Prop5.Prop21, Is.EqualTo(3));
|
||||||
|
Assert.That(deserialized.Prop5.Prop22, Is.EqualTo("456"));
|
||||||
|
Assert.That(deserialized.Prop6.Prop31, Is.EqualTo(4));
|
||||||
|
Assert.That(deserialized.Prop6.Prop32, Is.EqualTo("789"));
|
||||||
|
Assert.That(deserialized.Prop7, Is.EqualTo(TestEnum.Two));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class STJDecimalObject
|
public class STJDecimalObject
|
||||||
@ -281,4 +321,42 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
[JsonConverter(typeof(BoolConverter))]
|
[JsonConverter(typeof(BoolConverter))]
|
||||||
public bool Value { get; set; }
|
public bool Value { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[JsonConverter(typeof(ArrayConverter))]
|
||||||
|
record Test
|
||||||
|
{
|
||||||
|
[ArrayProperty(0)]
|
||||||
|
public int Prop1 { get; set; }
|
||||||
|
[ArrayProperty(1)]
|
||||||
|
public int? Prop2 { get; set; }
|
||||||
|
[ArrayProperty(2)]
|
||||||
|
public string Prop3 { get; set; }
|
||||||
|
[ArrayProperty(2)]
|
||||||
|
public string Prop3Again { get; set; }
|
||||||
|
[ArrayProperty(3)]
|
||||||
|
public string Prop4 { get; set; }
|
||||||
|
[ArrayProperty(4)]
|
||||||
|
public Test2 Prop5 { get; set; }
|
||||||
|
[ArrayProperty(5)]
|
||||||
|
public Test3 Prop6 { get; set; }
|
||||||
|
[ArrayProperty(6), JsonConverter(typeof(EnumConverter))]
|
||||||
|
public TestEnum? Prop7 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonConverter(typeof(ArrayConverter))]
|
||||||
|
record Test2
|
||||||
|
{
|
||||||
|
[ArrayProperty(0)]
|
||||||
|
public int Prop21 { get; set; }
|
||||||
|
[ArrayProperty(1)]
|
||||||
|
public string Prop22 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
record Test3
|
||||||
|
{
|
||||||
|
[JsonPropertyName("prop31")]
|
||||||
|
public int Prop31 { get; set; }
|
||||||
|
[JsonPropertyName("prop32")]
|
||||||
|
public string Prop32 { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,63 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
// TODO
|
if (value == null)
|
||||||
throw new NotImplementedException();
|
{
|
||||||
|
writer.WriteNullValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteStartArray();
|
||||||
|
|
||||||
|
var valueType = value.GetType();
|
||||||
|
if (!_typeAttributesCache.TryGetValue(valueType, out var typeAttributes))
|
||||||
|
typeAttributes = CacheTypeAttributes(valueType);
|
||||||
|
|
||||||
|
var ordered = typeAttributes.Where(x => x.ArrayProperty != null).OrderBy(p => p.ArrayProperty.Index);
|
||||||
|
var last = -1;
|
||||||
|
foreach (var prop in ordered)
|
||||||
|
{
|
||||||
|
if (prop.ArrayProperty.Index == last)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
while (prop.ArrayProperty.Index != last + 1)
|
||||||
|
{
|
||||||
|
writer.WriteNullValue();
|
||||||
|
last += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = prop.ArrayProperty.Index;
|
||||||
|
|
||||||
|
var objValue = prop.PropertyInfo.GetValue(value);
|
||||||
|
if (objValue == null)
|
||||||
|
{
|
||||||
|
writer.WriteNullValue();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonSerializerOptions? typeOptions = null;
|
||||||
|
if (prop.JsonConverterType != null)
|
||||||
|
{
|
||||||
|
var converter = (JsonConverter)Activator.CreateInstance(prop.JsonConverterType);
|
||||||
|
typeOptions = new JsonSerializerOptions();
|
||||||
|
typeOptions.Converters.Clear();
|
||||||
|
typeOptions.Converters.Add(converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop.JsonConverterType == null && IsSimple(prop.PropertyInfo.PropertyType))
|
||||||
|
{
|
||||||
|
if (prop.PropertyInfo.PropertyType == typeof(string))
|
||||||
|
writer.WriteStringValue(Convert.ToString(objValue, CultureInfo.InvariantCulture));
|
||||||
|
else
|
||||||
|
writer.WriteRawValue(Convert.ToString(objValue, CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JsonSerializer.Serialize(writer, objValue, typeOptions ?? options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -56,6 +111,19 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
return (T)ParseObject(ref reader, result, typeToConvert);
|
return (T)ParseObject(ref reader, result, typeToConvert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsSimple(Type type)
|
||||||
|
{
|
||||||
|
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||||
|
{
|
||||||
|
// nullable type, check if the nested type is simple.
|
||||||
|
return IsSimple(type.GetGenericArguments()[0]);
|
||||||
|
}
|
||||||
|
return type.IsPrimitive
|
||||||
|
|| type.IsEnum
|
||||||
|
|| type == typeof(string)
|
||||||
|
|| type == typeof(decimal);
|
||||||
|
}
|
||||||
|
|
||||||
private static List<ArrayPropertyInfo> CacheTypeAttributes(Type type)
|
private static List<ArrayPropertyInfo> CacheTypeAttributes(Type type)
|
||||||
{
|
{
|
||||||
var attributes = new List<ArrayPropertyInfo>();
|
var attributes = new List<ArrayPropertyInfo>();
|
||||||
@ -71,7 +139,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
ArrayProperty = att,
|
ArrayProperty = att,
|
||||||
PropertyInfo = property,
|
PropertyInfo = property,
|
||||||
DefaultDeserialization = property.GetCustomAttribute<JsonConversionAttribute>() != null,
|
DefaultDeserialization = property.GetCustomAttribute<JsonConversionAttribute>() != null,
|
||||||
JsonConverterType = property.GetCustomAttribute<JsonConverterAttribute>()?.ConverterType,
|
JsonConverterType = property.GetCustomAttribute<JsonConverterAttribute>()?.ConverterType ?? property.PropertyType.GetCustomAttribute<JsonConverterAttribute>()?.ConverterType,
|
||||||
TargetType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType
|
TargetType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -126,6 +194,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
JsonTokenType.True => true,
|
JsonTokenType.True => true,
|
||||||
JsonTokenType.String => reader.GetString(),
|
JsonTokenType.String => reader.GetString(),
|
||||||
JsonTokenType.Number => reader.GetDecimal(),
|
JsonTokenType.Number => reader.GetDecimal(),
|
||||||
|
JsonTokenType.StartObject => JsonSerializer.Deserialize(ref reader, attribute.TargetType),
|
||||||
_ => throw new NotImplementedException($"Array deserialization of type {reader.TokenType} not supported"),
|
_ => throw new NotImplementedException($"Array deserialization of type {reader.TokenType} not supported"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user