KEMBAR78
[System.Text.Json] Expose additional metadata in contract APIs. · Issue #102078 · dotnet/runtime · GitHub
Skip to content

[System.Text.Json] Expose additional metadata in contract APIs. #102078

@eiriktsarpalis

Description

@eiriktsarpalis

Background and motivation

Contributes to #100159. The implementation of the https://github.com/eiriktsarpalis/stj-schema-mapper prototype revealed a number of gaps in the existing STJ contract metadata APIs which currently need to be filled manually using reflection or need to be extracted from private fields in the STJ implementation itself.

This proposal includes all the APIs necessary to make schema-related metadata available to end-users looking to export STJ schemas for .NET types, both for reflection and the source generator. The primary motivation is giving access to attribute metadata, via the ICustomAttributeProvider abstraction in a way that works well for both reflection and source generators/trimmed apps without compromising startup time or application size.

API Proposal

namespace System.Text.Json.Serialization.Metadata;

public partial class JsonTypeInfo
{
+   // Attribute provider for the deserialization constructor (aka `JsonConstructorAttribute` ctors)   
+   public ICustomAttributeProvider? ConstructorAttributeProvider { get; }
}

public partial class JsonPropertyInfo
{
+   public Type DeclaringType { get; }
+   // The JsonParameterInfo that has been associated with the current property.
+   public JsonParameterInfo? AssociatedParameterInfo { get; }
    public ICustomAttributeProvider? AttributeProvider { get; set; }
}

// Currently internal type, exposed as a read-only façade for now.
+public class JsonParameterInfo
+{
+    public Type DeclaringType { get; }
+    public int Position { get; }
+    public Type ParameterType { get; }
+    public bool HasDefaultValue { get; }
+    public object? DefaultValue { get; }
+    public bool DisallowNull { get; }
+    public ICustomAttributeProvider? AttributeProvider { get; }
+}

// New APIs for SG-specific APIs
[EditorBrowsable(EditorBrowsable.Never)]
public partial class JsonObjectInfoValues<T>
{
+    public Func<ICustomAttributeProvider?>? ConstructorAttributeProviderFactory { get; init; }
}

[EditorBrowsable(EditorBrowsable.Never)]
public partial class JsonPropertyInfoValues<T>
{
+    public Func<ICustomAttributeProvider?>? AttributeProviderFactory { get; init; }
}

[EditorBrowsable(EditorBrowsableState.Never)]
public partial class JsonParameterInfoValues
{
+    public bool DisallowNull { get; init; }
}

API Usage

Consider the user defined-type:

public class MyPoco
{
    [MyCustomAttribute]
    public int Value { get; set; }
}

Then the source generator would be able to give access to property attributes by generating the following code:

new JsonPropertyInfoValues<int>
{
    AttributeProviderFactory = static () => typeof(MyPoco).GetProperty(nameof(MyPoco.Value), BindingFlags.Public | BindingFlags.Instance),
}

Factoring the attribute provider resolution logic into a delegate that uses a reflection literal expression this ensures that

  1. we have delayed, pay-for-play reflection-based lookups of attribute metadata,
  2. the delegate can be trimmed if not consumed in user code and
  3. The trimmer doesn't remove attribute metadata for the specified members.

cc @jozkee @stephentoub @eerhardt @captainsafia

Metadata

Metadata

Labels

api-approvedAPI was approved in API review, it can be implementedarea-System.Text.JsonblockingMarks issues that we want to fast track in order to unblock other important work

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions