From fc11ef6695047bbf41183739b11e710836cd94dc Mon Sep 17 00:00:00 2001
From: electricessence <5899455+electricessence@users.noreply.github.com>
Date: Sat, 21 May 2022 15:33:11 -0700
Subject: [PATCH] Added ReadOnlySpan option for System.Text.Json. Standardized
serialization to always return non-null string.
---
.../.editorconfig | 3 ++
.../Converters/JsonDecimalConverter.cs | 24 +++++++++++-
.../Converters/JsonDoubleRoundingConverter.cs | 2 +-
.../JsonNullableDecimalConverter.cs | 4 +-
.../Converters/JsonNullableDoubleConverter.cs | 2 +-
.../Converters/JsonValueConverterBase.cs | 17 ++++++--
.../JsonSerializerInternal.cs | 8 ++--
.../Open.Serialization.Json.Newtonsoft.csproj | 9 ++---
.../SerializationExtensions.cs | 6 ++-
.../JsonSerializerFactory.cs | 15 +++++++
.../JsonSerializerInternal.cs | 7 +++-
.../Open.Serialization.Json.System.csproj | 8 ++--
.../JsonSerializerInternal.cs | 2 +-
.../Open.Serialization.Json.Utf8Json.csproj | 8 ++--
.../SerializationExtensions.cs | 32 +++++++++++++++
.../JsonObjectSerializer.cs | 2 +-
Open.Serialization.Json/JsonSerializer.cs | 2 +-
.../Open.Serialization.Json.csproj | 10 ++---
.../DefaultImplementationTests.cs | 6 ++-
Open.Serialization/DefaultMethods.cs | 4 +-
.../Extensions/SerializationExtensions.cs | 2 +-
Open.Serialization/IDeserialize.cs | 18 +++++++--
Open.Serialization/IDeserializeObject.cs | 8 +++-
Open.Serialization/ISerialize.cs | 8 ++--
Open.Serialization/ISerializeObject.cs | 2 +-
Open.Serialization/ISerializer.cs | 1 +
Open.Serialization/ObjectSerializer.cs | 6 +--
Open.Serialization/ObjectSerializerBase.cs | 7 +---
Open.Serialization/Open.Serialization.csproj | 2 +-
Open.Serialization/Open.Serialization.xml | 39 ++++++++++---------
Open.Serialization/Serializer.cs | 26 ++-----------
Open.Serialization/SerializerBase.cs | 11 +++---
32 files changed, 195 insertions(+), 106 deletions(-)
diff --git a/Open.Serialization.Json.Newtonsoft/.editorconfig b/Open.Serialization.Json.Newtonsoft/.editorconfig
index eb2cabb..644a717 100644
--- a/Open.Serialization.Json.Newtonsoft/.editorconfig
+++ b/Open.Serialization.Json.Newtonsoft/.editorconfig
@@ -11,3 +11,6 @@ dotnet_diagnostic.CA1305.severity = silent
# CA1307: Specify StringComparison
dotnet_diagnostic.CA1307.severity = suggestion
+
+# CS1591: Missing XML comment for publicly visible type or member
+dotnet_diagnostic.CS1591.severity = silent
diff --git a/Open.Serialization.Json.Newtonsoft/Converters/JsonDecimalConverter.cs b/Open.Serialization.Json.Newtonsoft/Converters/JsonDecimalConverter.cs
index 82caee6..1fb9cdb 100644
--- a/Open.Serialization.Json.Newtonsoft/Converters/JsonDecimalConverter.cs
+++ b/Open.Serialization.Json.Newtonsoft/Converters/JsonDecimalConverter.cs
@@ -1,36 +1,56 @@
using Newtonsoft.Json;
using System;
using System.Diagnostics.Contracts;
-using System.Numerics;
namespace Open.Serialization.Json.Newtonsoft.Converters;
+///
+/// A converter for ensuring proper standardized processing of decimals.
+///
public class JsonDecimalConverter : JsonValueConverterBase
{
+ ///
+ /// Constructs a .
+ ///
protected JsonDecimalConverter()
{
// Prevent unnecessary replication.
}
+ ///
+ /// Shared instance of this converter.
+ ///
public static readonly JsonDecimalConverter Instance
= new();
+ ///
+#if NETSTANDARD2_1
+ [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("value")]
+#endif
public static string? Normalize(decimal? value)
=> Normalize(value?.ToString());
+ ///
+ /// Normalizes a decimal by removing any unnecessary trailing zeros or decimal.
+ ///
+#if NETSTANDARD2_1
+ [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("decimalString")]
+#endif
public static string? Normalize(string? decimalString)
=> string.IsNullOrEmpty(decimalString) || decimalString!.IndexOf('.') == -1
? decimalString
: decimalString.AsSpan().TrimEnd('0').TrimEnd('.').ToString();
+ ///
public override decimal ReadJson(JsonReader reader, Type objectType, decimal existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader is null) throw new ArgumentNullException(nameof(reader));
Contract.EndContractBlock();
- return ConvertToDecimal(reader.Value);
+ return ConvertToDecimal(reader.Value!);
}
+ ///
public override void WriteJson(JsonWriter writer, decimal value, JsonSerializer serializer)
{
if (writer is null) throw new ArgumentNullException(nameof(writer));
diff --git a/Open.Serialization.Json.Newtonsoft/Converters/JsonDoubleRoundingConverter.cs b/Open.Serialization.Json.Newtonsoft/Converters/JsonDoubleRoundingConverter.cs
index 2ae0a25..a49e2eb 100644
--- a/Open.Serialization.Json.Newtonsoft/Converters/JsonDoubleRoundingConverter.cs
+++ b/Open.Serialization.Json.Newtonsoft/Converters/JsonDoubleRoundingConverter.cs
@@ -33,7 +33,7 @@ public override double ReadJson(JsonReader reader, Type objectType, double exist
long i => i,
ulong i => i,
BigInteger i => (double)i,
- _ => Math.Round(ConvertToDouble(reader.Value), Maximum),
+ _ => Math.Round(ConvertToDouble(reader.Value!), Maximum),
};
}
diff --git a/Open.Serialization.Json.Newtonsoft/Converters/JsonNullableDecimalConverter.cs b/Open.Serialization.Json.Newtonsoft/Converters/JsonNullableDecimalConverter.cs
index dc505b2..1a28396 100644
--- a/Open.Serialization.Json.Newtonsoft/Converters/JsonNullableDecimalConverter.cs
+++ b/Open.Serialization.Json.Newtonsoft/Converters/JsonNullableDecimalConverter.cs
@@ -14,6 +14,7 @@ protected JsonNullableDecimalConverter()
public static readonly JsonNullableDecimalConverter Instance
= new();
+ ///
public override decimal? ReadJson(JsonReader reader, Type objectType, decimal? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader is null) throw new ArgumentNullException(nameof(reader));
@@ -23,10 +24,11 @@ public static readonly JsonNullableDecimalConverter Instance
{
JsonToken.Null => default,
JsonToken.Undefined => default,
- _ => ConvertToDecimal(reader.Value),
+ _ => ConvertToDecimal(reader.Value!),
};
}
+ ///
public override void WriteJson(JsonWriter writer, decimal? value, JsonSerializer serializer)
{
if (writer is null) throw new ArgumentNullException(nameof(writer));
diff --git a/Open.Serialization.Json.Newtonsoft/Converters/JsonNullableDoubleConverter.cs b/Open.Serialization.Json.Newtonsoft/Converters/JsonNullableDoubleConverter.cs
index b9dd269..732b8a3 100644
--- a/Open.Serialization.Json.Newtonsoft/Converters/JsonNullableDoubleConverter.cs
+++ b/Open.Serialization.Json.Newtonsoft/Converters/JsonNullableDoubleConverter.cs
@@ -23,7 +23,7 @@ public static readonly JsonNullableDoubleConverter Instance
{
JsonToken.Null => default,
JsonToken.Undefined => default,
- _ => ConvertToDouble(reader.Value)
+ _ => ConvertToDouble(reader.Value!)
};
}
diff --git a/Open.Serialization.Json.Newtonsoft/Converters/JsonValueConverterBase.cs b/Open.Serialization.Json.Newtonsoft/Converters/JsonValueConverterBase.cs
index edcb9c7..469aaf4 100644
--- a/Open.Serialization.Json.Newtonsoft/Converters/JsonValueConverterBase.cs
+++ b/Open.Serialization.Json.Newtonsoft/Converters/JsonValueConverterBase.cs
@@ -4,19 +4,27 @@
namespace Open.Serialization.Json.Newtonsoft.Converters;
+///
+/// Base JsonConverter for NewtsonSoft.Json.
+///
public abstract class JsonValueConverterBase : JsonConverter
{
// Avoids stack overflow.
private static readonly JsonSerializer Deserializer = JsonSerializer.Create();
- public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer)
- => Deserializer.Deserialize(reader);
+ ///
+ public override T ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer)
+ => Deserializer.Deserialize(reader)!;
- public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
+ ///
+ public override void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer)
#pragma warning disable CA1062 // Validate arguments of public methods
=> writer.WriteRawValue(value?.ToString());
#pragma warning restore CA1062 // Validate arguments of public methods
+ ///
+ /// Special convert to decimal from object.
+ ///
protected static decimal ConvertToDecimal(object value) => value switch
{
decimal d => d,
@@ -25,6 +33,9 @@ public override void WriteJson(JsonWriter writer, T value, JsonSerializer serial
_ => throw new ArgumentException("Unable to convert to decimal.", nameof(value)),
};
+ ///
+ /// Special convert to decimal from object.
+ ///
protected static double ConvertToDouble(object value) => value switch
{
double d => d,
diff --git a/Open.Serialization.Json.Newtonsoft/JsonSerializerInternal.cs b/Open.Serialization.Json.Newtonsoft/JsonSerializerInternal.cs
index b5d5343..3cb76e1 100644
--- a/Open.Serialization.Json.Newtonsoft/JsonSerializerInternal.cs
+++ b/Open.Serialization.Json.Newtonsoft/JsonSerializerInternal.cs
@@ -12,15 +12,15 @@ internal JsonSerializerInternal(JsonSerializerSettings settings)
}
public override T Deserialize(string? value)
- => JsonConvert.DeserializeObject(value, _settings);
+ => JsonConvert.DeserializeObject(value!, _settings)!;
- public override string? Serialize(T item)
+ public override string Serialize(T item)
=> JsonConvert.SerializeObject(item, _settings);
public override object? Deserialize(string? value, Type type)
- => JsonConvert.DeserializeObject(value, type);
+ => JsonConvert.DeserializeObject(value!, type);
- public override string? Serialize(object? item, Type type)
+ public override string Serialize(object? item, Type type)
=> JsonConvert.SerializeObject(item, type, _settings);
public new JsonSerializer Cast()
diff --git a/Open.Serialization.Json.Newtonsoft/Open.Serialization.Json.Newtonsoft.csproj b/Open.Serialization.Json.Newtonsoft/Open.Serialization.Json.Newtonsoft.csproj
index e17eded..46b34ab 100644
--- a/Open.Serialization.Json.Newtonsoft/Open.Serialization.Json.Newtonsoft.csproj
+++ b/Open.Serialization.Json.Newtonsoft/Open.Serialization.Json.Newtonsoft.csproj
@@ -18,7 +18,7 @@
https://github.com/Open-NET-Libraries/Open.Serialization
https://github.com/Open-NET-Libraries/Open.Serialization
git
- 2.3.1
+ 3.0.0
MIT
true
@@ -31,6 +31,8 @@
+
+
@@ -45,10 +47,7 @@
-
-
-
-
+
diff --git a/Open.Serialization.Json.Newtonsoft/SerializationExtensions.cs b/Open.Serialization.Json.Newtonsoft/SerializationExtensions.cs
index 4b940ec..5671f74 100644
--- a/Open.Serialization.Json.Newtonsoft/SerializationExtensions.cs
+++ b/Open.Serialization.Json.Newtonsoft/SerializationExtensions.cs
@@ -40,7 +40,7 @@ public static IServiceCollection AddJsonSerializer(this IServiceCollection se
}
public static Func GetDeserialize(this JsonSerializerSettings settings)
- => json => JsonConvert.DeserializeObject(json, settings);
+ => json => JsonConvert.DeserializeObject(json!, settings)!;
public static Func GetSerialize(this JsonSerializerSettings settings)
=> item => JsonConvert.SerializeObject(item, settings);
@@ -59,10 +59,12 @@ public static IJsonSerializerFactory GetSerializerFactory(this JsonSerializerSet
public static string? Serialize(this JsonSerializerSettings settings, TValue value)
=> JsonConvert.SerializeObject(value, settings);
+
public static string? Serialize(this JsonSerializerSettings settings, object? value)
=> JsonConvert.SerializeObject(value, settings);
+
public static TValue Deserialize(this JsonSerializerSettings settings, string? value)
- => JsonConvert.DeserializeObject(value, settings);
+ => JsonConvert.DeserializeObject(value!, settings)!;
public static JsonSerializerSettings Clone(this JsonSerializerSettings settings)
{
diff --git a/Open.Serialization.Json.System/JsonSerializerFactory.cs b/Open.Serialization.Json.System/JsonSerializerFactory.cs
index cbb48ac..9ec47ec 100644
--- a/Open.Serialization.Json.System/JsonSerializerFactory.cs
+++ b/Open.Serialization.Json.System/JsonSerializerFactory.cs
@@ -3,15 +3,23 @@
namespace Open.Serialization.Json.System;
+///
+/// The default for System.Text.Json.
+///
public class JsonSerializerFactory : IJsonSerializerFactory
{
static readonly JsonSerializerOptions DefaultOptions = RelaxedJson.Options();
readonly JsonSerializerOptions _options;
+
+ ///
+ /// Constructs a
+ ///
public JsonSerializerFactory(JsonSerializerOptions? defaultOptions)
{
_options = defaultOptions?.Clone() ?? DefaultOptions;
}
+ ///
public JsonSerializerFactory() : this(null)
{
}
@@ -20,6 +28,10 @@ public JsonSerializerFactory() : this(null)
JsonSerializerInternal? _ignoreCase;
static JsonSerializerFactory? _default;
+
+ ///
+ /// The default instance for System.Text.Json.
+ ///
public static JsonSerializerFactory Default
=> LazyInitializer.EnsureInitialized(ref _default)!;
@@ -52,6 +64,9 @@ internal JsonSerializerInternal GetSerializerInternal(IJsonSerializationOptions?
return new JsonSerializerInternal(o);
}
+ ///
+ /// Returns an .
+ ///
public IJsonSerializer GetSerializer(IJsonSerializationOptions? options = null, bool caseSensitive = false)
=> GetSerializerInternal(options, caseSensitive);
}
diff --git a/Open.Serialization.Json.System/JsonSerializerInternal.cs b/Open.Serialization.Json.System/JsonSerializerInternal.cs
index 2978ff6..3f2e654 100644
--- a/Open.Serialization.Json.System/JsonSerializerInternal.cs
+++ b/Open.Serialization.Json.System/JsonSerializerInternal.cs
@@ -6,7 +6,7 @@
namespace Open.Serialization.Json.System;
-internal class JsonSerializerInternal : JsonSerializerBase, IJsonSerializer
+internal class JsonSerializerInternal : JsonSerializerBase, IJsonSerializer, IDeserializeSpan
{
readonly JsonSerializerOptions _options;
internal JsonSerializerInternal(JsonSerializerOptions options)
@@ -17,13 +17,16 @@ internal JsonSerializerInternal(JsonSerializerOptions options)
public override T Deserialize(string? value)
=> JsonSerializer.Deserialize(value!, _options)!;
+ public T Deserialize(ReadOnlySpan value)
+ => JsonSerializer.Deserialize(value, _options)!;
+
ValueTask ISerializeAsync.SerializeAsync(Stream stream, T item, CancellationToken cancellationToken)
=> new(JsonSerializer.SerializeAsync(stream, item, _options, cancellationToken));
public new Task SerializeAsync(Stream stream, T item, CancellationToken cancellationToken = default)
=> JsonSerializer.SerializeAsync(stream, item, _options, cancellationToken);
- public override string? Serialize(T item)
+ public override string Serialize(T item)
=> JsonSerializer.Serialize(item, _options);
public override ValueTask DeserializeAsync(Stream stream, CancellationToken cancellationToken = default)
diff --git a/Open.Serialization.Json.System/Open.Serialization.Json.System.csproj b/Open.Serialization.Json.System/Open.Serialization.Json.System.csproj
index 860ee82..6546e70 100644
--- a/Open.Serialization.Json.System/Open.Serialization.Json.System.csproj
+++ b/Open.Serialization.Json.System/Open.Serialization.Json.System.csproj
@@ -17,7 +17,7 @@
https://github.com/Open-NET-Libraries/Open.Serialization
https://github.com/Open-NET-Libraries/Open.Serialization
git
- 2.3.3
+ 3.0.0
true
MIT
@@ -31,6 +31,8 @@
+
+
@@ -45,9 +47,7 @@
-
-
-
+
diff --git a/Open.Serialization.Json.Utf8Json/JsonSerializerInternal.cs b/Open.Serialization.Json.Utf8Json/JsonSerializerInternal.cs
index 3d5a874..0f7e082 100644
--- a/Open.Serialization.Json.Utf8Json/JsonSerializerInternal.cs
+++ b/Open.Serialization.Json.Utf8Json/JsonSerializerInternal.cs
@@ -49,7 +49,7 @@ ValueTask ISerializeAsync.SerializeAsync(Stream stream, T item, CancellationT
public override object? Deserialize(string? value, Type type)
=> JsonSerializer.NonGeneric.Deserialize(type, value, _resolver);
- public override string? Serialize(object? item, Type type)
+ public override string Serialize(object? item, Type type)
{
var json = JsonSerializer.NonGeneric.ToJsonString(type, item, _resolver);
return _indent ? JsonSerializer.PrettyPrint(json) : json;
diff --git a/Open.Serialization.Json.Utf8Json/Open.Serialization.Json.Utf8Json.csproj b/Open.Serialization.Json.Utf8Json/Open.Serialization.Json.Utf8Json.csproj
index c2d61bb..43907bf 100644
--- a/Open.Serialization.Json.Utf8Json/Open.Serialization.Json.Utf8Json.csproj
+++ b/Open.Serialization.Json.Utf8Json/Open.Serialization.Json.Utf8Json.csproj
@@ -18,7 +18,7 @@
https://github.com/Open-NET-Libraries/Open.Serialization
https://github.com/Open-NET-Libraries/Open.Serialization
git
- 2.3.1
+ 3.0.0
MIT
true
@@ -31,6 +31,8 @@
+
+
@@ -45,9 +47,7 @@
-
-
-
+
\ No newline at end of file
diff --git a/Open.Serialization.Json.Utf8Json/SerializationExtensions.cs b/Open.Serialization.Json.Utf8Json/SerializationExtensions.cs
index 58c0f10..5c95ba1 100644
--- a/Open.Serialization.Json.Utf8Json/SerializationExtensions.cs
+++ b/Open.Serialization.Json.Utf8Json/SerializationExtensions.cs
@@ -4,6 +4,9 @@
namespace Open.Serialization.Json.Utf8Json;
+///
+/// Extensions for Utf8Json serialization with Open.Serialization.Json.
+///
public static class SerializationExtensions
{
///
@@ -32,9 +35,15 @@ public static IServiceCollection AddJsonSerializer(this IServiceCollection se
return services;
}
+ ///
+ /// Returns a delegate for deserializing a to .
+ ///
public static Func GetDeserialize(this IJsonFormatterResolver options)
=> json => JsonSerializer.Deserialize(json, options);
+ ///
+ /// Returns a delegate for serializing to a .
+ ///
public static Func GetSerialize(this IJsonFormatterResolver options, bool indent = false)
=> item =>
{
@@ -42,6 +51,9 @@ public static IServiceCollection AddJsonSerializer(this IServiceCollection se
return indent ? JsonSerializer.PrettyPrint(result) : result;
};
+ ///
+ /// Returns a delegate for serializing to .
+ ///
public static Func
public Serializer(
Func? deserializer,
- Func? serializer = null,
+ Func? serializer = null,
Func>? deserializerAsync = null,
Func? serializerAsync = null)
{
@@ -36,37 +35,18 @@ public Serializer(
_serializerAsync = serializerAsync ?? base.SerializeAsync;
}
- ///
- public Serializer(
- IDeserialize deserializer,
- Func? serializer = null,
- Func>? deserializerAsync = null,
- Func? serializerAsync = null)
- : this(deserializer.Deserialize, serializer, deserializerAsync, serializerAsync)
- {
- _deserializerInstance = deserializer;
- }
-
///
public override T Deserialize(string? value)
=> _deserializer is null
? throw new NullReferenceException("No deserializer function was supplied.")
: _deserializer(value);
- ///
- public override T Deserialize(ReadOnlySpan value) // Should override if possible.
- => _deserializerInstance is not null
- ? _deserializerInstance.Deserialize(value)
- : _deserializer is null
- ? throw new NullReferenceException("No deserializer function was supplied.")
- : _deserializer(value.ToString());
-
///
public override ValueTask DeserializeAsync(Stream source, CancellationToken cancellationToken = default)
=> _deserializerAsync(source, cancellationToken);
///
- public override string? Serialize(T item)
+ public override string Serialize(T item)
=> _serializer is null
? throw new NullReferenceException("No serializer function was supplied.")
: _serializer(item);
diff --git a/Open.Serialization/SerializerBase.cs b/Open.Serialization/SerializerBase.cs
index f12994c..2e59296 100644
--- a/Open.Serialization/SerializerBase.cs
+++ b/Open.Serialization/SerializerBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -13,15 +14,12 @@ public abstract class SerializerBase : ISerializer, IAsyncSerializer
///
public abstract T Deserialize(string? value);
- ///
- public abstract T Deserialize(ReadOnlySpan value);
-
///
public virtual ValueTask DeserializeAsync(Stream source, CancellationToken cancellationToken = default)
=> DefaultMethods.DeserializeAsync(this, source);
///
- public abstract string? Serialize(T item);
+ public abstract string Serialize(T item);
///
public virtual ValueTask SerializeAsync(Stream target, T item, CancellationToken cancellationToken = default)
@@ -44,14 +42,15 @@ public abstract class SerializerBase : ISerializer, IAsyncSerializer
public abstract T Deserialize(string? value);
///
- public abstract T Deserialize(ReadOnlySpan value);
+ public virtual T Deserialize(ReadOnlySpan value)
+ => Deserialize(value.ToString());
///
public virtual ValueTask DeserializeAsync(Stream source, CancellationToken cancellationToken = default)
=> DefaultMethods.DeserializeAsync(this, source);
///
- public abstract string? Serialize(T item);
+ public abstract string Serialize(T item);
///
public virtual ValueTask SerializeAsync(Stream target, T item, CancellationToken cancellationToken = default)