Skip to content

Commit d2ca0d6

Browse files
author
Oren (electricessence)
committed
Resonable parity established for all sub projects.
1 parent 11fe4fd commit d2ca0d6

8 files changed

Lines changed: 117 additions & 181 deletions

File tree

Open.Serialization.Json.Newtonsoft/Open.Serialization.Json.Newtonsoft.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Part of the "Open" set of libraries.
1717
<RepositoryUrl>https://github.com/electricessence/Open.Serialization</RepositoryUrl>
1818
<RepositoryType>git</RepositoryType>
1919
<PackageTags>serialization json newtonsoft</PackageTags>
20-
<Version>1.0.1</Version>
20+
<Version>1.2.0</Version>
2121
</PropertyGroup>
2222

2323
<ItemGroup>

Open.Serialization.Json.System/Open.Serialization.Json.System.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Part of the "Open" set of libraries.
1717
<RepositoryUrl>https://github.com/electricessence/Open.Serialization</RepositoryUrl>
1818
<RepositoryType>git</RepositoryType>
1919
<PackageTags>serialization json stj</PackageTags>
20-
<Version>1.0.1</Version>
20+
<Version>1.2.0</Version>
2121
</PropertyGroup>
2222

2323
<ItemGroup>
Lines changed: 18 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using Open.Serialization.Json.Utf8Json;
2+
using System;
23
using System.Linq;
34
using Utf8Json;
45

@@ -9,17 +10,25 @@ public static class Extensions
910
public static Func<string, T> GetDeserialize<T>(this IJsonFormatterResolver options)
1011
=> json => JsonSerializer.Deserialize<T>(json, options);
1112

12-
public static Func<T, string> GetSerialize<T>(this IJsonFormatterResolver options)
13-
=> item => JsonSerializer.ToJsonString(item, options);
13+
public static Func<T, string> GetSerialize<T>(this IJsonFormatterResolver options, bool indent = false)
14+
=> item =>
15+
{
16+
var result = JsonSerializer.ToJsonString(item, options);
17+
return indent ? JsonSerializer.PrettyPrint(result) : result;
18+
};
1419

15-
public static Func<object, string> GetSerialize(this IJsonFormatterResolver options)
16-
=> item => JsonSerializer.ToJsonString(item, options);
20+
public static Func<object, string> GetSerialize(this IJsonFormatterResolver options, bool indent = false)
21+
=> item =>
22+
{
23+
var result = JsonSerializer.ToJsonString(item, options);
24+
return indent ? JsonSerializer.PrettyPrint(result) : result;
25+
};
1726

18-
public static IJsonSerializer GetSerializer(this IJsonFormatterResolver options)
19-
=> new JsonSerializerInternal(options);
27+
public static IJsonSerializer GetSerializer(this IJsonFormatterResolver options, bool indent = false)
28+
=> new JsonSerializerInternal(options, indent);
2029

21-
public static IJsonSerializer<T> GetSerializer<T>(this IJsonFormatterResolver options)
22-
=> new JsonSerializerInternal<T>(options);
30+
public static IJsonSerializer<T> GetSerializer<T>(this IJsonFormatterResolver options, bool indent = false)
31+
=> new JsonSerializerInternal<T>(options, indent);
2332

2433
public static IJsonSerializerFactory GetSerializerFactory(this IJsonFormatterResolver options)
2534
=> new JsonSerializerFactory(options);
@@ -31,135 +40,5 @@ public static string Serialize(this IJsonFormatterResolver options, object value
3140
public static TValue Deserialize<TValue>(this IJsonFormatterResolver options, string value)
3241
=> JsonSerializer.Deserialize<TValue>(value, options);
3342

34-
public static JsonSerializerOptions Clone(this JsonSerializerOptions options)
35-
{
36-
var clone = new JsonSerializerOptions
37-
{
38-
AllowTrailingCommas = options.AllowTrailingCommas,
39-
DefaultBufferSize = options.DefaultBufferSize,
40-
DictionaryKeyPolicy = options.DictionaryKeyPolicy,
41-
Encoder = options.Encoder,
42-
IgnoreNullValues = options.IgnoreNullValues,
43-
IgnoreReadOnlyProperties = options.IgnoreReadOnlyProperties,
44-
MaxDepth = options.MaxDepth,
45-
PropertyNameCaseInsensitive = options.PropertyNameCaseInsensitive,
46-
PropertyNamingPolicy = options.PropertyNamingPolicy,
47-
ReadCommentHandling = options.ReadCommentHandling,
48-
WriteIndented = options.WriteIndented
49-
};
50-
51-
foreach (var converter in options.Converters)
52-
clone.Converters.Add(converter);
53-
54-
return clone;
55-
}
56-
57-
public static JsonSerializerOptions SetPropertyNameCaseInsensitive(this JsonSerializerOptions options, bool value)
58-
{
59-
options.PropertyNameCaseInsensitive = value;
60-
return options;
61-
}
62-
63-
public static JsonSerializerOptions SetIgnoreNullValues(this JsonSerializerOptions options, bool value = true)
64-
{
65-
options.IgnoreNullValues = value;
66-
return options;
67-
}
68-
69-
public static JsonSerializerOptions UseUnsafeEncoding(this JsonSerializerOptions options)
70-
{
71-
options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
72-
return options;
73-
}
74-
75-
public static JsonSerializerOptions AddConverter(this JsonSerializerOptions options, JsonConverter converter)
76-
{
77-
options.Converters.Add(converter);
78-
return options;
79-
}
80-
81-
static JsonSerializerOptions RoundDoublesCore(this JsonSerializerOptions options, int maxDecimals)
82-
{
83-
var existing = options.Converters.FirstOrDefault(c => c is JsonConverter<double>);
84-
if (existing == null)
85-
return options.AddConverter(new JsonDoubleRoundingConverter(maxDecimals));
86-
if (existing is JsonDoubleRoundingConverter e && e.Maximum == maxDecimals)
87-
return options;
88-
throw new InvalidOperationException("A specific double converter already exists.");
89-
}
90-
91-
static JsonSerializerOptions RoundNullableDoublesCore(this JsonSerializerOptions options, int maxDecimals)
92-
{
93-
var existing = options.Converters.FirstOrDefault(c => c is JsonConverter<double?>);
94-
if (existing is JsonNullableDoubleConverter && existing.GetType() == typeof(JsonNullableDoubleConverter))
95-
{
96-
options.Converters.Remove(existing);
97-
existing = null;
98-
}
99-
if (existing == null)
100-
return options.AddConverter(new JsonNullableDoubleRoundingConverter(maxDecimals));
101-
if (existing is JsonNullableDoubleRoundingConverter e && e.Maximum == maxDecimals)
102-
return options;
103-
throw new InvalidOperationException("A specific double converter already exists.");
104-
}
105-
106-
public static JsonSerializerOptions RoundDoubles(this JsonSerializerOptions options, int maxDecimals)
107-
=> options
108-
.RoundDoublesCore(maxDecimals)
109-
.RoundNullableDoublesCore(maxDecimals);
110-
111-
public static JsonSerializerOptions NormalizeDecimals(this JsonSerializerOptions options)
112-
{
113-
var existing = options.Converters.FirstOrDefault(c => c is JsonConverter<decimal>);
114-
var existingNullable = options.Converters.FirstOrDefault(c => c is JsonConverter<decimal?>);
115-
116-
if (existing is JsonDecimalConverter && existingNullable is JsonNullableDecimalConverter)
117-
return options;
118-
119-
if (existing == null && existingNullable == null)
120-
return options
121-
.AddConverter(JsonDecimalConverter.Instance)
122-
.AddConverter(JsonNullableDecimalConverter.Instance);
123-
124-
if (existing != null)
125-
throw new InvalidOperationException("A specific decimal converter already exists.");
126-
127-
throw new InvalidOperationException("A specific Nullable<decimal> converter already exists.");
128-
}
129-
130-
static JsonSerializerOptions RoundDecimalsCore(this JsonSerializerOptions options, int maxDecimals)
131-
{
132-
var existing = options.Converters.FirstOrDefault(c => c is JsonConverter<decimal>);
133-
if (existing is JsonDecimalConverter && existing.GetType() == typeof(JsonDecimalConverter))
134-
{
135-
options.Converters.Remove(existing);
136-
existing = null;
137-
}
138-
if (existing == null)
139-
return options.AddConverter(new JsonDecimalRoundingConverter(maxDecimals));
140-
if (existing is JsonDecimalRoundingConverter e && e.Maximum == maxDecimals)
141-
return options;
142-
throw new InvalidOperationException("A specific decimal converter already exists.");
143-
}
144-
145-
static JsonSerializerOptions RoundNullableDecimalsCore(this JsonSerializerOptions options, int maxDecimals)
146-
{
147-
var existing = options.Converters.FirstOrDefault(c => c is JsonConverter<decimal?>);
148-
if (existing is JsonNullableDecimalConverter && existing.GetType() == typeof(JsonNullableDecimalConverter))
149-
{
150-
options.Converters.Remove(existing);
151-
existing = null;
152-
}
153-
if (existing == null)
154-
return options.AddConverter(new JsonNullableDecimalRoundingConverter(maxDecimals));
155-
if (existing is JsonNullableDecimalRoundingConverter e && e.Maximum == maxDecimals)
156-
return options;
157-
throw new InvalidOperationException("A specific Nullable<decimal> converter already exists.");
158-
}
159-
160-
public static JsonSerializerOptions RoundDecimals(this JsonSerializerOptions options, int maxDecimals)
161-
=> options
162-
.RoundDecimalsCore(maxDecimals)
163-
.RoundNullableDecimalsCore(maxDecimals);
16443
}
16544
}
Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,37 @@
1-
using System.Threading;
1+
using System;
2+
using System.Threading;
23
using Utf8Json;
4+
using Utf8Json.Resolvers;
35

4-
namespace Open.Serialization.Json.System
6+
namespace Open.Serialization.Json.Utf8Json
57
{
68
public class JsonSerializerFactory : JsonSerializerFactoryBase
79
{
8-
static readonly IJsonFormatterResolver DefaultOptions = RelaxedJson.Options();
9-
readonly IJsonFormatterResolver _options;
10-
public JsonSerializerFactory(IJsonFormatterResolver defaultOptions = null)
10+
readonly IJsonFormatterResolver _resolver;
11+
readonly bool _indent;
12+
public JsonSerializerFactory(IJsonFormatterResolver defaultResolver = null, bool indent = false)
1113
{
12-
_options = defaultOptions?.Clone() ?? DefaultOptions;
14+
_resolver = defaultResolver ?? StandardResolver.Default;
15+
_indent = indent;
1316
}
1417

1518
JsonSerializerInternal _default;
16-
JsonSerializerInternal _caseSensitive;
17-
JsonSerializerInternal _ignoreCase;
19+
JsonSerializerInternal Default => LazyInitializer.EnsureInitialized(ref _default, () => new JsonSerializerInternal(_resolver, _indent));
1820

19-
protected override SerializerBase GetDeserializerInternal(bool caseSensitive)
20-
=> caseSensitive
21-
? LazyInitializer.EnsureInitialized(ref _caseSensitive,
22-
() => new JsonSerializerInternal(_options.Clone().SetPropertyNameCaseInsensitive(false)))
23-
: LazyInitializer.EnsureInitialized(ref _ignoreCase,
24-
() => new JsonSerializerInternal(_options.Clone().SetPropertyNameCaseInsensitive(true)));
25-
26-
protected override SerializerBase GetSerializerInternal(IJsonSerializationOptions options)
21+
public override IJsonSerializer GetSerializer(IJsonSerializationOptions options = null, bool caseSensitive = false)
2722
{
23+
if (caseSensitive)
24+
throw new NotSupportedException("Utf8Json does not support case-sensitive deserialization.");
25+
2826
if (options == null)
29-
return LazyInitializer.EnsureInitialized(ref _default, () => new JsonSerializerInternal(_options));
27+
return Default;
3028

31-
var o = _options.Clone();
32-
o.IgnoreNullValues = options.OmitNull;
33-
o.WriteIndented = options.Indent;
34-
o.DictionaryKeyPolicy = options.CamelCaseKeys ? JsonNamingPolicy.CamelCase : null;
35-
o.PropertyNamingPolicy = options.CamelCaseProperties ? JsonNamingPolicy.CamelCase : null;
29+
if (options.CamelCaseKeys)
30+
throw new NotSupportedException("Utf8Json does not support camel casing keys.");
3631

37-
return new JsonSerializerInternal(o);
32+
return options.CamelCaseProperties
33+
? new JsonSerializerInternal(options.OmitNull ? StandardResolver.ExcludeNullCamelCase : StandardResolver.CamelCase, options.Indent)
34+
: new JsonSerializerInternal(options.OmitNull ? StandardResolver.ExcludeNull : StandardResolver.Default, options.Indent);
3835
}
3936
}
4037
}
Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,79 @@
1-
using Utf8Json;
1+
using System.IO;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using Utf8Json;
25

3-
namespace Open.Serialization.Json.System
6+
namespace Open.Serialization.Json.Utf8Json
47
{
5-
internal class JsonSerializerInternal : SerializerBase, IJsonSerializer
8+
internal class JsonSerializerInternal : JsonSerializerBase, IJsonSerializer
69
{
7-
readonly IJsonFormatterResolver _options;
8-
internal JsonSerializerInternal(IJsonFormatterResolver options)
10+
readonly IJsonFormatterResolver _resolver;
11+
readonly bool _indent;
12+
internal JsonSerializerInternal(IJsonFormatterResolver resolver, bool indent)
913
{
10-
_options = options;
14+
_resolver = resolver;
15+
_indent = indent;
1116
}
12-
17+
1318
public override T Deserialize<T>(string value)
14-
=> JsonSerializer.Deserialize<T>(value, _options);
19+
=> JsonSerializer.Deserialize<T>(value, _resolver);
20+
21+
public new Task<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default)
22+
=> JsonSerializer.DeserializeAsync<T>(stream, _resolver);
23+
24+
ValueTask<T> IDeserializeAsync.DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken)
25+
=> new ValueTask<T>(DeserializeAsync<T>(stream, cancellationToken));
1526

1627
public override string Serialize<T>(T item)
17-
=> JsonSerializer.ToJsonString(item, _options);
28+
{
29+
var json = JsonSerializer.ToJsonString(item, _resolver);
30+
return _indent ? JsonSerializer.PrettyPrint(json) : json;
31+
}
32+
33+
public new Task SerializeAsync<T>(Stream stream, T item, CancellationToken cancellationToken = default)
34+
{
35+
if (!_indent) return JsonSerializer.SerializeAsync(stream, item);
36+
37+
var result = JsonSerializer.PrettyPrintByteArray(JsonSerializer.Serialize(item));
38+
return stream.WriteAsync(result, 0, result.Length, cancellationToken);
39+
}
40+
41+
ValueTask ISerializeAsync.SerializeAsync<T>(Stream stream, T item, CancellationToken cancellationToken)
42+
=> new ValueTask(SerializeAsync(stream, item, cancellationToken));
43+
1844
}
1945

20-
internal class JsonSerializerInternal<T> : Serializer<T>, IJsonSerializer<T>
46+
internal class JsonSerializerInternal<T> : JsonSerializerBase<T>, IJsonSerializer<T>
2147
{
22-
internal JsonSerializerInternal(IJsonFormatterResolver options)
23-
:base(options.GetDeserialize<T>(), options.GetSerialize<T>())
48+
readonly IJsonFormatterResolver _resolver;
49+
readonly bool _indent;
50+
internal JsonSerializerInternal(IJsonFormatterResolver resolver, bool indent)
51+
{
52+
_resolver = resolver;
53+
_indent = indent;
54+
}
55+
56+
public override T Deserialize(string value)
57+
=> JsonSerializer.Deserialize<T>(value, _resolver);
58+
59+
public new Task SerializeAsync(Stream stream, T item, CancellationToken cancellationToken = default)
2460
{
61+
if (!_indent) return JsonSerializer.SerializeAsync(stream, item);
62+
63+
var result = JsonSerializer.PrettyPrintByteArray(JsonSerializer.Serialize(item));
64+
return stream.WriteAsync(result, 0, result.Length, cancellationToken);
2565
}
66+
67+
ValueTask ISerializeAsync<T>.SerializeAsync(Stream stream, T item, CancellationToken cancellationToken)
68+
=> new ValueTask(SerializeAsync(stream, item, cancellationToken));
69+
70+
public override string Serialize(T item)
71+
=> JsonSerializer.ToJsonString(item, _resolver);
72+
73+
public new Task<T> DeserializeAsync(Stream stream, CancellationToken cancellationToken = default)
74+
=> JsonSerializer.DeserializeAsync<T>(stream, _resolver);
75+
76+
ValueTask<T> IDeserializeAsync<T>.DeserializeAsync(Stream stream, CancellationToken cancellationToken)
77+
=> new ValueTask<T>(DeserializeAsync(stream, cancellationToken));
2678
}
2779
}

Open.Serialization.Json.Utf8Json/Open.Serialization.Json.Utf8Json.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Part of the "Open" set of libraries.
2121
</PropertyGroup>
2222

2323
<ItemGroup>
24-
<PackageReference Include="Open.Serialization.Json" Version="1.0.1" />
24+
<PackageReference Include="Open.Serialization.Json" Version="1.2.0" />
2525
<PackageReference Include="Utf8Json" Version="1.3.7" />
2626
</ItemGroup>
2727

Open.Serialization.Tests/ParityTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Open.Serialization.Json;
2+
using Open.Serialization.Json.Utf8Json;
23
using Xunit;
34

45
namespace Open.Serialization.Tests
@@ -15,6 +16,13 @@ public static void EnsureBasicParity()
1516
CompareFactories(newtonsoftFactory, systemFactory);
1617
}
1718

19+
{
20+
var newtonsoftFactory = new Json.Newtonsoft.JsonSerializerFactory(Json.Newtonsoft.CamelCaseJson.Minimal(true));
21+
var systemFactory = new JsonSerializerFactory(Utf8Json.Resolvers.StandardResolver.ExcludeNullCamelCase, true);
22+
23+
CompareFactories(newtonsoftFactory, systemFactory);
24+
}
25+
1826
{
1927
var newtonsoftFactory = new Json.Newtonsoft.JsonSerializerFactory();
2028
var systemFactory = new Json.System.JsonSerializerFactory();

Open.Serialization.Tests/SampleModel.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public class SampleModel
1212

1313
public int IntegerValue { get; set; } = 11;
1414

15-
public double DoubleValue { get; set; } = 1.2345678901234567891234;
16-
public decimal DecimalValue1 { get; set; } = 1.2345678901234567891234m;
15+
public double DoubleValue { get; set; } = 1.2345678901234567;
16+
public decimal DecimalValue1 { get; set; } = 1.2345678901234567m;
1717

1818
public decimal DecimalValue2 { get; set; } = 1.2345000m;
1919
public decimal DecimalValue3 { get; set; } = 11.000m;
@@ -26,8 +26,8 @@ public class SampleModel
2626

2727
public double? NullableDoubleNull { get; set; } = null;
2828

29-
public double? NullableDoubleValue { get; set; } = 1.2345678901234567891234;
30-
public decimal? NullableDecimalValue { get; set; } = 1.2345678901234567891234m;
29+
public double? NullableDoubleValue { get; set; } = 1.2345678901234567;
30+
public decimal? NullableDecimalValue { get; set; } = 1.2345678901234567m;
3131
public decimal? NullableDecimalNull { get; set; } = null;
3232

3333
public SampleModel Child { get; set; }

0 commit comments

Comments
 (0)