diff --git a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net461.cs b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net461.cs index c0a9794fe4ee9..d80640ef434fc 100644 --- a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net461.cs +++ b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net461.cs @@ -164,8 +164,10 @@ internal MutableJsonDocument() { } public Azure.Core.Json.MutableJsonElement RootElement { get { throw null; } } public void Dispose() { } public static Azure.Core.Json.MutableJsonDocument Parse(System.BinaryData utf8Json) { throw null; } + public static Azure.Core.Json.MutableJsonDocument Parse(System.ReadOnlyMemory utf8Json) { throw null; } public static Azure.Core.Json.MutableJsonDocument Parse(string json) { throw null; } public void WriteTo(System.IO.Stream stream, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer) { } } [System.Diagnostics.DebuggerDisplayAttribute("{DebuggerDisplay,nq}")] [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] diff --git a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net6.0.cs b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net6.0.cs index c0a9794fe4ee9..d80640ef434fc 100644 --- a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net6.0.cs +++ b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net6.0.cs @@ -164,8 +164,10 @@ internal MutableJsonDocument() { } public Azure.Core.Json.MutableJsonElement RootElement { get { throw null; } } public void Dispose() { } public static Azure.Core.Json.MutableJsonDocument Parse(System.BinaryData utf8Json) { throw null; } + public static Azure.Core.Json.MutableJsonDocument Parse(System.ReadOnlyMemory utf8Json) { throw null; } public static Azure.Core.Json.MutableJsonDocument Parse(string json) { throw null; } public void WriteTo(System.IO.Stream stream, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer) { } } [System.Diagnostics.DebuggerDisplayAttribute("{DebuggerDisplay,nq}")] [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 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 c0a9794fe4ee9..d80640ef434fc 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 @@ -164,8 +164,10 @@ internal MutableJsonDocument() { } public Azure.Core.Json.MutableJsonElement RootElement { get { throw null; } } public void Dispose() { } public static Azure.Core.Json.MutableJsonDocument Parse(System.BinaryData utf8Json) { throw null; } + public static Azure.Core.Json.MutableJsonDocument Parse(System.ReadOnlyMemory utf8Json) { throw null; } public static Azure.Core.Json.MutableJsonDocument Parse(string json) { throw null; } public void WriteTo(System.IO.Stream stream, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer) { } } [System.Diagnostics.DebuggerDisplayAttribute("{DebuggerDisplay,nq}")] [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] diff --git a/sdk/core/Azure.Core.Experimental/src/MutableJsonDocument.cs b/sdk/core/Azure.Core.Experimental/src/MutableJsonDocument.cs index a86d38f8518fc..de40211840d42 100644 --- a/sdk/core/Azure.Core.Experimental/src/MutableJsonDocument.cs +++ b/sdk/core/Azure.Core.Experimental/src/MutableJsonDocument.cs @@ -18,7 +18,7 @@ public sealed partial class MutableJsonDocument : IDisposable { internal static readonly JsonSerializerOptions DefaultJsonSerializerOptions = new JsonSerializerOptions(); - private readonly Memory _original; + private readonly ReadOnlyMemory _original; private readonly JsonDocument _originalDocument; internal ChangeTracker Changes { get; } = new(); @@ -47,11 +47,14 @@ public MutableJsonElement RootElement /// /// The stream to which to write the document. /// A format string indicating the format to use when writing the document. + /// The parameter is . /// Thrown if an unsupported value is passed for format. /// The value of can be default or 'J' to write the document as JSON. public void WriteTo(Stream stream, StandardFormat format = default) { - if (format != default || format.Symbol != 'J') + Argument.AssertNotNull(stream, nameof(stream)); + + if (format != default && format.Symbol != 'J') { throw new FormatException($"Unsupported format {format.Symbol}. Supported formats are: 'J' - JSON."); } @@ -66,8 +69,17 @@ public void WriteTo(Stream stream, StandardFormat format = default) RootElement.WriteTo(writer); } - internal void WriteTo(Utf8JsonWriter writer) + /// + /// Writes the document to the provided stream as a JSON value. + /// + /// The writer to which to write the document. + /// The parameter is . +#pragma warning disable AZC0014 // Avoid using banned types in public API + public void WriteTo(Utf8JsonWriter writer) +#pragma warning restore AZC0014 // Avoid using banned types in public API { + Argument.AssertNotNull(writer, nameof(writer)); + if (!Changes.HasChanges) { _originalDocument.RootElement.WriteTo(writer); @@ -96,10 +108,23 @@ private static void Write(Stream stream, ReadOnlySpan buffer) /// /// A UTF-8 encoded string representing a JSON value. /// A representation of the value. + /// does not represent a valid single JSON value. + public static MutableJsonDocument Parse(ReadOnlyMemory utf8Json) + { + var doc = JsonDocument.Parse(utf8Json); + return new MutableJsonDocument(doc, utf8Json); + } + + /// + /// Parses a UTF-8 encoded string representing a single JSON value into a . + /// + /// A UTF-8 encoded string representing a JSON value. + /// A representation of the value. + /// does not represent a valid single JSON value. public static MutableJsonDocument Parse(BinaryData utf8Json) { var doc = JsonDocument.Parse(utf8Json); - return new MutableJsonDocument(doc, utf8Json.ToArray().AsMemory()); + return new MutableJsonDocument(doc, utf8Json.ToMemory()); } /// @@ -107,6 +132,7 @@ public static MutableJsonDocument Parse(BinaryData utf8Json) /// /// The JSON string. /// A representation of the value. + /// does not represent a valid single JSON value. public static MutableJsonDocument Parse(string json) { byte[] utf8 = Encoding.UTF8.GetBytes(json); @@ -120,7 +146,7 @@ public void Dispose() _originalDocument.Dispose(); } - internal MutableJsonDocument(JsonDocument jsonDocument, Memory utf8Json) + internal MutableJsonDocument(JsonDocument jsonDocument, ReadOnlyMemory utf8Json) { _original = utf8Json; _originalDocument = jsonDocument; diff --git a/sdk/core/Azure.Core.Experimental/src/MutableJsonElement.WriteTo.cs b/sdk/core/Azure.Core.Experimental/src/MutableJsonElement.WriteTo.cs index c69fefe5f85aa..fd310d1c9a5e6 100644 --- a/sdk/core/Azure.Core.Experimental/src/MutableJsonElement.WriteTo.cs +++ b/sdk/core/Azure.Core.Experimental/src/MutableJsonElement.WriteTo.cs @@ -17,6 +17,32 @@ private void WriteElement(string path, int highWaterMark, JsonElement element, U { if (Changes.TryGetChange(path, highWaterMark, out MutableJsonChange change)) { + switch (change.Value) + { + case int i: + writer.WriteNumberValue(i); + return; + case long l: + writer.WriteNumberValue(l); + return; + case double d: + writer.WriteNumberValue(d); + return; + case float f: + writer.WriteNumberValue(f); + return; + case bool b: + writer.WriteBooleanValue(b); + return; + case null: + writer.WriteNullValue(); + return; + default: + break; + + // Note: string is not included to let JsonElement handle escaping. + } + element = change.AsJsonElement(); highWaterMark = change.Index; } diff --git a/sdk/core/Azure.Core.Experimental/tests/MutableJsonDocumentWriteToTests.cs b/sdk/core/Azure.Core.Experimental/tests/MutableJsonDocumentWriteToTests.cs index e76906f0576c5..98b44094dc3b0 100644 --- a/sdk/core/Azure.Core.Experimental/tests/MutableJsonDocumentWriteToTests.cs +++ b/sdk/core/Azure.Core.Experimental/tests/MutableJsonDocumentWriteToTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text.Json; using Azure.Core.Json; @@ -464,6 +465,48 @@ public void CanWriteArrayWithChangedElements() MutableJsonDocumentTests.ValidateWriteTo(expected, mdoc); } + [Test] + public void CanWriteToStream() + { + string json = """{ "foo" : 1 }"""; + MutableJsonDocument mdoc = MutableJsonDocument.Parse(json); + + using Stream stream = new MemoryStream(); + mdoc.WriteTo(stream); + stream.Flush(); + stream.Position = 0; + + string actual = BinaryData.FromStream(stream).ToString(); + + Assert.AreEqual(json, actual); + } + + [Test] + public void CanWriteToStreamWithJsonFormat() + { + string json = """{ "foo" : 1 }"""; + MutableJsonDocument mdoc = MutableJsonDocument.Parse(json); + + using Stream stream = new MemoryStream(); + mdoc.WriteTo(stream, 'J'); + stream.Flush(); + stream.Position = 0; + + string actual = BinaryData.FromStream(stream).ToString(); + + Assert.AreEqual(json, actual); + } + + [Test] + public void CannotWriteToStreamWithPatchFormat() + { + string json = """{ "foo" : 1 }"""; + MutableJsonDocument mdoc = MutableJsonDocument.Parse(json); + + Stream stream = new MemoryStream(); + Assert.Throws(() => mdoc.WriteTo(stream, 'P')); + } + [TestCaseSource(nameof(TestCases))] public void WriteToBehaviorMatchesJsonDocument(dynamic json) {