Skip to content

Commit

Permalink
Added ReadOnlySpan option for System.Text.Json. Standardized serializ…
Browse files Browse the repository at this point in the history
…ation to always return non-null string.
  • Loading branch information
electricessence committed May 21, 2022
1 parent 57cc7f3 commit fc11ef6
Show file tree
Hide file tree
Showing 32 changed files with 195 additions and 106 deletions.
3 changes: 3 additions & 0 deletions Open.Serialization.Json.Newtonsoft/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -1,36 +1,56 @@
using Newtonsoft.Json;
using System;
using System.Diagnostics.Contracts;
using System.Numerics;

namespace Open.Serialization.Json.Newtonsoft.Converters;

/// <summary>
/// A converter for ensuring proper standardized processing of decimals.
/// </summary>
public class JsonDecimalConverter : JsonValueConverterBase<decimal>
{
/// <summary>
/// Constructs a <see cref="JsonDecimalConverter"/>.
/// </summary>
protected JsonDecimalConverter()
{
// Prevent unnecessary replication.
}

/// <summary>
/// Shared instance of this converter.
/// </summary>
public static readonly JsonDecimalConverter Instance
= new();

/// <inheritdoc cref="Normalize(string?)"/>
#if NETSTANDARD2_1
[return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("value")]
#endif
public static string? Normalize(decimal? value)
=> Normalize(value?.ToString());

/// <summary>
/// Normalizes a decimal by removing any unnecessary trailing zeros or decimal.
/// </summary>
#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();

/// <inheritdoc />
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!);
}

/// <inheritdoc />
public override void WriteJson(JsonWriter writer, decimal value, JsonSerializer serializer)
{
if (writer is null) throw new ArgumentNullException(nameof(writer));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ protected JsonNullableDecimalConverter()
public static readonly JsonNullableDecimalConverter Instance
= new();

/// <inheritdoc />
public override decimal? ReadJson(JsonReader reader, Type objectType, decimal? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader is null) throw new ArgumentNullException(nameof(reader));
Expand All @@ -23,10 +24,11 @@ public static readonly JsonNullableDecimalConverter Instance
{
JsonToken.Null => default,
JsonToken.Undefined => default,
_ => ConvertToDecimal(reader.Value),
_ => ConvertToDecimal(reader.Value!),
};
}

/// <inheritdoc />
public override void WriteJson(JsonWriter writer, decimal? value, JsonSerializer serializer)
{
if (writer is null) throw new ArgumentNullException(nameof(writer));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static readonly JsonNullableDoubleConverter Instance
{
JsonToken.Null => default,
JsonToken.Undefined => default,
_ => ConvertToDouble(reader.Value)
_ => ConvertToDouble(reader.Value!)
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@

namespace Open.Serialization.Json.Newtonsoft.Converters;

/// <summary>
/// Base JsonConverter for NewtsonSoft.Json.
/// </summary>
public abstract class JsonValueConverterBase<T> : JsonConverter<T>
{
// 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<T>(reader);
/// <inheritdoc />
public override T ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer)
=> Deserializer.Deserialize<T>(reader)!;

public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
/// <inheritdoc />
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

/// <summary>
/// Special convert to decimal from object.
/// </summary>
protected static decimal ConvertToDecimal(object value) => value switch
{
decimal d => d,
Expand All @@ -25,6 +33,9 @@ public override void WriteJson(JsonWriter writer, T value, JsonSerializer serial
_ => throw new ArgumentException("Unable to convert to decimal.", nameof(value)),
};

/// <summary>
/// Special convert to decimal from object.
/// </summary>
protected static double ConvertToDouble(object value) => value switch
{
double d => d,
Expand Down
8 changes: 4 additions & 4 deletions Open.Serialization.Json.Newtonsoft/JsonSerializerInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ internal JsonSerializerInternal(JsonSerializerSettings settings)
}

public override T Deserialize<T>(string? value)
=> JsonConvert.DeserializeObject<T>(value, _settings);
=> JsonConvert.DeserializeObject<T>(value!, _settings)!;

public override string? Serialize<T>(T item)
public override string Serialize<T>(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<T> Cast<T>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<PackageProjectUrl>https://github.com/Open-NET-Libraries/Open.Serialization</PackageProjectUrl>
<RepositoryUrl>https://github.com/Open-NET-Libraries/Open.Serialization</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Version>2.3.1</Version>
<Version>3.0.0</Version>
<PackageReleaseNotes></PackageReleaseNotes>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
Expand All @@ -31,6 +31,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

<ItemGroup>
Expand All @@ -45,10 +47,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.1" />
<PackageReference Include="Open.Serialization.Json" Version="2.3.1" />
<PackageReference Include="System.Memory" Version="4.5.4" />
<ProjectReference Include="..\Open.Serialization.Json\Open.Serialization.Json.csproj" />
</ItemGroup>

</Project>
6 changes: 4 additions & 2 deletions Open.Serialization.Json.Newtonsoft/SerializationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static IServiceCollection AddJsonSerializer<T>(this IServiceCollection se
}

public static Func<string?, T> GetDeserialize<T>(this JsonSerializerSettings settings)
=> json => JsonConvert.DeserializeObject<T>(json, settings);
=> json => JsonConvert.DeserializeObject<T>(json!, settings)!;

public static Func<T, string?> GetSerialize<T>(this JsonSerializerSettings settings)
=> item => JsonConvert.SerializeObject(item, settings);
Expand All @@ -59,10 +59,12 @@ public static IJsonSerializerFactory GetSerializerFactory(this JsonSerializerSet

public static string? Serialize<TValue>(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<TValue>(this JsonSerializerSettings settings, string? value)
=> JsonConvert.DeserializeObject<TValue>(value, settings);
=> JsonConvert.DeserializeObject<TValue>(value!, settings)!;

public static JsonSerializerSettings Clone(this JsonSerializerSettings settings)
{
Expand Down
15 changes: 15 additions & 0 deletions Open.Serialization.Json.System/JsonSerializerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,23 @@

namespace Open.Serialization.Json.System;

/// <summary>
/// The default <see cref="IJsonSerializerFactory"/> for System.Text.Json.
/// </summary>
public class JsonSerializerFactory : IJsonSerializerFactory
{
static readonly JsonSerializerOptions DefaultOptions = RelaxedJson.Options();
readonly JsonSerializerOptions _options;

/// <summary>
/// Constructs a <see cref="JsonSerializerFactory"/>
/// </summary>
public JsonSerializerFactory(JsonSerializerOptions? defaultOptions)
{
_options = defaultOptions?.Clone() ?? DefaultOptions;
}

/// <inheritdoc cref="JsonSerializerFactory.JsonSerializerFactory(JsonSerializerOptions?)"/>
public JsonSerializerFactory() : this(null)
{
}
Expand All @@ -20,6 +28,10 @@ public JsonSerializerFactory() : this(null)
JsonSerializerInternal? _ignoreCase;

static JsonSerializerFactory? _default;

/// <summary>
/// The default <see cref="IJsonSerializerFactory"/> instance for System.Text.Json.
/// </summary>
public static JsonSerializerFactory Default
=> LazyInitializer.EnsureInitialized(ref _default)!;

Expand Down Expand Up @@ -52,6 +64,9 @@ internal JsonSerializerInternal GetSerializerInternal(IJsonSerializationOptions?
return new JsonSerializerInternal(o);
}

/// <summary>
/// Returns an <see cref="IJsonSerializer"/>.
/// </summary>
public IJsonSerializer GetSerializer(IJsonSerializationOptions? options = null, bool caseSensitive = false)
=> GetSerializerInternal(options, caseSensitive);
}
7 changes: 5 additions & 2 deletions Open.Serialization.Json.System/JsonSerializerInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -17,13 +17,16 @@ internal JsonSerializerInternal(JsonSerializerOptions options)
public override T Deserialize<T>(string? value)
=> JsonSerializer.Deserialize<T>(value!, _options)!;

public T Deserialize<T>(ReadOnlySpan<char> value)
=> JsonSerializer.Deserialize<T>(value, _options)!;

ValueTask ISerializeAsync.SerializeAsync<T>(Stream stream, T item, CancellationToken cancellationToken)
=> new(JsonSerializer.SerializeAsync(stream, item, _options, cancellationToken));

public new Task SerializeAsync<T>(Stream stream, T item, CancellationToken cancellationToken = default)
=> JsonSerializer.SerializeAsync(stream, item, _options, cancellationToken);

public override string? Serialize<T>(T item)
public override string Serialize<T>(T item)
=> JsonSerializer.Serialize(item, _options);

public override ValueTask<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<PackageProjectUrl>https://github.com/Open-NET-Libraries/Open.Serialization</PackageProjectUrl>
<RepositoryUrl>https://github.com/Open-NET-Libraries/Open.Serialization</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Version>2.3.3</Version>
<Version>3.0.0</Version>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes></PackageReleaseNotes>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand All @@ -31,6 +31,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="System.Text.Json" Version="6.0.4" />
</ItemGroup>

<ItemGroup>
Expand All @@ -45,9 +47,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Open.Serialization.Json" Version="2.3.1" />
<PackageReference Include="System.Text.Json" Version="6.0.4" />
<ProjectReference Include="..\Open.Serialization.Json\Open.Serialization.Json.csproj" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion Open.Serialization.Json.Utf8Json/JsonSerializerInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ ValueTask ISerializeAsync.SerializeAsync<T>(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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<PackageProjectUrl>https://github.com/Open-NET-Libraries/Open.Serialization</PackageProjectUrl>
<RepositoryUrl>https://github.com/Open-NET-Libraries/Open.Serialization</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Version>2.3.1</Version>
<Version>3.0.0</Version>
<PackageReleaseNotes></PackageReleaseNotes>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
Expand All @@ -31,6 +31,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Utf8Json" Version="1.3.7" />
</ItemGroup>

<ItemGroup>
Expand All @@ -45,9 +47,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Open.Serialization.Json" Version="2.3.1" />
<PackageReference Include="Utf8Json" Version="1.3.7" />
<ProjectReference Include="..\Open.Serialization.Json\Open.Serialization.Json.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit fc11ef6

Please sign in to comment.