-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
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
- we have delayed, pay-for-play reflection-based lookups of attribute metadata,
- the delegate can be trimmed if not consumed in user code and
- The trimmer doesn't remove attribute metadata for the specified members.