diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 45489aa1..bb942cdb 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,7 +3,7 @@ Sebastien Ros Sebastien Ros - net6.0 + net7.0 true portable https://github.com/sebastienros/yessql diff --git a/src/YesSql.Abstractions/IContentSerializer.cs b/src/YesSql.Abstractions/IContentSerializer.cs index 8ddd6b1c..eb548f97 100644 --- a/src/YesSql.Abstractions/IContentSerializer.cs +++ b/src/YesSql.Abstractions/IContentSerializer.cs @@ -22,12 +22,5 @@ public interface IContentSerializer /// The type of the object to deserialize. /// The deserialized object. object Deserialize(string content, Type type); - - /// - /// Deserializes an object to a dynamic instance. - /// - /// The instance representing the object to deserialize. - /// The deserialized object. - dynamic DeserializeDynamic(string content); } } diff --git a/src/YesSql.Core/Configuration.cs b/src/YesSql.Core/Configuration.cs index 4fed7c32..8d432302 100644 --- a/src/YesSql.Core/Configuration.cs +++ b/src/YesSql.Core/Configuration.cs @@ -15,7 +15,7 @@ public Configuration() { IdentifierAccessorFactory = new PropertyAccessorFactory("Id"); VersionAccessorFactory = new PropertyAccessorFactory("Version"); - ContentSerializer = new JsonContentSerializer(); + ContentSerializer = new DefaultContentSerializer(); IdGenerator = new DefaultIdGenerator(); IsolationLevel = IsolationLevel.ReadCommitted; TablePrefix = ""; diff --git a/src/YesSql.Core/Serialization/DefaultContentSerializer.cs b/src/YesSql.Core/Serialization/DefaultContentSerializer.cs new file mode 100644 index 00000000..3515a57e --- /dev/null +++ b/src/YesSql.Core/Serialization/DefaultContentSerializer.cs @@ -0,0 +1,34 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace YesSql.Serialization +{ + public class DefaultContentSerializer : IContentSerializer + { + private readonly JsonSerializerOptions _options; + + public DefaultContentSerializer() + { + _options = new(); + _options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + _options.Converters.Add(UtcDateTimeJsonConverter.Instance); + _options.Converters.Add(DynamicJsonConverter.Instance); + } + + public DefaultContentSerializer(JsonSerializerOptions options) + { + _options = options; + } + + public object Deserialize(string content, Type type) + { + return JsonSerializer.Deserialize(content, type, _options); + } + + public string Serialize(object item) + { + return JsonSerializer.Serialize(item, _options); + } + } +} diff --git a/src/YesSql.Core/Serialization/DynamicJsonConverter.cs b/src/YesSql.Core/Serialization/DynamicJsonConverter.cs new file mode 100644 index 00000000..e67285ec --- /dev/null +++ b/src/YesSql.Core/Serialization/DynamicJsonConverter.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace YesSql.Serialization +{ + public class DynamicJsonConverter : JsonConverter + { + public static readonly DynamicJsonConverter Instance = new(); + + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + switch (reader.TokenType) + { + case JsonTokenType.Null: + return null; + case JsonTokenType.False: + return false; + case JsonTokenType.True: + return true; + case JsonTokenType.String: + return reader.GetString(); + case JsonTokenType.Number: + { + if (reader.TryGetInt32(out var i)) + return i; + if (reader.TryGetInt64(out var l)) + return l; + // BigInteger could be added here. + if (reader.TryGetDouble(out var d)) + return d; + + throw new JsonException("Cannot parse number"); + } + case JsonTokenType.StartArray: + { + var list = new List(); + while (reader.Read()) + { + switch (reader.TokenType) + { + default: + list.Add(Read(ref reader, typeof(object), options)); + break; + case JsonTokenType.EndArray: + return list; + } + } + throw new JsonException(); + } + case JsonTokenType.StartObject: + IDictionary dict = new ExpandoObject(); + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonTokenType.EndObject: + return dict; + case JsonTokenType.PropertyName: + var key = reader.GetString(); + reader.Read(); + dict[key] = Read(ref reader, typeof(object), options); + break; + default: + throw new JsonException(); + } + } + throw new JsonException(); + default: + throw new JsonException(string.Format("Unknown token {0}", reader.TokenType)); + } + } + + public override void Write( + Utf8JsonWriter writer, + object objectToWrite, + JsonSerializerOptions options) => + JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options); + } +} diff --git a/src/YesSql.Core/Serialization/JsonContentSerializer.cs b/src/YesSql.Core/Serialization/JsonContentSerializer.cs deleted file mode 100644 index bc40cff5..00000000 --- a/src/YesSql.Core/Serialization/JsonContentSerializer.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Newtonsoft.Json; -using System; - -namespace YesSql.Serialization -{ - public class JsonContentSerializer : IContentSerializer - { - private readonly static JsonSerializerSettings _jsonSettings = new() - { - TypeNameHandling = TypeNameHandling.Auto, - DateTimeZoneHandling = DateTimeZoneHandling.Utc, - NullValueHandling = NullValueHandling.Ignore - }; - - public object Deserialize(string content, Type type) - { - return JsonConvert.DeserializeObject(content, type, _jsonSettings); - } - - public dynamic DeserializeDynamic(string content) - { - return JsonConvert.DeserializeObject(content, _jsonSettings); - } - - public string Serialize(object item) - { - return JsonConvert.SerializeObject(item, _jsonSettings); - } - } -} diff --git a/src/YesSql.Core/Serialization/UtcDateTimeJsonConverter.cs b/src/YesSql.Core/Serialization/UtcDateTimeJsonConverter.cs new file mode 100644 index 00000000..0011c4e9 --- /dev/null +++ b/src/YesSql.Core/Serialization/UtcDateTimeJsonConverter.cs @@ -0,0 +1,29 @@ +using System; +using System.Diagnostics; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace YesSql.Serialization +{ + public class UtcDateTimeJsonConverter : JsonConverter + { + public static readonly UtcDateTimeJsonConverter Instance = new(); + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + Debug.Assert(typeToConvert == typeof(DateTime)); + + if (!reader.TryGetDateTime(out DateTime value)) + { + value = DateTime.UtcNow; + } + + return value; + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToUniversalTime()); + } + } +} diff --git a/src/YesSql.Core/YesSql.Core.csproj b/src/YesSql.Core/YesSql.Core.csproj index c6061e19..25ac38c5 100644 --- a/src/YesSql.Core/YesSql.Core.csproj +++ b/src/YesSql.Core/YesSql.Core.csproj @@ -5,7 +5,6 @@ - diff --git a/test/YesSql.Tests/Models/Animal.cs b/test/YesSql.Tests/Models/Animal.cs index 4f553378..47440844 100644 --- a/test/YesSql.Tests/Models/Animal.cs +++ b/test/YesSql.Tests/Models/Animal.cs @@ -1,4 +1,4 @@ -using System.Runtime.Serialization; +using System.Text.Json.Serialization; namespace YesSql.Tests.Models { @@ -6,7 +6,7 @@ public class Animal { public string Name { get; set; } - [IgnoreDataMember] + [JsonIgnore] public string Color { get; set; } } } diff --git a/test/YesSql.Tests/Models/Drawing.cs b/test/YesSql.Tests/Models/Drawing.cs index bad6e985..b8057b1b 100644 --- a/test/YesSql.Tests/Models/Drawing.cs +++ b/test/YesSql.Tests/Models/Drawing.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text.Json.Serialization; namespace YesSql.Tests.Models { @@ -12,6 +13,9 @@ public Drawing() public IList Shapes { get; set; } } + [JsonPolymorphic] + [JsonDerivedType(typeof(Square), nameof(Square))] + [JsonDerivedType(typeof(Circle), nameof(Circle))] public abstract class Shape { public long Id { get; set; } diff --git a/test/YesSql.Tests/YesSql.Tests.csproj b/test/YesSql.Tests/YesSql.Tests.csproj index d5c532e0..0ed1020c 100644 --- a/test/YesSql.Tests/YesSql.Tests.csproj +++ b/test/YesSql.Tests/YesSql.Tests.csproj @@ -1,7 +1,7 @@ - net6.0;net7.0;net8.0 + net7.0;net8.0 latest YesSql.Tests YesSql.Tests