Skip to content
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

[API Proposal]: Add JsonSerializer.Deserialize(ReadOnlySequence) #100478

Closed
aetos382 opened this issue Apr 1, 2024 · 3 comments
Closed

[API Proposal]: Add JsonSerializer.Deserialize(ReadOnlySequence) #100478

aetos382 opened this issue Apr 1, 2024 · 3 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Text.Json untriaged New issue has not been triaged by the area owner

Comments

@aetos382
Copy link

aetos382 commented Apr 1, 2024

Background and motivation

In #68586 DeserializeAsync(PipeReader) is proposed, but there are dependency issues because the System.IO.Pipelines package is not included in the framework.

If Deserialize(ReadOnlySequence<byte>) is supported, it would be very easy to write code like follows.

var readResult = await pipeReader.ReadAsync(cancellationToken).ConfigureAwait(false);
var deserialized = JsonSerializer.Deserialize<TValue>(readResult.Buffer, jsonSerializerOptions);

There is no dependency problem because the ReadOnlySequence<T> is a type included in the framework and already depended on by Utf8JsonReader and so on.

API Proposal

namespace System.Text.Json;

public class JsonSerializer
{
    public static object? Deserialize(ReadOnlySequence<char> json, Type returnType, JsonSerializerOptions? options);
    public static object? Deserialize(ReadOnlySequence<byte> utf8Json, Type returnType, JsonSerializerOptions? options);

    public static object? Deserialize(ReadOnlySequence<char> json, Type returnType, JsonSerializerContext context);
    public static object? Deserialize(ReadOnlySequence<byte> utf8Json, Type returnType, JsonSerializerContext context);

    public static object? Deserialize(ReadOnlySequence<char> json, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(ReadOnlySequence<byte> utf8Json, JsonTypeInfo jsonTypeInfo);

    public static TValue? Deserialize<TValue>(ReadOnlySequence<char> json, JsonSerializerOptions? options);
    public static TValue? Deserialize<TValue>(ReadOnlySequence<byte> utf8Json, JsonSerializerOptions? options);

    public static TValue? Deserialize<TValue>(ReadOnlySequence<char> json, JsonSerializerContext context);
    public static TValue? Deserialize<TValue>(ReadOnlySequence<byte> utf8Json, JsonSerializerContext context);

    public static TValue? Deserialize<TValue>(ReadOnlySequence<char> json, JsonTypeInfo<TValue> jsonTypeInfo);
    public static TValue? Deserialize<TValue>(ReadOnlySequence<byte> utf8Json, JsonTypeInfo<TValue> jsonTypeInfo);
}

API Usage

var readResult = await pipeReader.ReadAsync(cancellationToken).ConfigureAwait(false);
var deserialized = JsonSerializer.Deserialize<TValue>(readResult.Buffer, jsonSerializerOptions);

Alternative Designs

The objective may be achieved by combining the following already provided functions.
But to me, the correct way to implement these is not always intuitive.

var reader = new Utf8JsonReader(readResult.Buffer, jsonReaderOptions);
var deserialized = JsonSerializer.Deserialize(ref reader, jsonSerializerOptions);

or

var document = JsonDocument.Parse(readResult.Buffer, jsonDocumentOptions);
var deserialized = JsonSerializer.Deserialize<TValue>(document, jsonSerializerOptions);

If these are recommended, please provide documentation for them.
Also, please provide methods to retrieve JsonReaderOptions and JsonDocumentOptions from JsonSerializerOptions.
JsonSerializerOptions.GetReaderOptions and JsonSerializerOptions.GetDocumentOptions are currently internal, so please consider making them public.


The JsonSerializer.Deserialize is a method that already has numerous overloads.
There are two ways to return: one that returns a strongly typed object and one that returns object.
There are also three variations to provide deserialization options.

  • JsonSerializerOptions
  • JsonSerializerContext
  • JsonTypeInfo (including its generic version)

The proposal would add ReadOnlySequence<char> and ReadOnlySequence<byte> as the first parameter type for each of the six patterns consisting of these combinations, increasing the total number of overloads by 12.
This is an excessive increase, and I would be ok with only some of these being implemented.
If the importance is to work with PipeReader, then at a minimum, only the following two would be needed.

public static object? Deserialize(ReadOnlySequence<byte> utf8Json, Type returnType, JsonSerializerOptions? options);
public static TValue? Deserialize<TValue>(ReadOnlySequence<byte> utf8Json, JsonSerializerOptions? options);

To extend while limiting the combinatorial explosion due to overloading, it might be conceivable to provide a new style of API, such as the following.

var deserialized = JsonSerializer.Deserialize.From(source).To<TValue>().With(options);
var deserialized = JsonSerializer.Deserialize.From(source).To(type).With(options);
var deserialized = await JsonSerializer.DeserializeAsync.From(stream).To<TValue>().With(options).ConfigureAwait(false);
var deserialized = await JsonSerializer.DeserializeAsync.From(stream).To(type).With(options).ConfigureAwait(false);

If JsonSerializer were not a static class, it would be easy to provide these variations through extension methods.
Extensions to static classes will have to wait for extensions to be implemented.

Risks

At #68586 (comment), it is noted that there is a reliability issue.

@aetos382 aetos382 added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Apr 1, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Apr 1, 2024
@PaulusParssinen
Copy link
Contributor

In #68586 DeserializeAsync(PipeReader) is proposed, but there are dependency issues because the System.IO.Pipelines package is not included in the framework.

...

We now have System.IO.Pipelines available in the shared runtime as the DeserializeAsync(PipeReader reader, ...) API was approved. (If I'm reading the notes right..)

@eiriktsarpalis
Copy link
Member

If Deserialize(ReadOnlySequence<byte>) is supported, it would be very easy to write code like follows.

Adding top-level ReadOnlySequence APIs wouldn't be enough to unblock pipe support, since these wouldn't suffice to express resumable deserialization necessary for async pipe-based serialization. The plan per #68586 is to bring pipelines into the shared framework and add first-class support in STJ.

With that in place, I don't think there is a strong use case for adding top-level ReadOnlySequence APIs to the JsonSerializer class.

@eiriktsarpalis eiriktsarpalis closed this as not planned Won't fix, can't repro, duplicate, stale Apr 2, 2024
@github-actions github-actions bot locked and limited conversation to collaborators May 3, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Text.Json untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests

3 participants