-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add interop between serializer and DOMs #56112
Conversation
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Tagging subscribers to this area: @eiriktsarpalis, @layomia Issue Detailsresolves #31274 Verified 100% code coverage and increased coverage for public API validation in other areas including JsonSerializer APIs that use
|
@@ -240,6 +258,24 @@ public static partial class JsonSerializer | |||
public static System.Threading.Tasks.Task SerializeAsync<TValue>(System.IO.Stream utf8Json, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } | |||
public static System.Threading.Tasks.Task SerializeAsync<TValue>(System.IO.Stream utf8Json, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } | |||
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] | |||
public static System.Text.Json.JsonDocument SerializeToDocument(object? value, System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the SerializetTo*
methods also come in async variants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we could have added async; it wasn't part of the ask. The approved list of API permutations were already greater than originally expected.
Today, JsonDocument
only has ParseAsync()
(no serialize behavior) so the workaround for that is something like:
Stream stream = ...
// Serialize object to stream
await JsonSerializer.SerializeAsync(stream, myObject);
// Deserialize stream to document
JsonDocument doc = await JsonDocument.ParseAsync(stream);
@@ -23,7 +23,13 @@ public sealed partial class JsonDocument : IDisposable | |||
{ | |||
private ReadOnlyMemory<byte> _utf8Json; | |||
private MetadataDb _parsedData; | |||
private byte[]? _extraRentedBytes; | |||
|
|||
private byte[]? _extraRentedArrayPoolBytes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are the extra flags needed? They seem to be equivalent to checking whether the rented references are null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The existing pattern was thread-safe using Interlocked.Exchange()
. Instead of doing two calls to Interlocked.Exchange()
(the original one and the new one), a bool
was added that will avoid the Interlocked.Exchange()
if not necessary.
|
||
// For performance, we avoid calling JsonSerializer.Deserialize(node) since that will allocate an extra byte[]. | ||
|
||
using (var output = new PooledByteBufferWriter(options.DefaultBufferSize)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: could avoid two layers of indentation with using var
syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did clean up the PooledByteBufferWriter
, but left the writer's using
since it isn't used all the way to the end of the method and I prefer the variable scoping.
} | ||
else | ||
{ | ||
node.WriteTo(writer, options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wish there was a way we could avoid writing to an intermediate buffer. At this point it's probably not possible with Utf8JsonReader
being a concrete ref struct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least we only have one intermediate buffer; the current workarounds (before this new support) would have 2.
In theory, we could add another type of reader (and writer; possibly derived) to avoid this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -28,6 +28,7 @@ public override void Write(Utf8JsonWriter writer, JsonNode? value, JsonSerialize | |||
if (value == null) | |||
{ | |||
writer.WriteNullValue(); | |||
// Note the JsonSerializer.Deserialize<T>(JsonNode?) also calls WriteNullValue() for a null + root JsonNode. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have the right serializer method referenced in this comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes -- the Deserialize() for JsonNode
has a special check for null
to allow it` to be properly deserialized (since a node is actually nullable, unlike document\element).
|
||
private static TValue? ReadUsingMetadata<TValue>(JsonDocument document, JsonTypeInfo jsonTypeInfo) | ||
{ | ||
ReadOnlySpan<byte> utf8Json = document.GetRawValue(0, includeQuotes: true).Span; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this implementation have called document.RootElement and passed that to ReadUsingMetadata<TValue>(JsonElement element, JsonTypeInfo jsonTypeInfo)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Thanks
…bug_tests * origin/main: (274 commits) Disable test ConnectWithCertificateForDifferentName_Throws (dotnet#56456) Update dependencies from https://github.com/mono/linker build 20210726.2 (dotnet#56374) Cleanup disabled test conditions (dotnet#56381) [mono] Add GC unsafe transition to mono_unhandled_exception (dotnet#56380) don't fail the file extraction when we can't set last write time (dotnet#56370) Properly rebuild optimization data when it changes (dotnet#56397) Make open function calls in coreclr EINTR resilient on macOS (dotnet#56403) Fix dependency from EventLog to TraceSource ref (dotnet#56417) Fix comments in asm with JitDiffableDasm=1 (dotnet#56416) Catch TcpClient ctor exceptions in FtpWebRequest.CreateConnectionAsync (dotnet#56379) Add interop between serializer and DOMs (dotnet#56112) Fix type loader not recognizing overridden method (dotnet#56337) Prevent Segfault in EventPipe on disable (dotnet#56104) Update runtimeconfig.json and deps.json paths when these break past the MAX_PATH threshold (dotnet#56224) Use native allocator instead of pinning when decompressing embedded PDB (dotnet#56336) Specify win-x64 as a valid platform in the microsoft-net-runtime-* workloads for iOS/tvOS/MacCatalyst (dotnet#56311) Fix FailFast message formatting race (dotnet#56388) Try to fix finalizer-based async tests (dotnet#56384) Fix MetricsEventSource tests (dotnet#56382) Remove invalid Castle.DynamicProxy.Internal.AbstractInvocation from ILLink descriptor files (dotnet#56392) ...
* origin/main: (95 commits) Disable test ConnectWithCertificateForDifferentName_Throws (dotnet#56456) Update dependencies from https://github.com/mono/linker build 20210726.2 (dotnet#56374) Cleanup disabled test conditions (dotnet#56381) [mono] Add GC unsafe transition to mono_unhandled_exception (dotnet#56380) don't fail the file extraction when we can't set last write time (dotnet#56370) Properly rebuild optimization data when it changes (dotnet#56397) Make open function calls in coreclr EINTR resilient on macOS (dotnet#56403) Fix dependency from EventLog to TraceSource ref (dotnet#56417) Fix comments in asm with JitDiffableDasm=1 (dotnet#56416) Catch TcpClient ctor exceptions in FtpWebRequest.CreateConnectionAsync (dotnet#56379) Add interop between serializer and DOMs (dotnet#56112) Fix type loader not recognizing overridden method (dotnet#56337) Prevent Segfault in EventPipe on disable (dotnet#56104) Update runtimeconfig.json and deps.json paths when these break past the MAX_PATH threshold (dotnet#56224) Use native allocator instead of pinning when decompressing embedded PDB (dotnet#56336) Specify win-x64 as a valid platform in the microsoft-net-runtime-* workloads for iOS/tvOS/MacCatalyst (dotnet#56311) Fix FailFast message formatting race (dotnet#56388) Try to fix finalizer-based async tests (dotnet#56384) Fix MetricsEventSource tests (dotnet#56382) Remove invalid Castle.DynamicProxy.Internal.AbstractInvocation from ILLink descriptor files (dotnet#56392) ...
resolves #31274
Verified 100% code coverage and increased coverage for public API validation in other areas including JsonSerializer APIs that use
Stream
.