From dacf61ddbc1c82eae0d27294a600eb0bb1f5d418 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 6 Oct 2020 17:12:57 -0700 Subject: [PATCH] Add serializer support to JsonPatchDocument (#15754) Fixes: https://github.com/Azure/azure-sdk-for-net/issues/15752 --- .../Azure.Core.Experimental.netstandard2.0.cs | 10 ++- .../src/JsonPatchDocument.cs | 62 +++++++++++++++++-- .../tests/JsonPatchDocumentTests.cs | 36 +++++++++-- 3 files changed, 94 insertions(+), 14 deletions(-) diff --git a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs index f0fa4b17845d4..7c0437c30d610 100644 --- a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs +++ b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs @@ -96,12 +96,16 @@ public void WriteTo(System.Text.Json.Utf8JsonWriter writer) { } public partial class JsonPatchDocument { public JsonPatchDocument() { } - public void AppendAdd(string path, string rawJsonValue) { } + public JsonPatchDocument(Azure.Core.Serialization.ObjectSerializer serializer) { } + public void AppendAddRaw(string path, string rawJsonValue) { } + public void AppendAdd(string path, T value, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { } public void AppendCopy(string from, string path) { } public void AppendMove(string from, string path) { } public void AppendRemove(string path) { } - public void AppendReplace(string path, string rawJsonValue) { } - public void AppendTest(string path, string rawJsonValue) { } + public void AppendReplaceRaw(string path, string rawJsonValue) { } + public void AppendReplace(string path, T value, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { } + public void AppendTestRaw(string path, string rawJsonValue) { } + public void AppendTest(string path, T value, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { } public override string ToString() { throw null; } } } diff --git a/sdk/core/Azure.Core.Experimental/src/JsonPatchDocument.cs b/sdk/core/Azure.Core.Experimental/src/JsonPatchDocument.cs index ad317617f4492..fe3bd11218cfa 100644 --- a/sdk/core/Azure.Core.Experimental/src/JsonPatchDocument.cs +++ b/sdk/core/Azure.Core.Experimental/src/JsonPatchDocument.cs @@ -1,11 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.ObjectModel; using System.IO; using System.Text; using System.Text.Json; +using System.Threading; using Azure.Core.JsonPatch; +using Azure.Core.Serialization; namespace Azure.Core { @@ -14,14 +17,24 @@ namespace Azure.Core /// public class JsonPatchDocument { - internal Collection Operations { get; } + private ObjectSerializer _serializer; + private Collection Operations { get; } + + /// + /// Initializes a new instance of that uses as the default serializer. + /// + public JsonPatchDocument() : this(new JsonObjectSerializer()) + { + } /// /// Initializes a new instance of /// - public JsonPatchDocument() + /// The instance to use for value serialization. + public JsonPatchDocument(ObjectSerializer serializer) { Operations = new Collection(); + _serializer = serializer ?? throw new ArgumentNullException(nameof(serializer)); } /// @@ -29,20 +42,41 @@ public JsonPatchDocument() /// /// The path to apply the addition to. /// The raw JSON value to add to the path. - public void AppendAdd(string path, string rawJsonValue) + public void AppendAddRaw(string path, string rawJsonValue) { Operations.Add(new JsonPatchOperation(JsonPatchOperationKind.Add, path, null, rawJsonValue)); } + /// + /// Appends an "add" operation to this . + /// + /// The path to apply the addition to. + /// The value to add to the path. + /// The to use. + public void AppendAdd(string path, T value, CancellationToken cancellationToken = default) + { + Operations.Add(new JsonPatchOperation(JsonPatchOperationKind.Add, path, null, Serialize(value, cancellationToken))); + } + /// /// Appends a "replace" operation to this . /// /// The path to replace. /// The raw JSON value to replace with. - public void AppendReplace(string path, string rawJsonValue) + public void AppendReplaceRaw(string path, string rawJsonValue) { Operations.Add(new JsonPatchOperation(JsonPatchOperationKind.Replace, path, null, rawJsonValue)); } + /// + /// Appends a "replace" operation to this . + /// + /// The path to replace. + /// The value to replace with. + /// The to use. + public void AppendReplace(string path, T value, CancellationToken cancellationToken = default) + { + Operations.Add(new JsonPatchOperation(JsonPatchOperationKind.Replace, path, null, Serialize(value, cancellationToken))); + } /// /// Appends a "copy" operation to this . @@ -78,11 +112,22 @@ public void AppendRemove(string path) /// /// The path to test. /// The raw JSON value to test against. - public void AppendTest(string path, string rawJsonValue) + public void AppendTestRaw(string path, string rawJsonValue) { Operations.Add(new JsonPatchOperation(JsonPatchOperationKind.Test, path, null, rawJsonValue)); } + /// + /// Appends a "test" operation to this . + /// + /// The path to test. + /// The value to replace with. + /// The to use. + public void AppendTest(string path, T value, CancellationToken cancellationToken = default) + { + Operations.Add(new JsonPatchOperation(JsonPatchOperationKind.Test, path, null, Serialize(value, cancellationToken))); + } + /// /// Returns a formatted JSON string representation of this . /// @@ -119,5 +164,12 @@ private void WriteTo(Utf8JsonWriter writer) } writer.WriteEndArray(); } + + private string Serialize(T value, CancellationToken cancellationToken) + { + using MemoryStream memoryStream = new MemoryStream(); + _serializer.Serialize(memoryStream, value, typeof(T), cancellationToken); + return Encoding.UTF8.GetString(memoryStream.ToArray()); + } } } \ No newline at end of file diff --git a/sdk/core/Azure.Core.Experimental/tests/JsonPatchDocumentTests.cs b/sdk/core/Azure.Core.Experimental/tests/JsonPatchDocumentTests.cs index 9578472e7e1dc..8b686363f0b72 100644 --- a/sdk/core/Azure.Core.Experimental/tests/JsonPatchDocumentTests.cs +++ b/sdk/core/Azure.Core.Experimental/tests/JsonPatchDocumentTests.cs @@ -12,7 +12,15 @@ public class JsonPatchDocumentTests public void AddIsSerializedCorrectly() { JsonPatchDocument document = new JsonPatchDocument(); - document.AppendAdd("/a/b/c","[ \"foo\", \"bar\" ]"); + document.AppendAddRaw("/a/b/c","[ \"foo\", \"bar\" ]"); + Assert.AreEqual(document.ToString(), "[{\"op\":\"add\",\"path\":\"/a/b/c\",\"value\":[\"foo\",\"bar\"]}]"); + } + + [Test] + public void AddIsSerializedCorrectlyGeneric() + { + JsonPatchDocument document = new JsonPatchDocument(); + document.AppendAdd("/a/b/c",new[] { "foo", "bar" }); Assert.AreEqual(document.ToString(), "[{\"op\":\"add\",\"path\":\"/a/b/c\",\"value\":[\"foo\",\"bar\"]}]"); } @@ -20,18 +28,34 @@ public void AddIsSerializedCorrectly() public void ReplaceIsSerializedCorrectly() { JsonPatchDocument document = new JsonPatchDocument(); - document.AppendReplace("/a/b/c","[ \"foo\", \"bar\" ]"); + document.AppendReplaceRaw("/a/b/c","[ \"foo\", \"bar\" ]"); Assert.AreEqual(document.ToString(), "[{\"op\":\"replace\",\"path\":\"/a/b/c\",\"value\":[\"foo\",\"bar\"]}]"); } + [Test] + public void ReplaceIsSerializedCorrectlyGeneric() + { + JsonPatchDocument document = new JsonPatchDocument(); + document.AppendReplace("/a/b/c",2); + Assert.AreEqual(document.ToString(), "[{\"op\":\"replace\",\"path\":\"/a/b/c\",\"value\":2}]"); + } + [Test] public void TestIsSerializedCorrectly() { JsonPatchDocument document = new JsonPatchDocument(); - document.AppendTest("/a/b/c","[ \"foo\", \"bar\" ]"); + document.AppendTestRaw("/a/b/c","[ \"foo\", \"bar\" ]"); Assert.AreEqual(document.ToString(), "[{\"op\":\"test\",\"path\":\"/a/b/c\",\"value\":[\"foo\",\"bar\"]}]"); } + [Test] + public void TestIsSerializedCorrectlyGeneric() + { + JsonPatchDocument document = new JsonPatchDocument(); + document.AppendTest("/a/b/c",new { a = 2}); + Assert.AreEqual(document.ToString(), "[{\"op\":\"test\",\"path\":\"/a/b/c\",\"value\":{\"a\":2}}]"); + } + [Test] public void RemoveIsSerializedCorrectly() { @@ -60,9 +84,9 @@ public void CopyIsSerializedCorrectly() public void MultipleOperationsSerializedInOrder() { JsonPatchDocument document = new JsonPatchDocument(); - document.AppendTest("/a/b/c","\"foo\""); - document.AppendAdd("/a/b/c","42"); - document.AppendReplace("/a/b/c","[ \"foo\", \"bar\" ]"); + document.AppendTestRaw("/a/b/c","\"foo\""); + document.AppendAddRaw("/a/b/c","42"); + document.AppendReplaceRaw("/a/b/c","[ \"foo\", \"bar\" ]"); document.AppendRemove("/a/b/c"); document.AppendMove("/a/b/c", "/a/b/d"); document.AppendCopy("/a/b/c", "/a/b/d");