diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml
index 9f8f20b..0edd1ac 100644
--- a/.github/workflows/build-and-test.yaml
+++ b/.github/workflows/build-and-test.yaml
@@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
build-configuration: [ Debug, Release ]
- test-target-framework: [ net6.0, net5.0, netcoreapp3.1 ]
+ test-target-framework: [ net8.0, net7.0, net6.0 ]
name: Build And Test (${{ matrix.test-target-framework }}, ${{ matrix.build-configuration }})
runs-on: ubuntu-latest
steps:
@@ -20,9 +20,9 @@ jobs:
uses: actions/setup-dotnet@v2
with:
dotnet-version: |
+ 8.x
+ 7.x
6.x
- 5.x
- 3.1.x
- name: Restore
run: dotnet restore ${{ env.JsonDiffPatchSolutionPath }}
- name: Build
diff --git a/README.md b/README.md
index 0947e19..1ed55e9 100644
--- a/README.md
+++ b/README.md
@@ -8,13 +8,12 @@ High-performance, low-allocating JSON object diff and patch extension for System
- Compatible with [jsondiffpatch delta format](https://github.com/benjamine/jsondiffpatch/blob/master/docs/deltas.md)
- Support generating patch document in RFC 6902 JSON Patch format
-- Target latest **.NET Standard** and **.NET Framework 4.6.1** (for legacy apps) and leverage latest .NET features
+- Support .NET and .NET Framework
- Alternative to [jsondiffpatch.net](https://github.com/wbish/jsondiffpatch.net) which is based on Newtonsoft.Json
- Fast large JSON document diffing with less memory consumption (see [benchmark](https://github.com/weichch/system-text-json-jsondiffpatch/blob/main/Benchmark.md))
- Support smart array diffing (e.g. move detect) using LCS (Longest Common Subsequence) and custom array item matcher
- _(Only when not using RFC 6902 format)_ Support diffing long text using [google-diff-match-patch](http://code.google.com/p/google-diff-match-patch/), or write your own diff algorithm
- Bonus `DeepEquals` method for comparing `JsonDocument`, `JsonElement` and `JsonNode`
-- Bonus `DeepClone` method
- Bonus [`JsonValueComparer`](https://github.com/weichch/system-text-json-jsondiffpatch/blob/main/src/SystemTextJson.JsonDiffPatch/JsonValueComparer.cs) that implements semantic comparison of two `JsonValue` objects
- JSON assert for xUnit, MSTest v2 and NUnit with customizable delta output
@@ -44,7 +43,7 @@ PM> Install-Package SystemTextJson.JsonDiffPatch.MSTest
PM> Install-Package SystemTextJson.JsonDiffPatch.NUnit
```
-## Usage
+## Examples
### Diff
@@ -106,13 +105,6 @@ var textEqual = node1.DeepEquals(node2, JsonElementComparison.RawText);
var semanticEqual = node1.DeepEquals(node2, JsonElementComparison.Semantic);
```
-### DeepClone
-
-```csharp
-var node = JsonNode.Parse("{\"foo\":\"bar\"}");
-var cloned = node.DeepClone();
-```
-
### Default Options
```csharp
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index 8e0b1b9..231e045 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -1,5 +1,18 @@
# Release Notes
+## 2.0.0
+
+- This version contains several **BREAKING CHANGES**:
+ - **Targeting framework changes**:
+ - Added: .NET 8, .NET 7, .NET 6, .NET Framework 4.6.2
+ - Removed: .NET Standard 2.1, .NET Framework 4.6.1
+ - Minimum version of `System.Text.Json` required is bumped up to `8.0.0`
+ - `JsonDiffPatcher.DeepEquals(JsonNode)` now simply calls `JsonNode.DeepEquals(JsonNode, JsonNode)` method introduced in [this issue](https://github.com/dotnet/runtime/issues/56592)
+ - `JsonDiffPatcher.Diff` method is unchanged because it does not use `JsonNode.DeepEquals(JsonNode, JsonNode)` method internally
+ - You can still use `JsonDiffPatcher.DeepEquals` method when invoked with custom comparison options
+ - When invoked against `JsonDocument` and `JsonElement`, `DeepEquals` method is unchanged
+ - Removed `JsonDiffPatcher.DeepClone` method. You can migrate to `JsonNode.DeepClone` method introduced in [this issue](https://github.com/dotnet/runtime/issues/56592)
+
## 1.3.1
- Added `PropertyFilter` to `JsonDiffOptions` (#29)
diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt
index 8c0b939..3d2deae 100644
--- a/THIRD-PARTY-NOTICES.txt
+++ b/THIRD-PARTY-NOTICES.txt
@@ -2,7 +2,9 @@ system-text-json-jsondiffpatch uses third-party libraries or other resources tha
distributed under licenses different than system-text-json-jsondiffpatch.
In the event that we accidentally failed to list a required notice, please
-bring it to our attention. Please post an issue.
+bring it to our attention.
+
+Please post an issue at https://github.com/weichch/system-text-json-jsondiffpatch/issues
The attached notices are provided for information only.
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index a58122d..8cb48b8 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,7 +1,7 @@
- netstandard2.0;netstandard2.1;net461
+ net8.0;net7.0;net6.0;netstandard2.0;net462
enable
latest
true
@@ -9,10 +9,10 @@
- 1.3.1
+ 2.0.0
Wei Chen
https://github.com/weichch/system-text-json-jsondiffpatch
- Copyright © Wei Chen 2022
+ Copyright © Wei Chen 2024
icon.png
LICENSE
https://github.com/weichch/system-text-json-jsondiffpatch/blob/$(JsonDiffPatchPackageVersion)/ReleaseNotes.md
@@ -27,6 +27,7 @@
+
diff --git a/src/SystemTextJson.JsonDiffPatch.MSTest/JsonAssert.cs b/src/SystemTextJson.JsonDiffPatch.MSTest/JsonAssert.cs
index f24b52d..9fd6663 100644
--- a/src/SystemTextJson.JsonDiffPatch.MSTest/JsonAssert.cs
+++ b/src/SystemTextJson.JsonDiffPatch.MSTest/JsonAssert.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
+using System.Text.Json.Serialization.Metadata;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace System.Text.Json.JsonDiffPatch.MsTest
@@ -8,7 +9,18 @@ namespace System.Text.Json.JsonDiffPatch.MsTest
///
public static class JsonAssert
{
- private static readonly JsonSerializerOptions SerializerOptions = new() {WriteIndented = true};
+ private static readonly JsonSerializerOptions SerializerOptions;
+
+ static JsonAssert()
+ {
+ SerializerOptions = new()
+ {
+ TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
+ WriteIndented = true
+ };
+
+ SerializerOptions.MakeReadOnly();
+ }
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
diff --git a/src/SystemTextJson.JsonDiffPatch.NUnit/JsonAssert.cs b/src/SystemTextJson.JsonDiffPatch.NUnit/JsonAssert.cs
index b1ff3a0..3534a1a 100644
--- a/src/SystemTextJson.JsonDiffPatch.NUnit/JsonAssert.cs
+++ b/src/SystemTextJson.JsonDiffPatch.NUnit/JsonAssert.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
+using System.Text.Json.Serialization.Metadata;
using NUnit.Framework;
namespace System.Text.Json.JsonDiffPatch.Nunit
@@ -8,7 +9,18 @@ namespace System.Text.Json.JsonDiffPatch.Nunit
///
public static class JsonAssert
{
- private static readonly JsonSerializerOptions SerializerOptions = new() {WriteIndented = true};
+ private static readonly JsonSerializerOptions SerializerOptions;
+
+ static JsonAssert()
+ {
+ SerializerOptions = new()
+ {
+ TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
+ WriteIndented = true
+ };
+
+ SerializerOptions.MakeReadOnly();
+ }
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
@@ -179,7 +191,7 @@ public static void JsonAreEqual(this Assert assert, string? expected, string? ac
/// Whether to print diff result.
public static void JsonAreEqual(this Assert assert, string? expected, string? actual, bool output)
=> AreEqual(expected, actual, output);
-
+
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -191,7 +203,7 @@ public static void JsonAreEqual(this Assert assert, string? expected, string? ac
public static void JsonAreEqual(this Assert assert, string? expected, string? actual,
JsonDiffOptions diffOptions)
=> AreEqual(expected, actual, diffOptions);
-
+
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -204,7 +216,7 @@ public static void JsonAreEqual(this Assert assert, string? expected, string? ac
public static void JsonAreEqual(this Assert assert, string? expected, string? actual,
JsonDiffOptions diffOptions, bool output)
=> AreEqual(expected, actual, diffOptions, output);
-
+
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -230,7 +242,7 @@ public static void JsonAreEqual(this Assert assert, string? expected, string? ac
JsonDiffOptions diffOptions,
Func outputFormatter)
=> AreEqual(expected, actual, diffOptions, outputFormatter);
-
+
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -242,7 +254,7 @@ public static void JsonAreEqual(this Assert assert, string? expected, string? ac
public static void JsonAreEqual(this Assert assert, T? expected, T? actual)
where T : JsonNode
=> AreEqual(expected, actual);
-
+
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -255,7 +267,7 @@ public static void JsonAreEqual(this Assert assert, T? expected, T? actual)
public static void JsonAreEqual(this Assert assert, T? expected, T? actual, bool output)
where T : JsonNode
=> AreEqual(expected, actual, output);
-
+
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -268,7 +280,7 @@ public static void JsonAreEqual(this Assert assert, T? expected, T? actual, b
public static void JsonAreEqual(this Assert assert, T? expected, T? actual, JsonDiffOptions diffOptions)
where T : JsonNode
=> AreEqual(expected, actual, diffOptions);
-
+
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -283,7 +295,7 @@ public static void JsonAreEqual(this Assert assert, T? expected, T? actual,
JsonDiffOptions diffOptions, bool output)
where T : JsonNode
=> AreEqual(expected, actual, diffOptions, output);
-
+
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -378,7 +390,7 @@ public static void AreNotEqual(string? expected, string? actual)
public static void AreNotEqual(string? expected, string? actual, JsonDiffOptions diffOptions)
=> AreNotEqual(expected is null ? null : JsonNode.Parse(expected),
actual is null ? null : JsonNode.Parse(actual), diffOptions);
-
+
///
/// Tests whether two JSON objects are not equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -389,7 +401,7 @@ public static void AreNotEqual(string? expected, string? actual, JsonDiffOptions
public static void AreNotEqual(T? expected, T? actual)
where T : JsonNode
=> HandleAreNotEqual(expected, actual, null);
-
+
///
/// Tests whether two JSON objects are not equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -402,7 +414,7 @@ public static void AreNotEqual(T? expected, T? actual, JsonDiffOptions diffOp
where T : JsonNode
=> HandleAreNotEqual(expected, actual,
diffOptions ?? throw new ArgumentNullException(nameof(diffOptions)));
-
+
///
/// Tests whether two JSON objects are not equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -412,7 +424,7 @@ public static void AreNotEqual(T? expected, T? actual, JsonDiffOptions diffOp
/// The actual value.
public static void JsonAreNotEqual(this Assert assert, string? expected, string? actual)
=> AreNotEqual(expected, actual);
-
+
///
/// Tests whether two JSON objects are not equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -424,7 +436,7 @@ public static void JsonAreNotEqual(this Assert assert, string? expected, string?
public static void JsonAreNotEqual(this Assert assert, string? expected, string? actual,
JsonDiffOptions diffOptions)
=> AreNotEqual(expected, actual, diffOptions);
-
+
///
/// Tests whether two JSON objects are not equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
@@ -436,7 +448,7 @@ public static void JsonAreNotEqual(this Assert assert, string? expected, string?
public static void JsonAreNotEqual(this Assert assert, T? expected, T? actual)
where T : JsonNode
=> AreNotEqual(expected, actual);
-
+
///
/// Tests whether two JSON objects are not equal. Note that when comparing the specified objects,
/// the ordering of members in the objects is not significant.
diff --git a/src/SystemTextJson.JsonDiffPatch.Xunit/JsonAssert.cs b/src/SystemTextJson.JsonDiffPatch.Xunit/JsonAssert.cs
index fcc56d5..81b5ee4 100644
--- a/src/SystemTextJson.JsonDiffPatch.Xunit/JsonAssert.cs
+++ b/src/SystemTextJson.JsonDiffPatch.Xunit/JsonAssert.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
+using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.JsonDiffPatch.Xunit
{
@@ -7,7 +8,18 @@ namespace System.Text.Json.JsonDiffPatch.Xunit
///
public static class JsonAssert
{
- private static readonly JsonSerializerOptions SerializerOptions = new() {WriteIndented = true};
+ private static readonly JsonSerializerOptions SerializerOptions;
+
+ static JsonAssert()
+ {
+ SerializerOptions = new()
+ {
+ TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
+ WriteIndented = true
+ };
+
+ SerializerOptions.MakeReadOnly();
+ }
///
/// Tests whether two JSON objects are equal. Note that when comparing the specified objects,
diff --git a/src/SystemTextJson.JsonDiffPatch/Diffs/JsonDiffDelta.cs b/src/SystemTextJson.JsonDiffPatch/Diffs/JsonDiffDelta.cs
index 5300504..7cbd5dc 100644
--- a/src/SystemTextJson.JsonDiffPatch/Diffs/JsonDiffDelta.cs
+++ b/src/SystemTextJson.JsonDiffPatch/Diffs/JsonDiffDelta.cs
@@ -244,22 +244,22 @@ public void Added(JsonNode? newValue)
{
EnsureDeltaType(nameof(Added), count: 1);
var arr = Document!.AsArray();
- arr[0] = newValue.DeepClone();
+ arr[0] = newValue?.DeepClone();
}
public void Modified(JsonNode? oldValue, JsonNode? newValue)
{
EnsureDeltaType(nameof(Modified), count: 2);
var arr = Document!.AsArray();
- arr[0] = oldValue.DeepClone();
- arr[1] = newValue.DeepClone();
+ arr[0] = oldValue?.DeepClone();
+ arr[1] = newValue?.DeepClone();
}
public void Deleted(JsonNode? oldValue)
{
EnsureDeltaType(nameof(Deleted), count: 3, opType: OpTypeDeleted);
var arr = Document!.AsArray();
- arr[0] = oldValue.DeepClone();
+ arr[0] = oldValue?.DeepClone();
arr[1] = 0;
}
diff --git a/src/SystemTextJson.JsonDiffPatch/JsonDiffPatcher.Clone.cs b/src/SystemTextJson.JsonDiffPatch/JsonDiffPatcher.Clone.cs
deleted file mode 100644
index 8296cca..0000000
--- a/src/SystemTextJson.JsonDiffPatch/JsonDiffPatcher.Clone.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.Json.Nodes;
-
-namespace System.Text.Json.JsonDiffPatch
-{
- static partial class JsonDiffPatcher
- {
- ///
- /// Creates a deep copy of the .
- ///
- /// The .
- public static T? DeepClone(this T? obj) where T : JsonNode
- {
- return (T?)(obj switch
- {
- null => (JsonNode?)null,
- JsonObject jsonObj => new JsonObject(Enumerate(jsonObj), obj.Options),
- JsonArray array => CloneArray(array),
- JsonValue value => CloneJsonValue(value),
- _ => throw new NotSupportedException(
- $"JsonNode of type '{obj.GetType().Name}' is not supported.")
- });
-
- static IEnumerable> Enumerate(JsonObject obj)
- {
- foreach (var kvp in obj)
- {
- yield return new KeyValuePair(kvp.Key, kvp.Value.DeepClone());
- }
- }
- }
-
- private static JsonValue? CloneJsonValue(JsonValue? value)
- {
- if (value is null)
- {
- return null;
- }
-
- if (value.TryGetValue(out var element))
- return JsonValue.Create(element.Clone(), value.Options);
- if (value.TryGetValue(out var intValue))
- return JsonValue.Create(intValue, value.Options);
- if (value.TryGetValue(out var longValue))
- return JsonValue.Create(longValue, value.Options);
- if (value.TryGetValue(out var doubleValue))
- return JsonValue.Create(doubleValue, value.Options);
- if (value.TryGetValue(out var shortValue))
- return JsonValue.Create(shortValue, value.Options);
- if (value.TryGetValue(out var decimalValue))
- return JsonValue.Create(decimalValue, value.Options);
- if (value.TryGetValue(out var byteValue))
- return JsonValue.Create(byteValue, value.Options);
- if (value.TryGetValue(out var floatValue))
- return JsonValue.Create(floatValue, value.Options);
- if (value.TryGetValue(out var uintValue))
- return JsonValue.Create(uintValue, value.Options);
- if (value.TryGetValue(out var ushortValue))
- return JsonValue.Create(ushortValue, value.Options);
- if (value.TryGetValue(out var ulongValue))
- return JsonValue.Create(ulongValue, value.Options);
- if (value.TryGetValue(out var sbyteValue))
- return JsonValue.Create(sbyteValue, value.Options);
- if (value.TryGetValue(out var stringValue))
- return JsonValue.Create(stringValue, value.Options);
- if (value.TryGetValue(out var dateTimeValue))
- return JsonValue.Create(dateTimeValue, value.Options);
- if (value.TryGetValue(out var dateTimeOffsetValue))
- return JsonValue.Create(dateTimeOffsetValue, value.Options);
- if (value.TryGetValue(out var guidValue))
- return JsonValue.Create(guidValue, value.Options);
- if (value.TryGetValue(out var charValue))
- return JsonValue.Create(charValue, value.Options);
- if (value.TryGetValue(out var byteArrayValue))
- return JsonValue.Create(byteArrayValue, value.Options);
-
- // Perf: This is slower than direct property access
- return JsonValue.Create(value.GetValue