Skip to content

Commit 835b1fb

Browse files
authored
Remove usage of Newtonsoft.Json in favor of System.Text.Json (#1932)
1 parent f0ab8e0 commit 835b1fb

File tree

12 files changed

+202
-117
lines changed

12 files changed

+202
-117
lines changed

Directory.Packages.props

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
1616
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
1717
<PackageVersion Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.1.0" />
18-
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
1918
<PackageVersion Include="NSubstitute" Version="5.3.0" />
2019
<PackageVersion Include="NuGet.Common" Version="6.13.2" />
2120
<PackageVersion Include="NuGet.Packaging" Version="6.13.2" />

gen/DocumentFormat.OpenXml.Generator.Models/Converters/QualifiedNameConverter.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,26 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using DocumentFormat.OpenXml.Generator.Models;
5-
using Newtonsoft.Json;
5+
using System;
6+
using System.Text.Json;
7+
using System.Text.Json.Serialization;
68

79
namespace DocumentFormat.OpenXml.Generator.Converters;
810

911
internal class QualifiedNameConverter : JsonConverter<QName>
1012
{
11-
public override QName? ReadJson(JsonReader reader, Type objectType, QName? existingValue, bool hasExistingValue, JsonSerializer serializer)
13+
public override QName? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1214
{
13-
if (reader.TokenType != JsonToken.String)
15+
if (reader.TokenType != JsonTokenType.String)
1416
{
1517
throw new InvalidOperationException("QName must be encoded as a string");
1618
}
1719

18-
var str = serializer.Deserialize<string>(reader) ?? string.Empty;
19-
20+
var str = reader.GetString() ?? string.Empty;
2021
return QName.Parse(str);
2122
}
2223

23-
public override void WriteJson(JsonWriter writer, QName? value, JsonSerializer serializer)
24+
public override void Write(Utf8JsonWriter writer, QName value, JsonSerializerOptions options)
2425
{
2526
throw new NotImplementedException();
2627
}

gen/DocumentFormat.OpenXml.Generator.Models/Converters/TypedQNameConverter.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using DocumentFormat.OpenXml.Generator.Models;
5-
using Newtonsoft.Json;
5+
using System;
6+
using System.Text.Json;
7+
using System.Text.Json.Serialization;
68

79
namespace DocumentFormat.OpenXml.Generator.Converters;
810

911
internal class TypedQNameConverter : JsonConverter<TypedQName>
1012
{
11-
public override TypedQName? ReadJson(JsonReader reader, Type objectType, TypedQName? existingValue, bool hasExistingValue, JsonSerializer serializer)
13+
public override TypedQName? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1214
{
13-
if (reader.TokenType != JsonToken.String)
15+
if (reader.TokenType != JsonTokenType.String)
1416
{
1517
throw new InvalidOperationException("TypedQName must be encoded as a string");
1618
}
1719

18-
var str = serializer.Deserialize<string>(reader) ?? string.Empty;
20+
var str = reader.GetString() ?? string.Empty;
1921
var split = str.Split('/');
2022

2123
if (split.Length != 2)
@@ -26,7 +28,7 @@ internal class TypedQNameConverter : JsonConverter<TypedQName>
2628
return new TypedQName(QName.Parse(split[0]), QName.Parse(split[1]));
2729
}
2830

29-
public override void WriteJson(JsonWriter writer, TypedQName? value, JsonSerializer serializer)
31+
public override void Write(Utf8JsonWriter writer, TypedQName value, JsonSerializerOptions options)
3032
{
3133
throw new NotImplementedException();
3234
}

gen/DocumentFormat.OpenXml.Generator.Models/DocumentFormat.OpenXml.Generator.Models.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<RootNamespace>DocumentFormat.OpenXml.Generator</RootNamespace>
1010
</PropertyGroup>
1111
<ItemGroup>
12-
<PackageReference Include="Newtonsoft.Json" PrivateAssets="all" />
12+
<PackageReference Include="System.Text.Json" PrivateAssets="all" />
1313
</ItemGroup>
1414
<ItemGroup>
1515
<PackageReference Include="System.Collections.Immutable" />

gen/DocumentFormat.OpenXml.Generator.Models/OpenXmlGeneratorDataSource.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,25 @@
44
using DocumentFormat.OpenXml.Generator.Converters;
55
using DocumentFormat.OpenXml.Generator.Models;
66
using DocumentFormat.OpenXml.Generator.Schematron;
7-
using Newtonsoft.Json;
8-
using Newtonsoft.Json.Converters;
97
using System.Collections.Immutable;
8+
using System.Text.Json;
9+
using System.Text.Json.Serialization;
1010

1111
namespace DocumentFormat.OpenXml.Generator;
1212

1313
public record OpenXmlGeneratorDataSource
1414
{
15-
private static readonly JsonSerializerSettings _settings = new()
15+
private static readonly JsonSerializerOptions _options = new()
1616
{
1717
Converters =
1818
{
19-
new StringEnumConverter(),
19+
new JsonStringEnumConverter(),
2020
new QualifiedNameConverter(),
2121
new TypedQNameConverter(),
2222
},
2323
};
2424

25-
public static T? Deserialize<T>(string? content) => content is null ? default : JsonConvert.DeserializeObject<T>(content, _settings);
25+
public static T? Deserialize<T>(string? content) => content is null ? default : JsonSerializer.Deserialize<T>(content, _options);
2626

2727
public ImmutableArray<NamespaceInfo> KnownNamespaces { get; init; } = ImmutableArray.Create<NamespaceInfo>();
2828

gen/DocumentFormat.OpenXml.Generator/SourceGenerator.targets

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
<ItemGroup>
88
<ProjectReference Include="@(OoxGenerator)" OutputItemType="Analyzer" ReferenceOutputAssembly="false" SkipGetTargetFrameworkProperties="true" GlobalPropertiesToRemove="TargetFramework" />
99
</ItemGroup>
10-
<ItemGroup>
11-
<PackageReference Include="Newtonsoft.Json" PrivateAssets="all" GeneratePathProperty="true" />
12-
<Analyzer Include="$(PkgNewtonsoft_Json)\lib\netstandard2.0\*.dll" Visible="false" />
13-
</ItemGroup>
10+
1411
<ItemGroup>
1512
<AdditionalFiles Include="@(OpenXmlDataNamespace)" OpenXml="Namespace" LinkBase="data" />
1613
<AdditionalFiles Include="@(OpenXmlDataSchematron)" OpenXml="Schematron" LinkBase="data" />

test/Directory.Build.targets

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
</ItemGroup>
1919

2020
<ItemGroup>
21-
<PackageReference Include="Newtonsoft.Json" />
2221
<PackageReference Include="System.Text.Json" />
2322
<PackageReference Include="System.ValueTuple" />
2423
<PackageReference Include="Microsoft.NET.Test.Sdk" />

test/DocumentFormat.OpenXml.Framework.Tests/TestUtility.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44
using System;
55
using System.IO;
66
using System.Reflection;
7+
using System.Text.Encodings.Web;
78
using System.Text.Json;
89
using System.Text.Json.Serialization;
10+
using Xunit;
911

1012
namespace DocumentFormat.OpenXml.Framework.Tests
1113
{
1214
internal static class TestUtility
1315
{
1416
private static readonly JsonSerializerOptions _options = new()
1517
{
18+
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
1619
Converters =
1720
{
1821
new OpenXmlNamespaceConverter(),
@@ -22,6 +25,17 @@ internal static class TestUtility
2225
WriteIndented = true,
2326
};
2427

28+
public static void ValidateJsonFileContentsAreEqual(Stream stream1, Stream stream2)
29+
{
30+
using var reader1 = new StreamReader(stream1);
31+
using var reader2 = new StreamReader(stream2);
32+
33+
var expected = reader1.ReadToEnd().Replace("\r\n", "\n");
34+
var actual = reader2.ReadToEnd().Replace("\r\n", "\n");
35+
36+
Assert.Equal(expected, actual);
37+
}
38+
2539
#nullable enable
2640

2741
public static T? Deserialize<T>(string name)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
// Copyright (c) Microsoft. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4-
using DocumentFormat.OpenXml.Framework;
54
using DocumentFormat.OpenXml.Framework.Tests;
6-
using System;
75
using System.IO;
86
using Xunit;
97

108
namespace DocumentFormat.OpenXml.Tests
119
{
1210
internal static class ITestOutputHelperExtenstions
1311
{
14-
public static void WriteObjectToTempFile<T>(this ITestOutputHelper output, string name, T obj)
12+
public static string WriteObjectToTempFile<T>(this ITestOutputHelper output, string name, T obj)
1513
{
1614
var tmp = Path.GetTempFileName();
1715

1816
output.WriteLine($"Wrote {name} to temp path {tmp}");
1917

2018
File.WriteAllText(tmp, TestUtility.Serialize(obj));
19+
20+
return tmp;
2121
}
2222
}
2323
}

test/DocumentFormat.OpenXml.Packaging.Tests/PartConstraintRuleTests.cs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33

44
using DocumentFormat.OpenXml.Features;
55
using DocumentFormat.OpenXml.Framework;
6+
using DocumentFormat.OpenXml.Framework.Tests;
67
using DocumentFormat.OpenXml.Packaging;
7-
using Newtonsoft.Json;
8-
using Newtonsoft.Json.Converters;
8+
using DocumentFormat.OpenXml.Packaging.Tests;
99
using NSubstitute;
1010
using System;
1111
using System.Collections.Generic;
1212
using System.IO;
1313
using System.Linq;
1414
using System.Reflection;
15+
using System.Text.Json;
16+
using System.Text.Json.Serialization;
1517
using Xunit;
1618

1719
namespace DocumentFormat.OpenXml.Tests
@@ -86,10 +88,9 @@ public void ValidatePart(Type partType)
8688
}
8789

8890
Assert.NotNull(expectedConstraints.Parts);
89-
#if DEBUG
91+
9092
_output.WriteObjectToTempFile("expected constraints", expectedConstraints.Parts.OrderBy(p => p.RelationshipType));
9193
_output.WriteObjectToTempFile("actual constraints", constraints.Rules.OrderBy(p => p.RelationshipType).Select(p => new PartConstraintRule2(p)));
92-
#endif
9394

9495
Assert.Equal(
9596
expectedConstraints.Parts.OrderBy(p => p.RelationshipType),
@@ -119,7 +120,13 @@ public void ExportData()
119120
})
120121
.OrderBy(d => d.Name, StringComparer.Ordinal);
121122

122-
_output.WriteObjectToTempFile("typed parts", result);
123+
var output = _output.WriteObjectToTempFile("typed parts", result);
124+
125+
using (var expectedStream = typeof(ParticleTests).GetTypeInfo().Assembly.GetManifestResourceStream("DocumentFormat.OpenXml.Packaging.Tests.data.PartConstraintData.json"))
126+
using (var actualStream = new FileStream(output, FileMode.Open, FileAccess.Read))
127+
{
128+
TestUtility.ValidateJsonFileContentsAreEqual(expectedStream!, actualStream);
129+
}
123130
}
124131

125132
public static IEnumerable<object[]> GetOpenXmlParts() => GetParts().Select(p => new[] { p });
@@ -134,9 +141,7 @@ private static IEnumerable<Type> GetParts() => typeof(SpreadsheetDocument)
134141

135142
private static OpenXmlPart InitializePart(Type type)
136143
{
137-
#nullable disable
138-
var part = (OpenXmlPart)Activator.CreateInstance(type, true);
139-
#nullable enable
144+
var part = (OpenXmlPart)Activator.CreateInstance(type, true)!;
140145

141146
var appType = Substitute.For<IApplicationTypeFeature>();
142147
appType.Type.Returns(ApplicationType.None);
@@ -148,7 +153,7 @@ private static OpenXmlPart InitializePart(Type type)
148153

149154
private static ConstraintData GetConstraintData(OpenXmlPart part) => _cachedConstraintData.Value[part.GetType().FullName!];
150155

151-
private static Lazy<Dictionary<string, ConstraintData>> _cachedConstraintData = new Lazy<Dictionary<string, ConstraintData>>(() =>
156+
private static readonly Lazy<Dictionary<string, ConstraintData>> _cachedConstraintData = new(() =>
152157
{
153158
var names = typeof(PartConstraintRuleTests).GetTypeInfo().Assembly.GetManifestResourceNames();
154159

@@ -157,7 +162,15 @@ private static OpenXmlPart InitializePart(Type type)
157162
using (var reader = new StreamReader(stream!))
158163
{
159164
#nullable disable
160-
return JsonConvert.DeserializeObject<ConstraintData[]>(reader.ReadToEnd(), new StringEnumConverter())
165+
var options = new JsonSerializerOptions
166+
{
167+
Converters =
168+
{
169+
new JsonStringEnumConverter(),
170+
},
171+
};
172+
173+
return JsonSerializer.Deserialize<ConstraintData[]>(reader.ReadToEnd(), options)
161174
.ToDictionary(t => t.Name, StringComparer.Ordinal);
162175
#nullable enable
163176
}

0 commit comments

Comments
 (0)