未验证 提交 e98db160 编写于 作者: D DoctorKrolic 提交者: GitHub

Add `JsonNode.ParseAsync` public API (#90006)

* Add `JsonNode.ParseAsync` public API

* Regenerate ref assemblies

* Change implementation to use unrented document
上级 4415472b
......@@ -774,7 +774,7 @@ public abstract partial class JsonNode
public static System.Text.Json.Nodes.JsonNode? Parse(System.ReadOnlySpan<byte> utf8Json, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; }
public static System.Text.Json.Nodes.JsonNode? Parse([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Json")] string json, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions)) { throw null; }
public static System.Text.Json.Nodes.JsonNode? Parse(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; }
public static System.Threading.Tasks.Task<System.Text.Json.Nodes.JsonNode?> ParseAsync(System.IO.Stream utf8Json, System.Text.Json.Nodes.JsonNodeOptions? nodeOptions = default(System.Text.Json.Nodes.JsonNodeOptions?), System.Text.Json.JsonDocumentOptions documentOptions = default(System.Text.Json.JsonDocumentOptions), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
[System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Creating JsonValue instances with non-primitive types requires generating code at runtime.")]
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Creating JsonValue instances with non-primitive types is not compatible with trimming. It can result in non-primitive types being serialized, which may have their members trimmed.")]
public void ReplaceWith<T>(T value) { throw null; }
......@@ -1217,12 +1217,12 @@ public static partial class JsonMetadataServices
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateIReadOnlyDictionaryInfo<TCollection, TKey, TValue>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.IReadOnlyDictionary<TKey, TValue> where TKey : notnull { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateISetInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.ISet<TElement> { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateListInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.List<TElement> { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<Memory<TElement>> CreateMemoryInfo<TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<Memory<TElement>> collectionInfo) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<System.Memory<TElement>> CreateMemoryInfo<TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<System.Memory<TElement>> collectionInfo) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> CreateObjectInfo<T>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<T> objectInfo) where T : notnull { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonPropertyInfo CreatePropertyInfo<T>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<T> propertyInfo) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateQueueInfo<TCollection>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo, System.Action<TCollection, object?> addFunc) where TCollection : System.Collections.IEnumerable { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateQueueInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.Queue<TElement> { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<ReadOnlyMemory<TElement>> CreateReadOnlyMemoryInfo<TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<ReadOnlyMemory<TElement>> collectionInfo) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<System.ReadOnlyMemory<TElement>> CreateReadOnlyMemoryInfo<TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<System.ReadOnlyMemory<TElement>> collectionInfo) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateStackInfo<TCollection>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo, System.Action<TCollection, object?> addFunc) where TCollection : System.Collections.IEnumerable { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateStackInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.Stack<TElement> { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> CreateValueInfo<T>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.JsonConverter converter) { throw null; }
......
......@@ -228,6 +228,24 @@ internal static JsonDocument ParseValue(string json, JsonDocumentOptions options
}
}
internal static async Task<JsonDocument> ParseAsyncCoreUnrented(
Stream utf8Json,
JsonDocumentOptions options = default,
CancellationToken cancellationToken = default)
{
ArraySegment<byte> drained = await ReadToEndAsync(utf8Json, cancellationToken).ConfigureAwait(false);
Debug.Assert(drained.Array != null);
byte[] owned = new byte[drained.Count];
Buffer.BlockCopy(drained.Array, 0, owned, 0, drained.Count);
// Holds document content, clear it before returning it.
drained.AsSpan().Clear();
ArrayPool<byte>.Shared.Return(drained.Array);
return ParseUnrented(owned.AsMemory(), options.GetReaderOptions());
}
/// <summary>
/// Parses text representing a single JSON value into a JsonDocument.
/// </summary>
......
......@@ -4,6 +4,8 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text.Json.Serialization.Converters;
using System.Threading;
using System.Threading.Tasks;
namespace System.Text.Json.Nodes
{
......@@ -126,5 +128,34 @@ public abstract partial class JsonNode
JsonElement element = JsonElement.ParseValue(utf8Json, documentOptions);
return JsonNodeConverter.Create(element, nodeOptions);
}
/// <summary>
/// Parse a <see cref="Stream"/> as UTF-8 encoded data representing a single JSON value into a
/// <see cref="JsonNode"/>. The Stream will be read to completion.
/// </summary>
/// <param name="utf8Json">JSON text to parse.</param>
/// <param name="nodeOptions">Options to control the node behavior after parsing.</param>
/// <param name="documentOptions">Options to control the document behavior during parsing.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>
/// A <see cref="Task"/> to produce a <see cref="JsonNode"/> representation of the JSON value.
/// </returns>
/// <exception cref="JsonException">
/// <paramref name="utf8Json"/> does not represent a valid single JSON value.
/// </exception>
public static async Task<JsonNode?> ParseAsync(
Stream utf8Json,
JsonNodeOptions? nodeOptions = null,
JsonDocumentOptions documentOptions = default,
CancellationToken cancellationToken = default)
{
if (utf8Json is null)
{
ThrowHelper.ThrowArgumentNullException(nameof(utf8Json));
}
JsonDocument document = await JsonDocument.ParseAsyncCoreUnrented(utf8Json, documentOptions, cancellationToken).ConfigureAwait(false);
return JsonNodeConverter.Create(document.RootElement, nodeOptions);
}
}
}
......@@ -4,6 +4,7 @@
using System.IO;
using System.Reflection;
using System.Text.Json.Serialization.Tests;
using System.Threading.Tasks;
using Xunit;
namespace System.Text.Json.Nodes.Tests
......@@ -125,15 +126,16 @@ public static void Parse_Fail()
}
[Fact]
public static void NullReference_Fail()
public static async Task NullReference_Fail()
{
Assert.Throws<ArgumentNullException>(() => JsonSerializer.Deserialize<JsonNode>((string)null));
Assert.Throws<ArgumentNullException>(() => JsonNode.Parse((string)null));
Assert.Throws<ArgumentNullException>(() => JsonNode.Parse((Stream)null));
await Assert.ThrowsAsync<ArgumentNullException>(() => JsonNode.ParseAsync(null));
}
[Fact]
public static void NullLiteral()
public static async Task NullLiteral()
{
Assert.Null(JsonSerializer.Deserialize<JsonNode>("null"));
Assert.Null(JsonNode.Parse("null"));
......@@ -141,11 +143,13 @@ public static void NullLiteral()
using (MemoryStream stream = new MemoryStream("null"u8.ToArray()))
{
Assert.Null(JsonNode.Parse(stream));
stream.Position = 0;
Assert.Null(await JsonNode.ParseAsync(stream));
}
}
[Fact]
public static void InternalValueFields()
public static async Task InternalValueFields()
{
// Use reflection to inspect the internal state of the 3 fields that hold values.
// There is not another way to verify, and using a debug watch causes nodes to be created.
......@@ -196,19 +200,51 @@ void Test()
Assert.Equal(SimpleTestClass.s_json.StripWhitespace(), actual);
}
}
using (MemoryStream stream = new MemoryStream(SimpleTestClass.s_data))
{
// Only JsonElement is present.
JsonNode node = await JsonNode.ParseAsync(stream);
object jsonDictionary = jsonDictionaryField.GetValue(node);
Assert.Null(jsonDictionary); // Value is null until converted from JsonElement.
Assert.NotNull(elementField.GetValue(node));
Test();
// Cause the single JsonElement to expand into individual JsonElement nodes.
Assert.Equal(1, node.AsObject()["MyInt16"].GetValue<int>());
Assert.Null(elementField.GetValue(node));
jsonDictionary = jsonDictionaryField.GetValue(node);
Assert.NotNull(jsonDictionary);
Assert.NotNull(listField.GetValue(jsonDictionary));
Assert.NotNull(dictionaryField.GetValue(jsonDictionary)); // The dictionary threshold was reached.
Test();
void Test()
{
string actual = node.ToJsonString();
// Replace the escaped "+" sign used with DateTimeOffset.
actual = actual.Replace("\\u002B", "+");
Assert.Equal(SimpleTestClass.s_json.StripWhitespace(), actual);
}
}
}
[Fact]
public static void ReadSimpleObjectWithTrailingTrivia()
public static async Task ReadSimpleObjectWithTrailingTrivia()
{
byte[] data = Encoding.UTF8.GetBytes(SimpleTestClass.s_json + " /* Multi\r\nLine Comment */\t");
using (MemoryStream stream = new MemoryStream(data))
var options = new JsonDocumentOptions
{
var options = new JsonDocumentOptions
{
CommentHandling = JsonCommentHandling.Skip
};
CommentHandling = JsonCommentHandling.Skip
};
using (MemoryStream stream = new MemoryStream(data))
{
JsonNode node = JsonNode.Parse(stream, nodeOptions: null, options);
string actual = node.ToJsonString();
......@@ -217,16 +253,33 @@ public static void ReadSimpleObjectWithTrailingTrivia()
Assert.Equal(SimpleTestClass.s_json.StripWhitespace(), actual);
}
using (MemoryStream stream = new MemoryStream(data))
{
JsonNode node = await JsonNode.ParseAsync(stream, nodeOptions: null, options);
string actual = node.ToJsonString();
// Replace the escaped "+" sign used with DateTimeOffset.
actual = actual.Replace("\\u002B", "+");
Assert.Equal(SimpleTestClass.s_json.StripWhitespace(), actual);
}
}
[Fact]
public static void ReadPrimitives()
public static async Task ReadPrimitives()
{
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(@"1")))
{
int i = JsonNode.Parse(stream).AsValue().GetValue<int>();
Assert.Equal(1, i);
}
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(@"1")))
{
int i = (await JsonNode.ParseAsync(stream)).AsValue().GetValue<int>();
Assert.Equal(1, i);
}
}
[Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册