The current iteration of JsonSerializerOptions.TypeInfoResolver
|
public IJsonTypeInfoResolver TypeInfoResolver |
|
{ |
|
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] |
|
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)] |
|
get |
|
{ |
|
return _typeInfoResolver ??= DefaultJsonTypeInfoResolver.RootDefaultInstance(); |
|
} |
|
set |
|
{ |
|
VerifyMutable(); |
|
_typeInfoResolver = value; |
|
} |
|
} |
is implemented as non-nullable and marked as
RequiredUnreferencedCode since by default it will return the reflection-based contract resolver. This has been informed by the existing semantics of the
JsonSerializer methods accepting
JsonSerializerOptions as an argument: unless a contract resolver is explicitly set the method will revert to using reflection-based serialization.
I believe however that this approach is problematic, for a number of reasons:
- Because the property is marked RUC, it can trigger linker warnings in otherwise innocuous operations, such as copying resolver configuration to a new options instance.
- The introduction of contract customization has effectively decoupled reflection-based serialization from
JsonSerializerOptions. While we cannot change the semantics of existing JsonSerializer methods it is conceivable that future serialization APIs can make use of it in a linker-safe manner. Assuming we ship the TypeInfoResolver property in the current manifestation, we forever couple JsonSerializerOptions to the reflection-based serialization and trimmability concerns.
I propose we make the following changes to the API:
public partial class JsonSerializerOptions
{
- [RequiresUnreferenceCode]
- [RequiresDynamicCode]
- public IJsonTypeInfoResolver TypeInfoResolver { get; set; }
+ public IJsonTypeInfoResolver? TypeInfoResolver { get; set; }
+ [RequiresUnreferenceCode]
+ [RequiresDynamicCode]
public static JsonSerializerOptions Default { get; } // default instance comes populated with reflection resolver
}
The current iteration of
JsonSerializerOptions.TypeInfoResolverruntime/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs
Lines 168 to 181 in 52d9d0c
is implemented as non-nullable and marked as
RequiredUnreferencedCodesince by default it will return the reflection-based contract resolver. This has been informed by the existing semantics of theJsonSerializermethods acceptingJsonSerializerOptionsas an argument: unless a contract resolver is explicitly set the method will revert to using reflection-based serialization.I believe however that this approach is problematic, for a number of reasons:
JsonSerializerOptions. While we cannot change the semantics of existingJsonSerializermethods it is conceivable that future serialization APIs can make use of it in a linker-safe manner. Assuming we ship theTypeInfoResolverproperty in the current manifestation, we forever coupleJsonSerializerOptionsto the reflection-based serialization and trimmability concerns.I propose we make the following changes to the API:
public partial class JsonSerializerOptions { - [RequiresUnreferenceCode] - [RequiresDynamicCode] - public IJsonTypeInfoResolver TypeInfoResolver { get; set; } + public IJsonTypeInfoResolver? TypeInfoResolver { get; set; } + [RequiresUnreferenceCode] + [RequiresDynamicCode] public static JsonSerializerOptions Default { get; } // default instance comes populated with reflection resolver }