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 overloads accepting non-generic JsonTypeInfo #77051

Closed
Tracked by #79122
eiriktsarpalis opened this issue Oct 14, 2022 · 3 comments · Fixed by #79397
Closed
Tracked by #79122
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Text.Json partner-impact This issue impacts a partner who needs to be kept updated
Milestone

Comments

@eiriktsarpalis
Copy link
Member

Background and motivation

The JsonSerializer class exposes serialization and deserialization overloads that accept JsonTypeInfo<T>. These overloads are generally marked AOT/linker-safe and provide the only entrypoint for serializing using materialized metadata instances. We are however missing non-generic overloads for doing the same thing.

API Proposal

namespace System.Text.Json;

public partial static class JsonSerializer
{
    public static object? Deserialize(string json, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(ReadOnlySpan<byte> utf8Json, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(ref Utf8JsonReader reader, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(Stream utf8Json, JsonTypeInfo jsonTypeInfo);
    public static ValueTask<object?> DeserializeAsync(Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default);
    public static object? Deserialize(JsonDocument document, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(JsonElement element, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(JsonNode node, JsonTypeInfo jsonTypeInfo);

    public static string Serialize(object? value, JsonTypeInfo jsonTypeInfo);
    public static byte[] SerializeToUtf8Bytes(object? value, JsonTypeInfo jsonTypeInfo);
    public static void Serialize(Utf8JsonWriter writer, object? value, JsonTypeInfo jsonTypeInfo);
    public static void Serialize(Stream utf8Json, object? value, JsonTypeInfo jsonTypeInfo);
    public static Task SerializeAsync(Stream utf8Json, object? value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default);
    public static JsonDocument SerializeToDocument(object? value, JsonTypeInfo jsonTypeInfo);
    public static JsonElement SerializeToElement(object? value, JsonTypeInfo jsonTypeInfo);
    public static JsonNode SerializeToNode(object? value, JsonTypeInfo jsonTypeInfo);
}

API Usage

The following example shows how we can perform non-generic serialization without invoking any of the RequiresUnreferencedCode APIs:

var options = new JsonSerializerOptions 
{ 
    TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default)
};

JsonTypeInfo typeInfo = options.GetTypeInfo(typeof(SupportedPoco));
object? result = JsonSerializer.Deserialize("{}", typeInfo);
Console.WriteLine(result is SupportedPoco); // True

Alternative Designs

No response

Risks

No response

@eiriktsarpalis eiriktsarpalis added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Oct 14, 2022
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Oct 14, 2022
@ghost
Copy link

ghost commented Oct 14, 2022

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

Issue Details

Background and motivation

The JsonSerializer class exposes serialization and deserialization overloads that accept JsonTypeInfo<T>. These overloads are generally marked AOT/linker-safe and provide the only entrypoint for serializing using materialized metadata instances. We are however missing non-generic overloads for doing the same thing.

API Proposal

namespace System.Text.Json;

public partial static class JsonSerializer
{
    public static object? Deserialize(string json, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(ReadOnlySpan<byte> utf8Json, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(ref Utf8JsonReader reader, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(Stream utf8Json, JsonTypeInfo jsonTypeInfo);
    public static ValueTask<object?> DeserializeAsync(Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default);
    public static object? Deserialize(JsonDocument document, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(JsonElement element, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(JsonNode node, JsonTypeInfo jsonTypeInfo);

    public static string Serialize(object? value, JsonTypeInfo jsonTypeInfo);
    public static byte[] SerializeToUtf8Bytes(object? value, JsonTypeInfo jsonTypeInfo);
    public static void Serialize(Utf8JsonWriter writer, object? value, JsonTypeInfo jsonTypeInfo);
    public static void Serialize(Stream utf8Json, object? value, JsonTypeInfo jsonTypeInfo);
    public static Task SerializeAsync(Stream utf8Json, object? value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default);
    public static JsonDocument SerializeToDocument(object? value, JsonTypeInfo jsonTypeInfo);
    public static JsonElement SerializeToElement(object? value, JsonTypeInfo jsonTypeInfo);
    public static JsonNode SerializeToNode(object? value, JsonTypeInfo jsonTypeInfo);
}

API Usage

The following example shows how we can perform non-generic serialization without invoking any of the RequiresUnreferencedCode APIs:

var options = new JsonSerializerOptions 
{ 
    TypeInfoResolver = JsonTypeInfoResolver.Combine(ContextA.Default, ContextB.Default)
};

JsonTypeInfo typeInfo = options.GetTypeInfo(typeof(SupportedPoco));
object? result = JsonSerializer.Deserialize("{}", typeInfo);
Console.WriteLine(result is SupportedPoco); // True

Alternative Designs

No response

Risks

No response

Author: eiriktsarpalis
Assignees: -
Labels:

api-suggestion, area-System.Text.Json

Milestone: -

@eiriktsarpalis eiriktsarpalis added api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged New issue has not been triaged by the area owner labels Oct 14, 2022
@eiriktsarpalis eiriktsarpalis added this to the 8.0.0 milestone Oct 14, 2022
@eiriktsarpalis eiriktsarpalis self-assigned this Oct 14, 2022
@eiriktsarpalis
Copy link
Member Author

cc @eerhardt @brunolins16 the APIs above would provide a mechanism to perform untyped, linker-safe serialization.

They can be used as an alternative to the proposal in #74492, via the workaround proposed in #74492 (comment)

@eiriktsarpalis eiriktsarpalis added the partner-impact This issue impacts a partner who needs to be kept updated label Nov 30, 2022
@bartonjs
Copy link
Member

bartonjs commented Dec 6, 2022

  • As these are just the weakly typed variant of the existing JsonTypeInfo overloads, looks good as proposed.
  • We caught two missing members (Deserialize(ROS<char>), DeserializeAsyncEnumerable) and added them.
namespace System.Text.Json;

public static partial class JsonSerializer
{
    public static object? Deserialize(string json, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(ReadOnlySpan<byte> utf8Json, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(ReadOnlySpan<char> json, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(ref Utf8JsonReader reader, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(Stream utf8Json, JsonTypeInfo jsonTypeInfo);
    public static ValueTask<object?> DeserializeAsync(Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default);
    public static IAsyncEnumerable<object?> DeserializeAsyncEnumerable(Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default);
    public static object? Deserialize(JsonDocument document, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(JsonElement element, JsonTypeInfo jsonTypeInfo);
    public static object? Deserialize(JsonNode node, JsonTypeInfo jsonTypeInfo);

    public static string Serialize(object? value, JsonTypeInfo jsonTypeInfo);
    public static byte[] SerializeToUtf8Bytes(object? value, JsonTypeInfo jsonTypeInfo);
    public static void Serialize(Utf8JsonWriter writer, object? value, JsonTypeInfo jsonTypeInfo);
    public static void Serialize(Stream utf8Json, object? value, JsonTypeInfo jsonTypeInfo);
    public static Task SerializeAsync(Stream utf8Json, object? value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken = default);
    public static JsonDocument SerializeToDocument(object? value, JsonTypeInfo jsonTypeInfo);
    public static JsonElement SerializeToElement(object? value, JsonTypeInfo jsonTypeInfo);
    public static JsonNode? SerializeToNode(object? value, JsonTypeInfo jsonTypeInfo);
}

@bartonjs bartonjs added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels Dec 6, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Dec 8, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Dec 12, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Jan 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Text.Json partner-impact This issue impacts a partner who needs to be kept updated
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants