未验证 提交 354ab2ad 编写于 作者: L Layomi Akinrinade 提交者: GitHub

[JSON source gen 1/3] Implement APIs needed by JSON source generator (#51149)

* Rename JsonClassInfo to JsonTypeInfo

* Move existing metadata types to new Metadata sub-folder/sub-namespace

* Add JsonMetadataServices and APIs needed by source generator

* Add tests and address feedback

* Rename ClassType to ConverterStrategy and clean up usage

* Move JsonSerializerContext to S.T.J.Serialization namespace and address doc feedback
上级 71142487
......@@ -194,13 +194,13 @@ public static partial class JsonSerializer
public static System.Threading.Tasks.ValueTask<TValue?> DeserializeAsync<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.IO.Stream utf8Json, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Collections.Generic.IAsyncEnumerable<TValue?> DeserializeAsyncEnumerable<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.IO.Stream utf8Json, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.ReadOnlySpan<byte> utf8Json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(string json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.ReadOnlySpan<char> json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(string json, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static TValue? Deserialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(ref System.Text.Json.Utf8JsonReader reader, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static string Serialize(object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static void Serialize(System.Text.Json.Utf8JsonWriter writer, object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { }
public static System.Threading.Tasks.Task SerializeAsync(System.IO.Stream utf8Json, object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Threading.Tasks.Task SerializeAsync<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields)]TValue>(System.IO.Stream utf8Json, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static System.Threading.Tasks.Task SerializeAsync<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.IO.Stream utf8Json, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public static byte[] SerializeToUtf8Bytes(object? value, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] System.Type inputType, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static byte[] SerializeToUtf8Bytes<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(TValue value, System.Text.Json.JsonSerializerOptions? options = null) { throw null; }
public static void Serialize<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)] TValue>(System.Text.Json.Utf8JsonWriter writer, TValue value, System.Text.Json.JsonSerializerOptions? options = null) { }
......@@ -236,6 +236,7 @@ public sealed partial class JsonSerializerOptions
public System.Text.Json.Serialization.ReferenceHandler? ReferenceHandler { get { throw null; } set { } }
public System.Text.Json.Serialization.JsonUnknownTypeHandling UnknownTypeHandling { get { throw null; } set { } }
public bool WriteIndented { get { throw null; } set { } }
public void AddContext<TContext>() where TContext : System.Text.Json.Serialization.JsonSerializerContext, new() { }
public System.Text.Json.Serialization.JsonConverter GetConverter(System.Type typeToConvert) { throw null; }
}
public enum JsonTokenType : byte
......@@ -712,6 +713,18 @@ public sealed partial class JsonPropertyNameAttribute : System.Text.Json.Seriali
public JsonPropertyNameAttribute(string name) { }
public string Name { get { throw null; } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple=true)]
public sealed partial class JsonSerializableAttribute : System.Text.Json.Serialization.JsonAttribute
{
public JsonSerializableAttribute(System.Type type) { }
public string? TypeInfoPropertyName { get { throw null; } set { } }
}
public abstract partial class JsonSerializerContext
{
protected JsonSerializerContext(System.Text.Json.JsonSerializerOptions? options) { }
public System.Text.Json.JsonSerializerOptions Options { get { throw null; } }
public abstract System.Text.Json.Serialization.Metadata.JsonTypeInfo? GetTypeInfo(System.Type type);
}
public sealed partial class JsonStringEnumConverter : System.Text.Json.Serialization.JsonConverterFactory
{
public JsonStringEnumConverter() { }
......@@ -744,3 +757,56 @@ public abstract partial class ReferenceResolver
public abstract object ResolveReference(string referenceId);
}
}
namespace System.Text.Json.Serialization.Metadata
{
public static partial class JsonMetadataServices
{
public static System.Text.Json.Serialization.JsonConverter<bool> BooleanConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<byte[]> ByteArrayConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<byte> ByteConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<char> CharConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.DateTime> DateTimeConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.DateTimeOffset> DateTimeOffsetConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<decimal> DecimalConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<double> DoubleConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.Guid> GuidConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<short> Int16Converter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<int> Int32Converter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<long> Int64Converter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<object> ObjectConverter { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public static System.Text.Json.Serialization.JsonConverter<sbyte> SByteConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<float> SingleConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<string> StringConverter { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public static System.Text.Json.Serialization.JsonConverter<ushort> UInt16Converter { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public static System.Text.Json.Serialization.JsonConverter<uint> UInt32Converter { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public static System.Text.Json.Serialization.JsonConverter<ulong> UInt64Converter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.Uri> UriConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.Version> VersionConverter { get { throw null; } }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TElement[]> CreateArrayInfo<TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateDictionaryInfo<TCollection, TKey, TValue>(System.Text.Json.JsonSerializerOptions options, System.Func<TCollection> createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo keyInfo, System.Text.Json.Serialization.Metadata.JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling) where TCollection : System.Collections.Generic.Dictionary<TKey, TValue> where TKey : notnull { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateListInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Func<TCollection>? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling) where TCollection : System.Collections.Generic.List<TElement> { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> CreateObjectInfo<T>() where T : notnull { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonPropertyInfo CreatePropertyInfo<T>(System.Text.Json.JsonSerializerOptions options, bool isProperty, System.Type declaringType, System.Text.Json.Serialization.Metadata.JsonTypeInfo propertyTypeInfo, System.Text.Json.Serialization.JsonConverter<T>? converter, System.Func<object, T>? getter, System.Action<object, T>? setter, System.Text.Json.Serialization.JsonIgnoreCondition ignoreCondition, System.Text.Json.Serialization.JsonNumberHandling numberHandling, string propertyName, System.Text.Json.JsonEncodedText jsonPropertyName) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> CreateValueInfo<T, TConverterReturn>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.JsonConverter<TConverterReturn> converter) where TConverterReturn : T { throw null; }
public static System.Text.Json.Serialization.JsonConverter<T> GetEnumConverter<T>(System.Text.Json.JsonSerializerOptions options) where T : struct { throw null; }
public static System.Text.Json.Serialization.JsonConverter<T?> GetNullableConverter<T>(System.Text.Json.Serialization.JsonConverter<T> underlyingTypeconverter) where T : struct { throw null; }
public static void InitializeObjectInfo<T>(System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> info, System.Text.Json.JsonSerializerOptions options, System.Func<T>? createObjectFunc, System.Func<System.Text.Json.Serialization.JsonSerializerContext, System.Text.Json.Serialization.Metadata.JsonPropertyInfo[]> propInitFunc, System.Text.Json.Serialization.JsonNumberHandling numberHandling) where T : notnull { }
}
public abstract partial class JsonPropertyInfo
{
internal JsonPropertyInfo() { }
}
public partial class JsonTypeInfo
{
internal JsonTypeInfo() { }
public static readonly System.Type ObjectType;
}
public abstract partial class JsonTypeInfo<T> : System.Text.Json.Serialization.Metadata.JsonTypeInfo
{
internal JsonTypeInfo() { }
}
}
......@@ -16,6 +16,7 @@
<ProjectReference Include="$(LibrariesProjectRoot)System.Linq.Expressions\ref\System.Linq.Expressions.csproj" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Reference Include="System.Collections" />
<Reference Include="System.Memory" />
<Reference Include="System.Runtime" />
<Reference Include="System.Linq.Expressions" />
......
......@@ -5,19 +5,19 @@
<argument>ILLink</argument>
<argument>IL2075</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionEmitMemberAccessor.CreateParameterizedConstructor(System.Reflection.ConstructorInfo,System.Type,System.Type,System.Type,System.Type)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionEmitMemberAccessor.CreateParameterizedConstructor(System.Reflection.ConstructorInfo,System.Type,System.Type,System.Type,System.Type)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2075</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionEmitMemberAccessor.CreateParameterizedConstructor(System.Reflection.ConstructorInfo)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionEmitMemberAccessor.CreateParameterizedConstructor(System.Reflection.ConstructorInfo)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2090</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionMemberAccessor.CreateParameterizedConstructor(System.Reflection.ConstructorInfo)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionMemberAccessor.CreateParameterizedConstructor(System.Reflection.ConstructorInfo)</property>
</attribute>
</assembly>
</linker>
......@@ -35,7 +35,7 @@
<argument>ILLink</argument>
<argument>IL2070</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.JsonClassInfo.#ctor(System.Type,System.Text.Json.JsonSerializerOptions)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.JsonTypeInfo.#ctor(System.Type,System.Text.Json.JsonSerializerOptions)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
......@@ -47,13 +47,13 @@
<argument>ILLink</argument>
<argument>IL2070</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionEmitMemberAccessor.CreateAddMethodDelegate(System.Type)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionEmitMemberAccessor.CreateAddMethodDelegate(System.Type)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2070</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionEmitMemberAccessor.CreateConstructor(System.Type)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionEmitMemberAccessor.CreateConstructor(System.Type)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
......@@ -71,31 +71,31 @@
<argument>ILLink</argument>
<argument>IL2077</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionMemberAccessor.&lt;&gt;c__DisplayClass0_0.&lt;CreateConstructor&gt;b__0</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionMemberAccessor.&lt;&gt;c__DisplayClass0_0.&lt;CreateConstructor&gt;b__0</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2080</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionMemberAccessor.CreateConstructor(System.Type)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionMemberAccessor.CreateConstructor(System.Type)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2090</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionMemberAccessor.CreateAddMethodDelegate``1</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionMemberAccessor.CreateAddMethodDelegate``1</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2090</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionMemberAccessor.CreateParameterizedConstructor``1(System.Reflection.ConstructorInfo)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionMemberAccessor.CreateParameterizedConstructor``1(System.Reflection.ConstructorInfo)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2090</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Text.Json.Serialization.ReflectionMemberAccessor.CreateParameterizedConstructor``5(System.Reflection.ConstructorInfo)</property>
<property name="Target">M:System.Text.Json.Serialization.Metadata.ReflectionMemberAccessor.CreateParameterizedConstructor``5(System.Reflection.ConstructorInfo)</property>
</attribute>
</assembly>
</linker>
......@@ -590,4 +590,16 @@
<data name="ValueCannotBeNull" xml:space="preserve">
<value>Value cannot be null. (Parameter '{0}')</value>
</data>
<data name="SerializerContextOptionsImmutable" xml:space="preserve">
<value>A 'JsonSerializerOptions' instance associated with a 'JsonSerializerContext' instance cannot be mutated once the context has been instantiated.</value>
</data>
<data name="OptionsAlreadyBoundToContext" xml:space="preserve">
<value>"The specified 'JsonSerializerOptions' instance is already bound with a 'JsonSerializerContext' instance."</value>
</data>
<data name="InitializeTypeInfoAsObjectInvalid" xml:space="preserve">
<value>The value must represent an object type.</value>
</data>
<data name="ConverterForPropertyMustBeValid" xml:space="preserve">
<value>The generic type of the converter for property '{0}.{1}' must match with the specified converter type '{2}'. The converter must not be 'null'.</value>
</data>
</root>
......@@ -78,9 +78,17 @@
<Compile Include="System\Text\Json\Serialization\Attributes\JsonIncludeAttribute.cs" />
<Compile Include="System\Text\Json\Serialization\Attributes\JsonNumberHandlingAttribute.cs" />
<Compile Include="System\Text\Json\Serialization\Attributes\JsonPropertyNameAttribute.cs" />
<Compile Include="System\Text\Json\Serialization\Attributes\JsonSerializableAttribute.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Object\ObjectSourceGenConverter.cs" />
<Compile Include="System\Text\Json\Serialization\IgnoreReferenceResolver.cs" />
<Compile Include="System\Text\Json\Serialization\JsonSerializerContext.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonMetadataServices.Collections.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonMetadataServices.Converters.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonTypeInfoInternalOfT.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonTypeInfoOfT.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonMetadataServices.cs" />
<Compile Include="System\Text\Json\Serialization\ReferenceEqualsWrapper.cs" />
<Compile Include="System\Text\Json\Serialization\ClassType.cs" />
<Compile Include="System\Text\Json\Serialization\ConverterStrategy.cs" />
<Compile Include="System\Text\Json\Serialization\ConverterList.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Collection\ArrayConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Collection\ConcurrentQueueOfTConverter.cs" />
......@@ -153,8 +161,6 @@
<Compile Include="System\Text\Json\Serialization\Converters\Value\VersionConverter.cs" />
<Compile Include="System\Text\Json\Serialization\IgnoreReferenceHandler.cs" />
<Compile Include="System\Text\Json\Serialization\JsonCamelCaseNamingPolicy.cs" />
<Compile Include="System\Text\Json\Serialization\JsonClassInfo.cs" />
<Compile Include="System\Text\Json\Serialization\JsonClassInfo.Cache.cs" />
<Compile Include="System\Text\Json\Serialization\JsonConverter.cs" />
<Compile Include="System\Text\Json\Serialization\JsonConverter.ReadAhead.cs" />
<Compile Include="System\Text\Json\Serialization\JsonConverterFactory.cs" />
......@@ -165,11 +171,6 @@
<Compile Include="System\Text\Json\Serialization\JsonIgnoreCondition.cs" />
<Compile Include="System\Text\Json\Serialization\JsonNamingPolicy.cs" />
<Compile Include="System\Text\Json\Serialization\JsonNumberHandling.cs" />
<Compile Include="System\Text\Json\Serialization\JsonParameterInfo.cs" />
<Compile Include="System\Text\Json\Serialization\JsonParameterInfoOfT.cs" />
<Compile Include="System\Text\Json\Serialization\JsonPropertyInfo.cs" />
<Compile Include="System\Text\Json\Serialization\JsonPropertyInfoOfT.cs" />
<Compile Include="System\Text\Json\Serialization\GenericMethodHolder.cs" />
<Compile Include="System\Text\Json\Serialization\JsonResumableConverterOfT.cs" />
<Compile Include="System\Text\Json\Serialization\JsonSerializer.Read.HandleMetadata.cs" />
<Compile Include="System\Text\Json\Serialization\JsonSerializer.Read.HandlePropertyName.cs" />
......@@ -189,12 +190,21 @@
<Compile Include="System\Text\Json\Serialization\JsonSerializerOptions.cs" />
<Compile Include="System\Text\Json\Serialization\JsonStringEnumConverter.cs" />
<Compile Include="System\Text\Json\Serialization\JsonUnknownTypeHandling.cs" />
<Compile Include="System\Text\Json\Serialization\MemberAccessor.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\GenericMethodHolder.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonParameterInfo.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonParameterInfoOfT.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonPropertyInfo.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonPropertyInfoOfT.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonTypeInfo.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonTypeInfo.Cache.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\MemberAccessor.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\ParameterRef.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\PropertyRef.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\ReflectionEmitMemberAccessor.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\ReflectionMemberAccessor.cs" />
<Compile Include="System\Text\Json\Serialization\MetadataPropertyName.cs" />
<Compile Include="System\Text\Json\Serialization\ParameterRef.cs" />
<Compile Include="System\Text\Json\Serialization\PreserveReferenceHandler.cs" />
<Compile Include="System\Text\Json\Serialization\PreserveReferenceResolver.cs" />
<Compile Include="System\Text\Json\Serialization\PropertyRef.cs" />
<Compile Include="System\Text\Json\Serialization\ReadAsyncBufferState.cs" />
<Compile Include="System\Text\Json\Serialization\ReadStack.cs" />
<Compile Include="System\Text\Json\Serialization\ReadStackFrame.cs" />
......@@ -202,8 +212,6 @@
<Compile Include="System\Text\Json\Serialization\ReferenceHandlerOfT.cs" />
<Compile Include="System\Text\Json\Serialization\ReferenceHandlingStrategy.cs" />
<Compile Include="System\Text\Json\Serialization\ReferenceResolver.cs" />
<Compile Include="System\Text\Json\Serialization\ReflectionEmitMemberAccessor.cs" />
<Compile Include="System\Text\Json\Serialization\ReflectionMemberAccessor.cs" />
<Compile Include="System\Text\Json\Serialization\StackFrameObjectState.cs" />
<Compile Include="System\Text\Json\Serialization\StackFramePropertyState.cs" />
<Compile Include="System\Text\Json\Serialization\WriteStack.cs" />
......
......@@ -16,8 +16,8 @@ namespace System.Text.Json
/// </remarks>
public readonly struct JsonEncodedText : IEquatable<JsonEncodedText>
{
private readonly byte[] _utf8Value;
private readonly string _value;
internal readonly byte[] _utf8Value;
internal readonly string _value;
/// <summary>
/// Returns the UTF-8 encoded representation of the pre-encoded JSON text.
......
......@@ -997,7 +997,7 @@ private void SkipWhiteSpace()
{
byte val = localBuffer[_consumed];
// JSON RFC 8259 section 2 says only these 4 characters count, not all of the Unicode defintions of whitespace.
// JSON RFC 8259 section 2 says only these 4 characters count, not all of the Unicode definitions of whitespace.
if (val != JsonConstants.Space &&
val != JsonConstants.CarriageReturn &&
val != JsonConstants.LineFeed &&
......
......@@ -2,9 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
using FoundProperties = System.ValueTuple<System.Text.Json.JsonPropertyInfo, System.Text.Json.JsonReaderState, long, byte[]?, string?>;
using FoundPropertiesAsync = System.ValueTuple<System.Text.Json.JsonPropertyInfo, object?, string?>;
using FoundProperties = System.ValueTuple<System.Text.Json.Serialization.Metadata.JsonPropertyInfo, System.Text.Json.JsonReaderState, long, byte[]?, string?>;
using FoundPropertiesAsync = System.ValueTuple<System.Text.Json.Serialization.Metadata.JsonPropertyInfo, object?, string?>;
namespace System.Text.Json
{
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
/// <summary>
/// Instructs the System.Text.Json source generator to generate source code to help optimize performance
/// when serializing and deserializing instances of the specified type and types in its object graph.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class JsonSerializableAttribute : JsonAttribute
{
/// <summary>
/// The name of the property for the generated <see cref="JsonTypeInfo{T}"/> for
/// the type on the generated, derived <see cref="JsonSerializerContext"/> type.
/// </summary>
/// <remarks>
/// Useful to resolve a name collision with another type in the compilation closure.
/// </remarks>
public string? TypeInfoPropertyName { get; set; }
/// <summary>
/// Initializes a new instance of <see cref="JsonSerializableAttribute"/> with the specified type.
/// </summary>
/// <param name="type">The type to generate source code for.</param>
public JsonSerializableAttribute(Type type) { }
}
}
......@@ -7,10 +7,10 @@ namespace System.Text.Json
/// Determines how a given class is treated when it is (de)serialized.
/// </summary>
/// <remarks>
/// Although bit flags are used, a given ClassType can only be one value.
/// Although bit flags are used, a given ConverterStrategy can only be one value.
/// Bit flags are used to efficiently compare against more than one value.
/// </remarks>
internal enum ClassType : byte
internal enum ConverterStrategy : byte
{
// Default - no class type.
None = 0x0,
......@@ -18,8 +18,6 @@ internal enum ClassType : byte
Object = 0x1,
// JsonConverter<> - simple values.
Value = 0x2,
// JsonValueConverter<> - simple values that need to re-enter the serializer such as KeyValuePair<TKey, TValue>.
NewValue = 0x4,
// JsonIEnumerableConverter<> - all enumerable collections except dictionaries.
Enumerable = 0x8,
// JsonDictionaryConverter<,> - dictionary types.
......
......@@ -17,12 +17,12 @@ protected override void Add(in TElement value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonClassInfo.Type);
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonTypeInfo.Type);
}
state.Current.ReturnValue = state.Current.JsonClassInfo.CreateObject();
state.Current.ReturnValue = state.Current.JsonTypeInfo.CreateObject();
}
protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state)
......
......@@ -17,12 +17,12 @@ protected override void Add(in TElement value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonClassInfo.Type);
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonTypeInfo.Type);
}
state.Current.ReturnValue = state.Current.JsonClassInfo.CreateObject();
state.Current.ReturnValue = state.Current.JsonTypeInfo.CreateObject();
}
protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state)
......
......@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -37,9 +38,9 @@ internal abstract class DictionaryDefaultConverter<TCollection, TKey, TValue>
protected JsonConverter<TKey>? _keyConverter;
protected JsonConverter<TValue>? _valueConverter;
protected static JsonConverter<T> GetConverter<T>(JsonClassInfo classInfo)
protected static JsonConverter<T> GetConverter<T>(JsonTypeInfo typeInfo)
{
JsonConverter<T> converter = (JsonConverter<T>)classInfo.PropertyInfoForClassInfo.ConverterBase;
JsonConverter<T> converter = (JsonConverter<T>)typeInfo.PropertyInfoForTypeInfo.ConverterBase;
Debug.Assert(converter != null); // It should not be possible to have a null converter at this point.
return converter;
......@@ -52,7 +53,7 @@ protected static JsonConverter<T> GetConverter<T>(JsonClassInfo classInfo)
ref ReadStack state,
[MaybeNullWhen(false)] out TCollection value)
{
JsonClassInfo elementClassInfo = state.Current.JsonClassInfo.ElementClassInfo!;
JsonTypeInfo elementTypeInfo = state.Current.JsonTypeInfo.ElementTypeInfo!;
if (state.UseFastPath)
{
......@@ -65,7 +66,7 @@ protected static JsonConverter<T> GetConverter<T>(JsonClassInfo classInfo)
CreateCollection(ref reader, ref state);
_valueConverter ??= GetConverter<TValue>(elementClassInfo);
_valueConverter ??= GetConverter<TValue>(elementTypeInfo);
if (_valueConverter.CanUseDirectReadOrWrite && state.Current.NumberHandling == null)
{
// Process all elements.
......@@ -158,7 +159,7 @@ protected static JsonConverter<T> GetConverter<T>(JsonClassInfo classInfo)
}
// Process all elements.
_valueConverter ??= GetConverter<TValue>(elementClassInfo);
_valueConverter ??= GetConverter<TValue>(elementTypeInfo);
while (true)
{
if (state.Current.PropertyState == StackFramePropertyState.None)
......@@ -208,7 +209,7 @@ protected static JsonConverter<T> GetConverter<T>(JsonClassInfo classInfo)
{
state.Current.PropertyState = StackFramePropertyState.ReadValue;
if (!SingleValueReadWithReadAhead(_valueConverter.ClassType, ref reader, ref state))
if (!SingleValueReadWithReadAhead(_valueConverter.ConverterStrategy, ref reader, ref state))
{
state.Current.DictionaryKey = key;
value = default;
......@@ -250,7 +251,7 @@ TKey ReadDictionaryKey(ref Utf8JsonReader reader, ref ReadStack state)
}
else
{
_keyConverter ??= GetConverter<TKey>(state.Current.JsonClassInfo.KeyClassInfo!);
_keyConverter ??= GetConverter<TKey>(state.Current.JsonTypeInfo.KeyTypeInfo!);
key = _keyConverter.ReadWithQuotes(ref reader);
unescapedPropertyNameAsString = reader.GetString()!;
}
......@@ -285,7 +286,7 @@ TKey ReadDictionaryKey(ref Utf8JsonReader reader, ref ReadStack state)
}
}
state.Current.DeclaredJsonPropertyInfo = state.Current.JsonClassInfo.ElementClassInfo!.PropertyInfoForClassInfo;
state.Current.DeclaredJsonPropertyInfo = state.Current.JsonTypeInfo.ElementTypeInfo!.PropertyInfoForTypeInfo;
}
bool success = OnWriteResume(writer, dictionary, options, ref state);
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -21,12 +22,12 @@ protected override void Add(TKey key, in TValue value, JsonSerializerOptions opt
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state)
{
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonClassInfo.Type);
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonTypeInfo.Type);
}
state.Current.ReturnValue = state.Current.JsonClassInfo.CreateObject();
state.Current.ReturnValue = state.Current.JsonTypeInfo.CreateObject();
}
protected internal override bool OnWriteResume(
......@@ -50,9 +51,9 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
enumerator = (Dictionary<TKey, TValue>.Enumerator)state.Current.CollectionEnumerator;
}
JsonClassInfo classInfo = state.Current.JsonClassInfo;
_keyConverter ??= GetConverter<TKey>(classInfo.KeyClassInfo!);
_valueConverter ??= GetConverter<TValue>(classInfo.ElementClassInfo!);
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
_keyConverter ??= GetConverter<TKey>(typeInfo.KeyTypeInfo!);
_valueConverter ??= GetConverter<TValue>(typeInfo.ElementTypeInfo!);
if (!state.SupportContinuation && _valueConverter.CanUseDirectReadOrWrite && state.Current.NumberHandling == null)
{
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -24,7 +25,7 @@ protected override void Add(in TElement value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
if (TypeToConvert.IsInterface || TypeToConvert.IsAbstract)
{
......@@ -37,12 +38,12 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
}
else
{
if (classInfo.CreateObject == null)
if (typeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state);
}
TCollection returnValue = (TCollection)classInfo.CreateObject()!;
TCollection returnValue = (TCollection)typeInfo.CreateObject()!;
if (returnValue.IsReadOnly)
{
......
......@@ -3,6 +3,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -26,7 +27,7 @@ protected override void Add(string key, in object? value, JsonSerializerOptions
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
if (TypeToConvert.IsInterface || TypeToConvert.IsAbstract)
{
......@@ -40,12 +41,12 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
}
else
{
if (classInfo.CreateObject == null)
if (typeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state);
}
TCollection returnValue = (TCollection)classInfo.CreateObject()!;
TCollection returnValue = (TCollection)typeInfo.CreateObject()!;
if (returnValue.IsReadOnly)
{
......@@ -72,8 +73,8 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio
enumerator = (IDictionaryEnumerator)state.Current.CollectionEnumerator;
}
JsonClassInfo classInfo = state.Current.JsonClassInfo;
_valueConverter ??= GetConverter<object?>(classInfo.ElementClassInfo!);
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
_valueConverter ??= GetConverter<object?>(typeInfo.ElementTypeInfo!);
do
{
......@@ -90,7 +91,7 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio
// Optimize for string since that's the hot path.
if (key is string keyString)
{
_keyConverter ??= GetConverter<string>(classInfo.KeyClassInfo!);
_keyConverter ??= GetConverter<string>(typeInfo.KeyTypeInfo!);
_keyConverter.WriteWithQuotes(writer, keyString, options, ref state);
}
else
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -26,7 +27,7 @@ protected override void Add(TKey key, in TValue value, JsonSerializerOptions opt
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
if (TypeToConvert.IsInterface || TypeToConvert.IsAbstract)
{
......@@ -39,12 +40,12 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
}
else
{
if (classInfo.CreateObject == null)
if (typeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state);
}
TCollection returnValue = (TCollection)classInfo.CreateObject()!;
TCollection returnValue = (TCollection)typeInfo.CreateObject()!;
if (returnValue.IsReadOnly)
{
......@@ -76,9 +77,9 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
enumerator = (IEnumerator<KeyValuePair<TKey, TValue>>)state.Current.CollectionEnumerator;
}
JsonClassInfo classInfo = state.Current.JsonClassInfo;
_keyConverter ??= GetConverter<TKey>(classInfo.KeyClassInfo!);
_valueConverter ??= GetConverter<TValue>(classInfo.ElementClassInfo!);
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
_keyConverter ??= GetConverter<TKey>(typeInfo.KeyTypeInfo!);
_valueConverter ??= GetConverter<TValue>(typeInfo.ElementTypeInfo!);
do
{
......
......@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
......@@ -48,7 +49,7 @@ internal static class IEnumerableConverterFactoryHelpers
Type? baseTypeToCheck = type;
while (baseTypeToCheck != null && baseTypeToCheck != JsonClassInfo.ObjectType)
while (baseTypeToCheck != null && baseTypeToCheck != JsonTypeInfo.ObjectType)
{
if (baseTypeToCheck.IsGenericType)
{
......
......@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -16,9 +17,9 @@ internal abstract class IEnumerableDefaultConverter<TCollection, TElement>
protected abstract void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options);
protected virtual void ConvertCollection(ref ReadStack state, JsonSerializerOptions options) { }
protected static JsonConverter<TElement> GetElementConverter(JsonClassInfo elementClassInfo)
protected static JsonConverter<TElement> GetElementConverter(JsonTypeInfo elementTypeInfo)
{
JsonConverter<TElement> converter = (JsonConverter<TElement>)elementClassInfo.PropertyInfoForClassInfo.ConverterBase;
JsonConverter<TElement> converter = (JsonConverter<TElement>)elementTypeInfo.PropertyInfoForTypeInfo.ConverterBase;
Debug.Assert(converter != null); // It should not be possible to have a null converter at this point.
return converter;
......@@ -39,7 +40,7 @@ protected static JsonConverter<TElement> GetElementConverter(ref WriteStack stat
ref ReadStack state,
[MaybeNullWhen(false)] out TCollection value)
{
JsonClassInfo elementClassInfo = state.Current.JsonClassInfo.ElementClassInfo!;
JsonTypeInfo elementTypeInfo = state.Current.JsonTypeInfo.ElementTypeInfo!;
if (state.UseFastPath)
{
......@@ -52,7 +53,7 @@ protected static JsonConverter<TElement> GetElementConverter(ref WriteStack stat
CreateCollection(ref reader, ref state, options);
JsonConverter<TElement> elementConverter = GetElementConverter(elementClassInfo);
JsonConverter<TElement> elementConverter = GetElementConverter(elementTypeInfo);
if (elementConverter.CanUseDirectReadOrWrite && state.Current.NumberHandling == null)
{
// Fast path that avoids validation and extra indirection.
......@@ -134,13 +135,13 @@ protected static JsonConverter<TElement> GetElementConverter(ref WriteStack stat
if (state.Current.ObjectState < StackFrameObjectState.CreatedObject)
{
CreateCollection(ref reader, ref state, options);
state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.ElementClassInfo!.PropertyInfoForClassInfo;
state.Current.JsonPropertyInfo = state.Current.JsonTypeInfo.ElementTypeInfo!.PropertyInfoForTypeInfo;
state.Current.ObjectState = StackFrameObjectState.CreatedObject;
}
if (state.Current.ObjectState < StackFrameObjectState.ReadElements)
{
JsonConverter<TElement> elementConverter = GetElementConverter(elementClassInfo);
JsonConverter<TElement> elementConverter = GetElementConverter(elementTypeInfo);
// Process all elements.
while (true)
......@@ -149,7 +150,7 @@ protected static JsonConverter<TElement> GetElementConverter(ref WriteStack stat
{
state.Current.PropertyState = StackFramePropertyState.ReadValue;
if (!SingleValueReadWithReadAhead(elementConverter.ClassType, ref reader, ref state))
if (!SingleValueReadWithReadAhead(elementConverter.ConverterStrategy, ref reader, ref state))
{
value = default;
return false;
......@@ -251,7 +252,7 @@ protected static JsonConverter<TElement> GetElementConverter(ref WriteStack stat
writer.WriteStartArray();
}
state.Current.DeclaredJsonPropertyInfo = state.Current.JsonClassInfo.ElementClassInfo!.PropertyInfoForClassInfo;
state.Current.DeclaredJsonPropertyInfo = state.Current.JsonTypeInfo.ElementTypeInfo!.PropertyInfoForTypeInfo;
}
success = OnWriteResume(writer, value, options, ref state);
......
......@@ -3,6 +3,7 @@
using System.Collections;
using System.Diagnostics;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -12,15 +13,15 @@ internal sealed class IEnumerableWithAddMethodConverter<TCollection>
{
protected override void Add(in object? value, ref ReadStack state)
{
var addMethodDelegate = ((Action<TCollection, object?>?)state.Current.JsonClassInfo.AddMethodDelegate);
var addMethodDelegate = ((Action<TCollection, object?>?)state.Current.JsonTypeInfo.AddMethodDelegate);
Debug.Assert(addMethodDelegate != null);
addMethodDelegate((TCollection)state.Current.ReturnValue!, value);
}
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonClassInfo.ConstructorDelegate? constructorDelegate = classInfo.CreateObject;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
JsonTypeInfo.ConstructorDelegate? constructorDelegate = typeInfo.CreateObject;
if (constructorDelegate == null)
{
......@@ -30,10 +31,10 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
state.Current.ReturnValue = constructorDelegate();
// Initialize add method used to populate the collection.
if (classInfo.AddMethodDelegate == null)
if (typeInfo.AddMethodDelegate == null)
{
// We verified this exists when we created the converter in the enumerable converter factory.
classInfo.AddMethodDelegate = options.MemberAccessorStrategy.CreateAddMethodDelegate<TCollection>();
typeInfo.AddMethodDelegate = options.MemberAccessorStrategy.CreateAddMethodDelegate<TCollection>();
}
}
......
......@@ -3,6 +3,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -23,7 +24,7 @@ protected override void Add(in object? value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
if (TypeToConvert.IsInterface || TypeToConvert.IsAbstract)
{
......@@ -36,12 +37,12 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
}
else
{
if (classInfo.CreateObject == null)
if (typeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state);
}
TCollection returnValue = (TCollection)classInfo.CreateObject()!;
TCollection returnValue = (TCollection)typeInfo.CreateObject()!;
if (returnValue.IsReadOnly)
{
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -24,7 +25,7 @@ protected override void Add(in TElement value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
if (TypeToConvert.IsInterface || TypeToConvert.IsAbstract)
{
......@@ -37,12 +38,12 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
}
else
{
if (classInfo.CreateObject == null)
if (typeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state);
}
TCollection returnValue = (TCollection)classInfo.CreateObject()!;
TCollection returnValue = (TCollection)typeInfo.CreateObject()!;
if (returnValue.IsReadOnly)
{
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -42,9 +43,9 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio
enumerator = (Dictionary<TKey, TValue>.Enumerator)state.Current.CollectionEnumerator;
}
JsonClassInfo classInfo = state.Current.JsonClassInfo;
_keyConverter ??= GetConverter<TKey>(classInfo.KeyClassInfo!);
_valueConverter ??= GetConverter<TValue>(classInfo.ElementClassInfo!);
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
_keyConverter ??= GetConverter<TKey>(typeInfo.KeyTypeInfo!);
_valueConverter ??= GetConverter<TValue>(typeInfo.ElementTypeInfo!);
do
{
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -21,7 +22,7 @@ protected override void Add(in TElement value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
if (TypeToConvert.IsInterface || TypeToConvert.IsAbstract)
{
......@@ -34,12 +35,12 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
}
else
{
if (classInfo.CreateObject == null)
if (typeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state);
}
TCollection returnValue = (TCollection)classInfo.CreateObject()!;
TCollection returnValue = (TCollection)typeInfo.CreateObject()!;
if (returnValue.IsReadOnly)
{
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -24,13 +25,13 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection>? creator = (Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection>?)classInfo.CreateObjectWithArgs;
Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection>? creator = (Func<IEnumerable<KeyValuePair<TKey, TValue>>, TCollection>?)typeInfo.CreateObjectWithArgs;
if (creator == null)
{
creator = options.MemberAccessorStrategy.CreateImmutableDictionaryCreateRangeDelegate<TCollection, TKey, TValue>();
classInfo.CreateObjectWithArgs = creator;
typeInfo.CreateObjectWithArgs = creator;
}
state.Current.ReturnValue = creator((Dictionary<TKey, TValue>)state.Current.ReturnValue!);
......@@ -53,9 +54,9 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio
enumerator = (IEnumerator<KeyValuePair<TKey, TValue>>)state.Current.CollectionEnumerator;
}
JsonClassInfo classInfo = state.Current.JsonClassInfo;
_keyConverter ??= GetConverter<TKey>(classInfo.KeyClassInfo!);
_valueConverter ??= GetConverter<TValue>(classInfo.ElementClassInfo!);
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
_keyConverter ??= GetConverter<TKey>(typeInfo.KeyTypeInfo!);
_valueConverter ??= GetConverter<TValue>(typeInfo.ElementTypeInfo!);
do
{
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -23,13 +24,13 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac
protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
Func<IEnumerable<TElement>, TCollection>? creator = (Func<IEnumerable<TElement>, TCollection>?)classInfo.CreateObjectWithArgs;
Func<IEnumerable<TElement>, TCollection>? creator = (Func<IEnumerable<TElement>, TCollection>?)typeInfo.CreateObjectWithArgs;
if (creator == null)
{
creator = options.MemberAccessorStrategy.CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>();
classInfo.CreateObjectWithArgs = creator;
typeInfo.CreateObjectWithArgs = creator;
}
state.Current.ReturnValue = creator((List<TElement>)state.Current.ReturnValue!);
......
......@@ -8,7 +8,7 @@ namespace System.Text.Json.Serialization
/// </summary>
internal abstract class JsonCollectionConverter<TCollection, TElement> : JsonResumableConverter<TCollection>
{
internal sealed override ClassType ClassType => ClassType.Enumerable;
internal sealed override ConverterStrategy ConverterStrategy => ConverterStrategy.Enumerable;
internal override Type ElementType => typeof(TElement);
}
}
......@@ -8,7 +8,7 @@ namespace System.Text.Json.Serialization
/// </summary>
internal abstract class JsonDictionaryConverter<T> : JsonResumableConverter<T>
{
internal sealed override ClassType ClassType => ClassType.Dictionary;
internal sealed override ConverterStrategy ConverterStrategy => ConverterStrategy.Dictionary;
protected internal abstract bool OnWriteResume(Utf8JsonWriter writer, T dictionary, JsonSerializerOptions options, ref WriteStack state);
}
......
......@@ -17,12 +17,12 @@ protected override void Add(in TElement value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonClassInfo.Type);
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonTypeInfo.Type);
}
state.Current.ReturnValue = state.Current.JsonClassInfo.CreateObject();
state.Current.ReturnValue = state.Current.JsonTypeInfo.CreateObject();
}
protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state)
......
......@@ -16,12 +16,12 @@ protected override void Add(in TElement value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonClassInfo.Type);
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonTypeInfo.Type);
}
state.Current.ReturnValue = state.Current.JsonClassInfo.CreateObject();
state.Current.ReturnValue = state.Current.JsonTypeInfo.CreateObject();
}
protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state)
......
......@@ -16,12 +16,12 @@ protected override void Add(in TElement value, ref ReadStack state)
protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonClassInfo.Type);
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(state.Current.JsonTypeInfo.Type);
}
state.Current.ReturnValue = state.Current.JsonClassInfo.CreateObject();
state.Current.ReturnValue = state.Current.JsonTypeInfo.CreateObject();
}
protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state)
......
......@@ -12,7 +12,6 @@ internal class JsonNodeConverter : JsonConverter<object>
public JsonArrayConverter ArrayConverter { get; } = new JsonArrayConverter();
public JsonObjectConverter ObjectConverter { get; } = new JsonObjectConverter();
public JsonValueConverter ValueConverter { get; } = new JsonValueConverter();
public ObjectConverter ElementConverter { get; } = new ObjectConverter();
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
......
......@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Text.Json.Node;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -10,7 +11,7 @@ internal sealed class JsonNodeConverterFactory : JsonConverterFactory
{
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
if (JsonClassInfo.ObjectType == typeToConvert)
if (JsonTypeInfo.ObjectType == typeToConvert)
{
if (options.UnknownTypeHandling == JsonUnknownTypeHandling.JsonNode)
{
......@@ -18,7 +19,7 @@ internal sealed class JsonNodeConverterFactory : JsonConverterFactory
}
// Return the converter for System.Object which uses JsonElement.
return JsonNodeConverter.Instance.ElementConverter;
return JsonMetadataServices.ObjectConverter;
}
if (typeof(JsonValue).IsAssignableFrom(typeToConvert))
......@@ -41,7 +42,7 @@ internal sealed class JsonNodeConverterFactory : JsonConverterFactory
}
public override bool CanConvert(Type typeToConvert) =>
typeToConvert == JsonClassInfo.ObjectType ||
typeToConvert == JsonTypeInfo.ObjectType ||
typeof(JsonNode).IsAssignableFrom(typeToConvert);
}
}
......@@ -9,7 +9,7 @@ namespace System.Text.Json.Serialization
/// </summary>
internal abstract class JsonObjectConverter<T> : JsonResumableConverter<T>
{
internal sealed override ClassType ClassType => ClassType.Object;
internal sealed override ConverterStrategy ConverterStrategy => ConverterStrategy.Object;
internal sealed override Type? ElementType => null;
}
}
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -51,10 +52,10 @@ internal override void Initialize(JsonSerializerOptions options)
JsonSerializerOptions options,
out JsonParameterInfo? jsonParameterInfo)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
ArgumentState? argState = state.Current.CtorArgumentState;
Debug.Assert(classInfo.ClassType == ClassType.Object);
Debug.Assert(typeInfo.PropertyInfoForTypeInfo.ConverterStrategy == ConverterStrategy.Object);
Debug.Assert(argState != null);
Debug.Assert(_keyName != null);
Debug.Assert(_valueName != null);
......@@ -67,13 +68,13 @@ internal override void Initialize(JsonSerializerOptions options)
if (!argState.FoundKey &&
FoundKeyProperty(propertyName, caseInsensitiveMatch))
{
jsonParameterInfo = classInfo.ParameterCache![_keyName];
jsonParameterInfo = typeInfo.ParameterCache![_keyName];
argState.FoundKey = true;
}
else if (!argState.FoundValue &&
FoundValueProperty(propertyName, caseInsensitiveMatch))
{
jsonParameterInfo = classInfo.ParameterCache![_valueName];
jsonParameterInfo = typeInfo.ParameterCache![_valueName];
argState.FoundValue = true;
}
else
......
......@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -44,7 +45,7 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer
if (parameterCount <= JsonConstants.UnboxedParameterCountThreshold)
{
Type placeHolderType = JsonClassInfo.ObjectType;
Type placeHolderType = JsonTypeInfo.ObjectType;
Type[] typeArguments = new Type[JsonConstants.UnboxedParameterCountThreshold + 1];
typeArguments[0] = typeToConvert;
......
......@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -25,12 +26,12 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert,
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
}
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(state.Current.JsonClassInfo.Type, ref reader, ref state);
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(state.Current.JsonTypeInfo.Type, ref reader, ref state);
}
obj = state.Current.JsonClassInfo.CreateObject!()!;
obj = state.Current.JsonTypeInfo.CreateObject!()!;
// Process all properties.
while (true)
......@@ -96,12 +97,12 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert,
if (state.Current.ObjectState < StackFrameObjectState.CreatedObject)
{
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(state.Current.JsonClassInfo.Type, ref reader, ref state);
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(state.Current.JsonTypeInfo.Type, ref reader, ref state);
}
obj = state.Current.JsonClassInfo.CreateObject!()!;
obj = state.Current.JsonTypeInfo.CreateObject!()!;
state.Current.ReturnValue = obj;
state.Current.ObjectState = StackFrameObjectState.CreatedObject;
......@@ -213,7 +214,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert,
// Check if we are trying to build the sorted cache.
if (state.Current.PropertyRefCache != null)
{
state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current);
state.Current.JsonTypeInfo.UpdateSortedPropertyCache(ref state.Current);
}
value = (T)obj;
......@@ -221,7 +222,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert,
return true;
}
internal sealed override bool OnTryWrite(
internal override bool OnTryWrite(
Utf8JsonWriter writer,
T value,
JsonSerializerOptions options,
......@@ -241,10 +242,10 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert,
}
}
JsonPropertyInfo? dataExtensionProperty = state.Current.JsonClassInfo.DataExtensionProperty;
JsonPropertyInfo? dataExtensionProperty = state.Current.JsonTypeInfo.DataExtensionProperty;
int propertyCount = 0;
JsonPropertyInfo[]? propertyCacheArray = state.Current.JsonClassInfo.PropertyCacheArray;
JsonPropertyInfo[]? propertyCacheArray = state.Current.JsonTypeInfo.PropertyCacheArray;
if (propertyCacheArray != null)
{
propertyCount = propertyCacheArray.Length;
......@@ -271,7 +272,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert,
{
if (!jsonPropertyInfo.GetMemberAndWriteJson(objectValue, ref state, writer))
{
Debug.Assert(jsonPropertyInfo.ConverterBase.ClassType != ClassType.Value);
Debug.Assert(jsonPropertyInfo.ConverterBase.ConverterStrategy != ConverterStrategy.Value);
return false;
}
}
......@@ -299,10 +300,10 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert,
state.Current.ProcessedStartToken = true;
}
JsonPropertyInfo? dataExtensionProperty = state.Current.JsonClassInfo.DataExtensionProperty;
JsonPropertyInfo? dataExtensionProperty = state.Current.JsonTypeInfo.DataExtensionProperty;
int propertyCount = 0;
JsonPropertyInfo[]? propertyCacheArray = state.Current.JsonClassInfo.PropertyCacheArray;
JsonPropertyInfo[]? propertyCacheArray = state.Current.JsonTypeInfo.PropertyCacheArray;
if (propertyCacheArray != null)
{
propertyCount = propertyCacheArray.Length;
......@@ -327,7 +328,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert,
{
if (!jsonPropertyInfo.GetMemberAndWriteJson(objectValue!, ref state, writer))
{
Debug.Assert(jsonPropertyInfo.ConverterBase.ClassType != ClassType.Value);
Debug.Assert(jsonPropertyInfo.ConverterBase.ConverterStrategy != ConverterStrategy.Value);
return false;
}
}
......@@ -392,7 +393,7 @@ protected bool ReadAheadPropertyValue(ref ReadStack state, ref Utf8JsonReader re
if (!state.Current.UseExtensionProperty)
{
if (!SingleValueReadWithReadAhead(jsonPropertyInfo.ConverterBase.ClassType, ref reader, ref state))
if (!SingleValueReadWithReadAhead(jsonPropertyInfo.ConverterBase.ConverterStrategy, ref reader, ref state))
{
return false;
}
......@@ -400,7 +401,7 @@ protected bool ReadAheadPropertyValue(ref ReadStack state, ref Utf8JsonReader re
else
{
// The actual converter is JsonElement, so force a read-ahead.
if (!SingleValueReadWithReadAhead(ClassType.Value, ref reader, ref state))
if (!SingleValueReadWithReadAhead(ConverterStrategy.Value, ref reader, ref state))
{
return false;
}
......@@ -411,12 +412,12 @@ protected bool ReadAheadPropertyValue(ref ReadStack state, ref Utf8JsonReader re
internal sealed override void CreateInstanceForReferenceResolver(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
{
if (state.Current.JsonClassInfo.CreateObject == null)
if (state.Current.JsonTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(state.Current.JsonClassInfo.Type, ref reader, ref state);
ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(state.Current.JsonTypeInfo.Type, ref reader, ref state);
}
object obj = state.Current.JsonClassInfo.CreateObject!()!;
object obj = state.Current.JsonTypeInfo.CreateObject!()!;
state.Current.ReturnValue = obj;
}
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
/// <summary>
/// Implementation of <cref>JsonObjectConverter{T}</cref> for source-generated converters.
/// </summary>
internal sealed class ObjectSourceGenConverter<T> : ObjectDefaultConverter<T> where T : notnull
{
internal override bool OnTryRead(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options,
ref ReadStack state,
[MaybeNullWhen(false)] out T value)
{
JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;
if (jsonTypeInfo.PropertyCache == null)
{
jsonTypeInfo.InitializeDeserializePropCache();
}
return base.OnTryRead(ref reader, typeToConvert, options, ref state, out value);
}
internal override bool OnTryWrite(
Utf8JsonWriter writer,
T value,
JsonSerializerOptions options,
ref WriteStack state)
{
JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo;
if (jsonTypeInfo.PropertyCacheArray == null)
{
jsonTypeInfo.InitializeSerializePropCache();
}
return base.OnTryWrite(writer, value, options, ref state);
}
}
}
......@@ -3,6 +3,7 @@
using System.Buffers;
using System.Diagnostics;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -31,7 +32,7 @@ protected override object CreateObject(ref ReadStackFrame frame)
{
object[] arguments = (object[])frame.CtorArgumentState!.Arguments;
var createObject = (JsonClassInfo.ParameterizedConstructorDelegate<T>?)frame.JsonClassInfo.CreateObjectWithArgs;
var createObject = (JsonTypeInfo.ParameterizedConstructorDelegate<T>?)frame.JsonTypeInfo.CreateObjectWithArgs;
if (createObject == null)
{
......@@ -47,15 +48,15 @@ protected override object CreateObject(ref ReadStackFrame frame)
protected override void InitializeConstructorArgumentCaches(ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
if (classInfo.CreateObjectWithArgs == null)
if (typeInfo.CreateObjectWithArgs == null)
{
classInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateParameterizedConstructor<T>(ConstructorInfo!);
typeInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateParameterizedConstructor<T>(ConstructorInfo!);
}
object[] arguments = ArrayPool<object>.Shared.Rent(classInfo.ParameterCount);
foreach (JsonParameterInfo jsonParameterInfo in classInfo.ParameterCache!.Values)
object[] arguments = ArrayPool<object>.Shared.Rent(typeInfo.ParameterCount);
foreach (JsonParameterInfo jsonParameterInfo in typeInfo.ParameterCache!.Values)
{
if (jsonParameterInfo.ShouldDeserialize)
{
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
......@@ -13,8 +14,8 @@ internal class SmallObjectWithParameterizedConstructorConverter<T, TArg0, TArg1,
{
protected override object CreateObject(ref ReadStackFrame frame)
{
var createObject = (JsonClassInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>)
frame.JsonClassInfo.CreateObjectWithArgs!;
var createObject = (JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>)
frame.JsonTypeInfo.CreateObjectWithArgs!;
var arguments = (Arguments<TArg0, TArg1, TArg2, TArg3>)frame.CtorArgumentState!.Arguments;
return createObject!(arguments.Arg0, arguments.Arg1, arguments.Arg2, arguments.Arg3);
}
......@@ -74,17 +75,17 @@ protected override object CreateObject(ref ReadStackFrame frame)
protected override void InitializeConstructorArgumentCaches(ref ReadStack state, JsonSerializerOptions options)
{
JsonClassInfo classInfo = state.Current.JsonClassInfo;
JsonTypeInfo typeInfo = state.Current.JsonTypeInfo;
if (classInfo.CreateObjectWithArgs == null)
if (typeInfo.CreateObjectWithArgs == null)
{
classInfo.CreateObjectWithArgs =
typeInfo.CreateObjectWithArgs =
options.MemberAccessorStrategy.CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo!);
}
var arguments = new Arguments<TArg0, TArg1, TArg2, TArg3>();
foreach (JsonParameterInfo parameterInfo in classInfo.ParameterCache!.Values)
foreach (JsonParameterInfo parameterInfo in typeInfo.ParameterCache!.Values)
{
if (parameterInfo.ShouldDeserialize)
{
......
......@@ -6,9 +6,10 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization.Metadata;
using FoundProperty = System.ValueTuple<System.Text.Json.JsonPropertyInfo, System.Text.Json.JsonReaderState, long, byte[]?, string?>;
using FoundPropertyAsync = System.ValueTuple<System.Text.Json.JsonPropertyInfo, object?, string?>;
using FoundProperty = System.ValueTuple<System.Text.Json.Serialization.Metadata.JsonPropertyInfo, System.Text.Json.JsonReaderState, long, byte[]?, string?>;
using FoundPropertyAsync = System.ValueTuple<System.Text.Json.Serialization.Metadata.JsonPropertyInfo, object?, string?>;
namespace System.Text.Json.Serialization.Converters
{
......@@ -62,7 +63,7 @@ internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToCo
if (useExtensionProperty)
{
Debug.Assert(jsonPropertyInfo == state.Current.JsonClassInfo.DataExtensionProperty);
Debug.Assert(jsonPropertyInfo == state.Current.JsonTypeInfo.DataExtensionProperty);
state.Current.JsonPropertyNameAsString = dataExtKey;
JsonSerializer.CreateDataExtensionProperty(obj, jsonPropertyInfo);
}
......@@ -106,7 +107,7 @@ internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToCo
}
else
{
Debug.Assert(jsonPropertyInfo == state.Current.JsonClassInfo.DataExtensionProperty);
Debug.Assert(jsonPropertyInfo == state.Current.JsonTypeInfo.DataExtensionProperty);
JsonSerializer.CreateDataExtensionProperty(obj, jsonPropertyInfo);
object extDictionary = jsonPropertyInfo.GetValueAsObject(obj)!;
......@@ -130,13 +131,13 @@ internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToCo
// Check if we are trying to build the sorted cache.
if (state.Current.PropertyRefCache != null)
{
state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current);
state.Current.JsonTypeInfo.UpdateSortedPropertyCache(ref state.Current);
}
// Check if we are trying to build the sorted parameter cache.
if (argumentState.ParameterRefCache != null)
{
state.Current.JsonClassInfo.UpdateSortedParameterCache(ref state.Current);
state.Current.JsonTypeInfo.UpdateSortedParameterCache(ref state.Current);
}
EndRead(ref state);
......@@ -208,7 +209,7 @@ private void ReadConstructorArguments(ref ReadStack state, ref Utf8JsonReader re
if (argumentState.FoundProperties == null)
{
argumentState.FoundProperties =
ArrayPool<FoundProperty>.Shared.Rent(Math.Max(1, state.Current.JsonClassInfo.PropertyCache!.Count));
ArrayPool<FoundProperty>.Shared.Rent(Math.Max(1, state.Current.JsonTypeInfo.PropertyCache!.Count));
}
else if (argumentState.FoundPropertyCount == argumentState.FoundProperties.Length)
{
......@@ -341,7 +342,7 @@ private bool ReadConstructorArgumentsWithContinuation(ref ReadStack state, ref U
// Returning false below will cause the read-ahead functionality to finish the read.
state.Current.PropertyState = StackFramePropertyState.ReadValue;
if (!SingleValueReadWithReadAhead(jsonParameterInfo.ConverterBase.ClassType, ref reader, ref state))
if (!SingleValueReadWithReadAhead(jsonParameterInfo.ConverterBase.ConverterStrategy, ref reader, ref state))
{
return false;
}
......@@ -406,7 +407,7 @@ private bool ReadConstructorArgumentsWithContinuation(ref ReadStack state, ref U
if (argumentState.FoundPropertiesAsync == null)
{
argumentState.FoundPropertiesAsync = ArrayPool<FoundPropertyAsync>.Shared.Rent(Math.Max(1, state.Current.JsonClassInfo.PropertyCache!.Count));
argumentState.FoundPropertiesAsync = ArrayPool<FoundPropertyAsync>.Shared.Rent(Math.Max(1, state.Current.JsonTypeInfo.PropertyCache!.Count));
}
else if (argumentState.FoundPropertyCount == argumentState.FoundPropertiesAsync!.Length)
{
......@@ -439,7 +440,7 @@ private void BeginRead(ref ReadStack state, ref Utf8JsonReader reader, JsonSeria
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
}
if (state.Current.JsonClassInfo.ParameterCount != state.Current.JsonClassInfo.ParameterCache!.Count)
if (state.Current.JsonTypeInfo.ParameterCount != state.Current.JsonTypeInfo.ParameterCache!.Count)
{
ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(ConstructorInfo!, TypeToConvert);
}
......@@ -463,11 +464,11 @@ private void BeginRead(ref ReadStack state, ref Utf8JsonReader reader, JsonSeria
JsonSerializerOptions options,
out JsonParameterInfo? jsonParameterInfo)
{
Debug.Assert(state.Current.JsonClassInfo.ClassType == ClassType.Object);
Debug.Assert(state.Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy == ConverterStrategy.Object);
ReadOnlySpan<byte> unescapedPropertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options);
jsonParameterInfo = state.Current.JsonClassInfo.GetParameter(
jsonParameterInfo = state.Current.JsonTypeInfo.GetParameter(
unescapedPropertyName,
ref state.Current,
out byte[] utf8PropertyName);
......
......@@ -17,9 +17,9 @@ public abstract partial class JsonConverter
// AggressiveInlining used since this method is on a hot path and short. The optionally called
// method DoSingleValueReadWithReadAhead is not inlined.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool SingleValueReadWithReadAhead(ClassType classType, ref Utf8JsonReader reader, ref ReadStack state)
internal static bool SingleValueReadWithReadAhead(ConverterStrategy converterStrategy, ref Utf8JsonReader reader, ref ReadStack state)
{
bool readAhead = (state.ReadAhead && (classType & (ClassType.Value | ClassType.NewValue)) != 0);
bool readAhead = state.ReadAhead && converterStrategy == ConverterStrategy.Value;
if (!readAhead)
{
return reader.Read();
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Reflection;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
......@@ -19,7 +20,7 @@ public abstract partial class JsonConverter
/// <returns>True if the type can be converted, false otherwise.</returns>
public abstract bool CanConvert(Type typeToConvert);
internal abstract ClassType ClassType { get; }
internal abstract ConverterStrategy ConverterStrategy { get; }
/// <summary>
/// Can direct Read or Write methods be called (for performance).
......@@ -87,7 +88,7 @@ internal bool ShouldFlush(Utf8JsonWriter writer, ref WriteStack state)
/// </summary>
internal abstract void WriteWithQuotesAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, ref WriteStack state);
// Whether a type (ClassType.Object) is deserialized using a parameterized constructor.
// Whether a type (ConverterStrategy.Object) is deserialized using a parameterized constructor.
internal virtual bool ConstructorIsParameterized { get; }
internal ConstructorInfo? ConstructorInfo { get; set; }
......
......@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
......@@ -18,11 +19,11 @@ public abstract class JsonConverterFactory : JsonConverter
/// </summary>
protected JsonConverterFactory() { }
internal sealed override ClassType ClassType
internal sealed override ConverterStrategy ConverterStrategy
{
get
{
return ClassType.None;
return ConverterStrategy.None;
}
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
......@@ -24,7 +24,7 @@ public partial class JsonConverter<T>
{
if (!state.IsContinuation)
{
if (!SingleValueReadWithReadAhead(ClassType, ref reader, ref state))
if (!SingleValueReadWithReadAhead(ConverterStrategy, ref reader, ref state))
{
if (state.SupportContinuation)
{
......@@ -51,14 +51,14 @@ public partial class JsonConverter<T>
{
// For a continuation, read ahead here to avoid having to build and then tear
// down the call stack if there is more than one buffer fetch necessary.
if (!SingleValueReadWithReadAhead(ClassType.Value, ref reader, ref state))
if (!SingleValueReadWithReadAhead(ConverterStrategy.Value, ref reader, ref state))
{
state.BytesConsumed += reader.BytesConsumed;
return default;
}
}
JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.PropertyInfoForClassInfo;
JsonPropertyInfo jsonPropertyInfo = state.Current.JsonTypeInfo.PropertyInfoForTypeInfo;
bool success = TryRead(ref reader, jsonPropertyInfo.RuntimePropertyType!, options, ref state, out T? value);
if (success)
{
......
......@@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
......@@ -19,7 +20,7 @@ protected internal JsonConverter()
{
// Today only typeof(object) can have polymorphic writes.
// In the future, this will be check for !IsSealed (and excluding value types).
CanBePolymorphic = TypeToConvert == JsonClassInfo.ObjectType;
CanBePolymorphic = TypeToConvert == JsonTypeInfo.ObjectType;
IsValueType = TypeToConvert.IsValueType;
CanBeNull = !IsValueType || TypeToConvert.IsNullableOfT();
IsInternalConverter = GetType().Assembly == typeof(JsonConverter).Assembly;
......@@ -36,7 +37,7 @@ protected internal JsonConverter()
// 2) A converter overroad HandleNull and returned false so HandleNullOnRead and HandleNullOnWrite
// will be their default values of false.
CanUseDirectReadOrWrite = !CanBePolymorphic && IsInternalConverter && ClassType == ClassType.Value;
CanUseDirectReadOrWrite = !CanBePolymorphic && IsInternalConverter && ConverterStrategy == ConverterStrategy.Value;
}
/// <summary>
......@@ -52,7 +53,7 @@ public override bool CanConvert(Type typeToConvert)
return typeToConvert == typeof(T);
}
internal override ClassType ClassType => ClassType.Value;
internal override ConverterStrategy ConverterStrategy => ConverterStrategy.Value;
internal sealed override JsonPropertyInfo CreateJsonPropertyInfo()
{
......@@ -144,7 +145,7 @@ internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, J
internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, out T? value)
{
if (ClassType == ClassType.Value)
if (ConverterStrategy == ConverterStrategy.Value)
{
// A value converter should never be within a continuation.
Debug.Assert(!state.IsContinuation);
......@@ -341,7 +342,7 @@ internal bool TryWrite(Utf8JsonWriter writer, in T value, JsonSerializerOptions
{
if (value == null)
{
Debug.Assert(ClassType == ClassType.Value);
Debug.Assert(ConverterStrategy == ConverterStrategy.Value);
Debug.Assert(!state.IsContinuation);
Debug.Assert(HandleNullOnWrite);
......@@ -353,7 +354,7 @@ internal bool TryWrite(Utf8JsonWriter writer, in T value, JsonSerializerOptions
}
Type type = value.GetType();
if (type == JsonClassInfo.ObjectType)
if (type == JsonTypeInfo.ObjectType)
{
writer.WriteStartObject();
writer.WriteEndObject();
......@@ -387,7 +388,7 @@ internal bool TryWrite(Utf8JsonWriter writer, in T value, JsonSerializerOptions
}
}
if (ClassType == ClassType.Value)
if (ConverterStrategy == ConverterStrategy.Value)
{
Debug.Assert(!state.IsContinuation);
......
......@@ -28,7 +28,7 @@ public static partial class JsonSerializer
ref ReadStack state,
JsonSerializerOptions options)
{
JsonConverter converter = state.Current.JsonClassInfo.PropertyInfoForClassInfo.ConverterBase;
JsonConverter converter = state.Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase;
if (state.Current.ObjectState < StackFrameObjectState.ReadAheadNameOrEndObject)
{
......@@ -169,7 +169,7 @@ public static partial class JsonSerializer
ref ReadStack state,
JsonSerializerOptions options)
{
JsonConverter converter = state.Current.JsonClassInfo.PropertyInfoForClassInfo.ConverterBase;
JsonConverter converter = state.Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase;
if (state.Current.ObjectState < StackFrameObjectState.ReadAheadNameOrEndObject)
{
......
......@@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json
{
......@@ -21,11 +22,11 @@ public static partial class JsonSerializer
out bool useExtensionProperty,
bool createExtensionProperty = true)
{
Debug.Assert(state.Current.JsonClassInfo.ClassType == ClassType.Object);
Debug.Assert(state.Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy == ConverterStrategy.Object);
useExtensionProperty = false;
JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(
JsonPropertyInfo jsonPropertyInfo = state.Current.JsonTypeInfo.GetProperty(
unescapedPropertyName,
ref state.Current,
out byte[] utf8PropertyName);
......@@ -39,7 +40,7 @@ public static partial class JsonSerializer
// Determine if we should use the extension property.
if (jsonPropertyInfo == JsonPropertyInfo.s_missingProperty)
{
JsonPropertyInfo? dataExtProperty = state.Current.JsonClassInfo.DataExtensionProperty;
JsonPropertyInfo? dataExtProperty = state.Current.JsonTypeInfo.DataExtensionProperty;
if (dataExtProperty != null && dataExtProperty.HasGetter && dataExtProperty.HasSetter)
{
state.Current.JsonPropertyNameAsString = JsonHelpers.Utf8GetString(unescapedPropertyName);
......@@ -108,15 +109,15 @@ public static partial class JsonSerializer
Debug.Assert(genericArgs.Length == 2);
Debug.Assert(genericArgs[0].UnderlyingSystemType == typeof(string));
Debug.Assert(
genericArgs[1].UnderlyingSystemType == JsonClassInfo.ObjectType ||
genericArgs[1].UnderlyingSystemType == JsonTypeInfo.ObjectType ||
genericArgs[1].UnderlyingSystemType == typeof(JsonElement));
#endif
if (jsonPropertyInfo.RuntimeClassInfo.CreateObject == null)
if (jsonPropertyInfo.RuntimeTypeInfo.CreateObject == null)
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(jsonPropertyInfo.DeclaredPropertyType);
}
extensionData = jsonPropertyInfo.RuntimeClassInfo.CreateObject();
extensionData = jsonPropertyInfo.RuntimeTypeInfo.CreateObject();
jsonPropertyInfo.SetExtensionDictionaryAsObject(obj, extensionData);
}
......
......@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json
{
......@@ -21,7 +22,7 @@ public static partial class JsonSerializer
Debug.Assert(writer != null);
// We treat typeof(object) special and allow polymorphic behavior.
if (inputType == JsonClassInfo.ObjectType && value != null)
if (inputType == JsonTypeInfo.ObjectType && value != null)
{
inputType = value.GetType();
}
......
......@@ -4,6 +4,7 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;
......@@ -108,7 +109,7 @@ public static partial class JsonSerializer
using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions))
{
// We treat typeof(object) special and allow polymorphic behavior.
if (inputType == JsonClassInfo.ObjectType && value != null)
if (inputType == JsonTypeInfo.ObjectType && value != null)
{
inputType = value!.GetType();
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
/// <summary>
/// Provides metadata about a set of types that is relevant to JSON serialization.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public abstract partial class JsonSerializerContext
{
internal JsonSerializerOptions? _options;
/// <summary>
/// Gets the run-time specified options of the context. If no options were passed
/// when instanciating the context, then a new instance is bound and returned.
/// </summary>
/// <remarks>
/// The instance cannot be mutated once it is bound with the context instance.
/// </remarks>
public JsonSerializerOptions Options
{
get
{
if (_options == null)
{
_options = new JsonSerializerOptions();
_options._context = this;
}
return _options;
}
}
/// <summary>
/// Creates an instance of <see cref="JsonSerializerContext"/> and binds it with the indicated <see cref="JsonSerializerOptions"/>.
/// </summary>
/// <param name="options">The run-time provided options for the context instance.</param>
/// <remarks>
/// If no options are passed, then no options are set until the context is bound using <see cref="JsonSerializerOptions.AddContext{TContext}"/>,
/// or until <see cref="Options"/> is called, where a new options instance is created and bound.
/// </remarks>
protected JsonSerializerContext(JsonSerializerOptions? options)
{
if (options != null)
{
if (options._context != null)
{
ThrowHelper.ThrowInvalidOperationException_JsonSerializerOptionsAlreadyBoundToContext();
}
_options = options;
options._context = this;
}
}
/// <summary>
/// Returns a <see cref="JsonTypeInfo"/> instance representing the given type.
/// </summary>
/// <param name="type">The type to fetch metadata about.</param>
/// <returns>Should return null if the context has no metadata for the type.</returns>
public abstract JsonTypeInfo? GetTypeInfo(Type type);
}
}
......@@ -7,6 +7,7 @@
using System.Reflection;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Converters;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json
{
......@@ -45,28 +46,28 @@ public sealed partial class JsonSerializerOptions
// Use a dictionary for simple converters.
// When adding to this, update NumberOfSimpleConverters above.
Add(new BooleanConverter());
Add(new ByteConverter());
Add(new ByteArrayConverter());
Add(new CharConverter());
Add(new DateTimeConverter());
Add(new DateTimeOffsetConverter());
Add(new DoubleConverter());
Add(new DecimalConverter());
Add(new GuidConverter());
Add(new Int16Converter());
Add(new Int32Converter());
Add(new Int64Converter());
Add(JsonMetadataServices.BooleanConverter);
Add(JsonMetadataServices.ByteConverter);
Add(JsonMetadataServices.ByteArrayConverter);
Add(JsonMetadataServices.CharConverter);
Add(JsonMetadataServices.DateTimeConverter);
Add(JsonMetadataServices.DateTimeOffsetConverter);
Add(JsonMetadataServices.DoubleConverter);
Add(JsonMetadataServices.DecimalConverter);
Add(JsonMetadataServices.GuidConverter);
Add(JsonMetadataServices.Int16Converter);
Add(JsonMetadataServices.Int32Converter);
Add(JsonMetadataServices.Int64Converter);
Add(new JsonElementConverter());
Add(new JsonDocumentConverter());
Add(new SByteConverter());
Add(new SingleConverter());
Add(new StringConverter());
Add(new UInt16Converter());
Add(new UInt32Converter());
Add(new UInt64Converter());
Add(new UriConverter());
Add(new VersionConverter());
Add(JsonMetadataServices.SByteConverter);
Add(JsonMetadataServices.SingleConverter);
Add(JsonMetadataServices.StringConverter);
Add(JsonMetadataServices.UInt16Converter);
Add(JsonMetadataServices.UInt32Converter);
Add(JsonMetadataServices.UInt64Converter);
Add(JsonMetadataServices.UriConverter);
Add(JsonMetadataServices.VersionConverter);
Debug.Assert(NumberOfSimpleConverters == converters.Count);
......
......@@ -8,6 +8,7 @@
using System.Text.Encodings.Web;
using System.Text.Json.Node;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json
{
......@@ -20,11 +21,11 @@ public sealed partial class JsonSerializerOptions
internal static readonly JsonSerializerOptions s_defaultOptions = new JsonSerializerOptions();
private readonly ConcurrentDictionary<Type, JsonClassInfo> _classes = new ConcurrentDictionary<Type, JsonClassInfo>();
private readonly ConcurrentDictionary<Type, JsonTypeInfo> _classes = new ConcurrentDictionary<Type, JsonTypeInfo>();
// Simple LRU cache for the public (de)serialize entry points that avoid some lookups in _classes.
// Although this may be written by multiple threads, 'volatile' was not added since any local affinity is fine.
private JsonClassInfo? _lastClass { get; set; }
private JsonTypeInfo? _lastClass { get; set; }
// For any new option added, adding it to the options copied in the copy constructor below must be considered.
......@@ -49,6 +50,8 @@ public sealed partial class JsonSerializerOptions
private bool _propertyNameCaseInsensitive;
private bool _writeIndented;
internal JsonSerializerContext? _context;
/// <summary>
/// Constructs a new <see cref="JsonSerializerOptions"/> instance.
/// </summary>
......@@ -96,7 +99,7 @@ public JsonSerializerOptions(JsonSerializerOptions options)
EffectiveMaxDepth = options.EffectiveMaxDepth;
ReferenceHandlingStrategy = options.ReferenceHandlingStrategy;
// _classes is not copied as sharing the JsonClassInfo and JsonPropertyInfo caches can result in
// _classes is not copied as sharing the JsonTypeInfo and JsonPropertyInfo caches can result in
// unnecessary references to type metadata, potentially hindering garbage collection on the source options.
// _haveTypesBeenCreated is not copied; it's okay to make changes to this options instance as (de)serialization has not occurred.
......@@ -135,6 +138,25 @@ public JsonSerializerOptions(JsonSerializerDefaults defaults) : this()
}
}
/// <summary>
/// Binds current <see cref="JsonSerializerOptions"/> instance with a new instance of the specified <see cref="JsonSerializerContext"/> type.
/// </summary>
/// <typeparam name="TContext">The generic definition of the specified context type.</typeparam>
/// <remarks>When serializing and deserializing types using the options
/// instance, metadata for the types will be fetched from the context instance.
/// </remarks>
public void AddContext<TContext>() where TContext : JsonSerializerContext, new()
{
if (_context != null)
{
ThrowHelper.ThrowInvalidOperationException_JsonSerializerOptionsAlreadyBoundToContext();
}
TContext context = new();
_context = context;
context._options = this;
}
/// <summary>
/// Defines whether an extra comma at the end of a list of JSON values in an object or array
/// is allowed (and ignored) within the JSON payload being deserialized.
......@@ -545,34 +567,34 @@ internal MemberAccessor MemberAccessorStrategy
}
}
internal JsonClassInfo GetOrAddClass(Type type)
internal JsonTypeInfo GetOrAddClass(Type type)
{
_haveTypesBeenCreated = true;
// todo: for performance and reduced instances, consider using the converters and JsonClassInfo from s_defaultOptions by cloning (or reference directly if no changes).
// todo: for performance and reduced instances, consider using the converters and JsonTypeInfo from s_defaultOptions by cloning (or reference directly if no changes).
// https://github.com/dotnet/runtime/issues/32357
if (!_classes.TryGetValue(type, out JsonClassInfo? result))
if (!_classes.TryGetValue(type, out JsonTypeInfo? result))
{
result = _classes.GetOrAdd(type, new JsonClassInfo(type, this));
result = _classes.GetOrAdd(type, new JsonTypeInfo(type, this));
}
return result;
}
/// <summary>
/// Return the ClassInfo for root API calls.
/// Return the TypeInfo for root API calls.
/// This has a LRU cache that is intended only for public API calls that specify the root type.
/// </summary>
internal JsonClassInfo GetOrAddClassForRootType(Type type)
internal JsonTypeInfo GetOrAddClassForRootType(Type type)
{
JsonClassInfo? jsonClassInfo = _lastClass;
if (jsonClassInfo?.Type != type)
JsonTypeInfo? jsonTypeInfo = _lastClass;
if (jsonTypeInfo?.Type != type)
{
jsonClassInfo = GetOrAddClass(type);
_lastClass = jsonClassInfo;
jsonTypeInfo = GetOrAddClass(type);
_lastClass = jsonTypeInfo;
}
return jsonClassInfo;
return jsonTypeInfo;
}
internal bool TypeIsCached(Type type)
......@@ -621,9 +643,9 @@ internal void VerifyMutable()
// The default options are hidden and thus should be immutable.
Debug.Assert(this != s_defaultOptions);
if (_haveTypesBeenCreated)
if (_haveTypesBeenCreated || _context != null)
{
ThrowHelper.ThrowInvalidOperationException_SerializerOptionsImmutable();
ThrowHelper.ThrowInvalidOperationException_SerializerOptionsImmutable(_context);
}
}
}
......
......@@ -4,7 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Text.Json.Serialization
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Allows virtual dispatch to GenericMethodHolder{T}.
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Text.Json.Serialization.Converters;
namespace System.Text.Json.Serialization.Metadata
{
public static partial class JsonMetadataServices
{
/// <summary>
/// Creates metadata for an array.
/// </summary>
/// <typeparam name="TElement">The generic definition of the element type.</typeparam>
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
/// <param name="elementInfo">A <see cref="JsonTypeInfo"/> instance representing the element type.</param>
/// <param name="numberHandling">The <see cref="JsonNumberHandling"/> option to apply to number collection elements.</param>
/// <returns></returns>
public static JsonTypeInfo<TElement[]> CreateArrayInfo<TElement>(
JsonSerializerOptions options,
JsonTypeInfo elementInfo,
JsonNumberHandling numberHandling)
=> new JsonTypeInfoInternal<TElement[]>(
options,
createObjectFunc: null,
new ArrayConverter<TElement[], TElement>(),
elementInfo,
numberHandling);
/// <summary>
/// Creates metadata for types assignable to <see cref="List{T}"/>.
/// </summary>
/// <typeparam name="TCollection">The generic definition of the type.</typeparam>
/// <typeparam name="TElement">The generic definition of the element type.</typeparam>
/// <param name="options"></param>
/// <param name="createObjectFunc">A <see cref="Func{TResult}"/> to create an instance of the list when deserializing.</param>
/// <param name="elementInfo">A <see cref="JsonTypeInfo"/> instance representing the element type.</param>
/// <param name="numberHandling">The <see cref="JsonNumberHandling"/> option to apply to number collection elements.</param>
/// <returns></returns>
public static JsonTypeInfo<TCollection> CreateListInfo<TCollection, TElement>(
JsonSerializerOptions options,
Func<TCollection>? createObjectFunc,
JsonTypeInfo elementInfo,
JsonNumberHandling numberHandling)
where TCollection : List<TElement>
=> new JsonTypeInfoInternal<TCollection>(
options,
createObjectFunc,
new ListOfTConverter<TCollection, TElement>(),
elementInfo,
numberHandling);
/// <summary>
/// Creates metadata for types assignable to <see cref="Dictionary{TKey, TValue}"/>.
/// </summary>
/// <typeparam name="TCollection">The generic definition of the type.</typeparam>
/// <typeparam name="TKey">The generic definition of the key type.</typeparam>
/// <typeparam name="TValue">The generic definition of the value type.</typeparam>
/// <param name="options"></param>
/// <param name="createObjectFunc">A <see cref="Func{TResult}"/> to create an instance of the list when deserializing.</param>
/// <param name="keyInfo">A <see cref="JsonTypeInfo"/> instance representing the key type.</param>
/// <param name="valueInfo">A <see cref="JsonTypeInfo"/> instance representing the value type.</param>
/// <param name="numberHandling">The <see cref="JsonNumberHandling"/> option to apply to number collection elements.</param>
/// <returns></returns>
public static JsonTypeInfo<TCollection> CreateDictionaryInfo<TCollection, TKey, TValue>(
JsonSerializerOptions options,
Func<TCollection> createObjectFunc,
JsonTypeInfo keyInfo,
JsonTypeInfo valueInfo,
JsonNumberHandling numberHandling)
where TCollection : Dictionary<TKey, TValue>
where TKey : notnull
=> new JsonTypeInfoInternal<TCollection>(
options,
createObjectFunc,
new DictionaryOfTKeyTValueConverter<TCollection, TKey, TValue>(),
keyInfo,
valueInfo,
numberHandling);
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text.Json.Serialization.Converters;
namespace System.Text.Json.Serialization.Metadata
{
public static partial class JsonMetadataServices
{
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="bool"/> values.
/// </summary>
public static JsonConverter<bool> BooleanConverter => s_booleanConverter ??= new BooleanConverter();
private static JsonConverter<bool>? s_booleanConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts byte array values.
/// </summary>
public static JsonConverter<byte[]> ByteArrayConverter => s_byteArrayConverter ??= new ByteArrayConverter();
private static JsonConverter<byte[]>? s_byteArrayConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="byte"/> values.
/// </summary>
public static JsonConverter<byte> ByteConverter => s_byteConverter ??= new ByteConverter();
private static JsonConverter<byte>? s_byteConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="char"/> values.
/// </summary>
public static JsonConverter<char> CharConverter => s_charConverter ??= new CharConverter();
private static JsonConverter<char>? s_charConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="DateTime"/> values.
/// </summary>
public static JsonConverter<DateTime> DateTimeConverter => s_dateTimeConverter ??= new DateTimeConverter();
private static JsonConverter<DateTime>? s_dateTimeConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="DateTimeOffset"/> values.
/// </summary>
public static JsonConverter<DateTimeOffset> DateTimeOffsetConverter => s_dateTimeOffsetConverter ??= new DateTimeOffsetConverter();
private static JsonConverter<DateTimeOffset>? s_dateTimeOffsetConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="decimal"/> values.
/// </summary>
public static JsonConverter<decimal> DecimalConverter => s_decimalConverter ??= new DecimalConverter();
private static JsonConverter<decimal>? s_decimalConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="double"/> values.
/// </summary>
public static JsonConverter<double> DoubleConverter => s_doubleConverter ??= new DoubleConverter();
private static JsonConverter<double>? s_doubleConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="Guid"/> values.
/// </summary>
public static JsonConverter<Guid> GuidConverter => s_guidConverter ??= new GuidConverter();
private static JsonConverter<Guid>? s_guidConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="short"/> values.
/// </summary>
public static JsonConverter<short> Int16Converter => s_int16Converter ??= new Int16Converter();
private static JsonConverter<short>? s_int16Converter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="int"/> values.
/// </summary>
public static JsonConverter<int> Int32Converter => s_int32Converter ??= new Int32Converter();
private static JsonConverter<int>? s_int32Converter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="long"/> values.
/// </summary>
public static JsonConverter<long> Int64Converter => s_int64Converter ??= new Int64Converter();
private static JsonConverter<long>? s_int64Converter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="object"/> values.
/// </summary>
public static JsonConverter<object> ObjectConverter => s_objectConverter ??= new ObjectConverter();
private static JsonConverter<object>? s_objectConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="float"/> values.
/// </summary>
public static JsonConverter<float> SingleConverter => s_singleConverter ??= new SingleConverter();
private static JsonConverter<float>? s_singleConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="sbyte"/> values.
/// </summary>
[CLSCompliant(false)]
public static JsonConverter<sbyte> SByteConverter => s_sbyteConverter ??= new SByteConverter();
private static JsonConverter<sbyte>? s_sbyteConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="string"/> values.
/// </summary>
public static JsonConverter<string> StringConverter => s_stringConverter ??= new StringConverter();
private static JsonConverter<string>? s_stringConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="ushort"/> values.
/// </summary>
[CLSCompliant(false)]
public static JsonConverter<ushort> UInt16Converter => s_uint16Converter ??= new UInt16Converter();
private static JsonConverter<ushort>? s_uint16Converter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="uint"/> values.
/// </summary>
[CLSCompliant(false)]
public static JsonConverter<uint> UInt32Converter => s_uint32Converter ??= new UInt32Converter();
private static JsonConverter<uint>? s_uint32Converter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="ulong"/> values.
/// </summary>
[CLSCompliant(false)]
public static JsonConverter<ulong> UInt64Converter => s_uint64Converter ??= new UInt64Converter();
private static JsonConverter<ulong>? s_uint64Converter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="Uri"/> values.
/// </summary>
public static JsonConverter<Uri> UriConverter => s_uriConverter ??= new UriConverter();
private static JsonConverter<Uri>? s_uriConverter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="Version"/> values.
/// </summary>
public static JsonConverter<Version> VersionConverter => s_versionConverter ??= new VersionConverter();
private static JsonConverter<Version>? s_versionConverter;
/// <summary>
/// Creates a <see cref="JsonConverter{T}"/> instance that converts <typeparamref name="T"/> values.
/// </summary>
/// <typeparam name="T">The generic definition for the enum type.</typeparam>
/// <param name="options"></param>
/// <returns></returns>
public static JsonConverter<T> GetEnumConverter<T>(JsonSerializerOptions options) where T : struct, Enum
=> new EnumConverter<T>(EnumConverterOptions.AllowNumbers, options ?? throw new ArgumentNullException(nameof(options)));
/// <summary>
/// Creates a <see cref="JsonConverter{T}"/> instance that converts <typeparamref name="T?"/> values.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="underlyingTypeconverter"></param>
/// <returns></returns>
public static JsonConverter<T?> GetNullableConverter<T>(JsonConverter<T> underlyingTypeconverter) where T : struct
=> new NullableConverter<T>(underlyingTypeconverter ?? throw new ArgumentNullException(nameof(underlyingTypeconverter)));
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
using System.Diagnostics;
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Provides helpers to create and initialize metadata for JSON-serializable types.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static partial class JsonMetadataServices
{
/// <summary>
/// Creates metadata for a property or field.
/// </summary>
/// <typeparam name="T">The type that the converter for the property returns or accepts when converting JSON data.</typeparam>
/// <returns>A <see cref="JsonPropertyInfo"/> instance intialized with the provided metadata.</returns>
public static JsonPropertyInfo CreatePropertyInfo<T>(
JsonSerializerOptions options,
bool isProperty,
Type declaringType,
JsonTypeInfo propertyTypeInfo,
JsonConverter<T>? converter,
Func<object, T>? getter,
Action<object, T>? setter,
JsonIgnoreCondition ignoreCondition,
JsonNumberHandling numberHandling,
string propertyName,
JsonEncodedText jsonPropertyName)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (declaringType == null)
{
throw new ArgumentNullException(nameof(declaringType));
}
if (propertyTypeInfo == null)
{
throw new ArgumentNullException(nameof(propertyTypeInfo));
}
if (propertyName == null)
{
throw new ArgumentNullException(propertyName);
}
if (converter == null)
{
converter = propertyTypeInfo.PropertyInfoForTypeInfo.ConverterBase as JsonConverter<T>;
if (converter == null)
{
throw new InvalidOperationException(SR.Format(SR.ConverterForPropertyMustBeValid, declaringType, propertyName, typeof(T)));
}
}
JsonPropertyInfo<T> jsonPropertyInfo = new JsonPropertyInfo<T>();
jsonPropertyInfo.InitializeForSourceGen(
options,
isProperty,
declaringType,
propertyTypeInfo,
converter,
getter,
setter,
ignoreCondition,
numberHandling,
propertyName,
jsonPropertyName);
return jsonPropertyInfo;
}
/// <summary>
/// Creates metadata for a complex class or struct.
/// </summary>
/// <typeparam name="T">The type of the class or struct.</typeparam>
/// <returns>A <see cref="JsonTypeInfo{T}"/> instance representing the class or struct.</returns>
public static JsonTypeInfo<T> CreateObjectInfo<T>() where T : notnull => new JsonTypeInfoInternal<T>();
/// <summary>
/// Initializes metadata for a class or struct.
/// </summary>
/// <typeparam name="T">The type of the class or struct</typeparam>
/// <param name="info"></param>
/// <param name="options"></param>
/// <param name="createObjectFunc"></param>
/// <param name="propInitFunc"></param>
/// <param name="numberHandling"></param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="options"/>, <paramref name="info"/>, or <paramref name="propInitFunc"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="info"/>, does not represent a complex class or struct type.</exception>
public static void InitializeObjectInfo<T>(
JsonTypeInfo<T> info,
JsonSerializerOptions options,
Func<T>? createObjectFunc,
Func<JsonSerializerContext, JsonPropertyInfo[]> propInitFunc,
JsonNumberHandling numberHandling)
where T : notnull
{
if (info == null)
{
throw new ArgumentNullException(nameof(info));
}
if (info.PropertyInfoForTypeInfo != null)
{
// ConverterStrategy.Object is the only info type we won't have set PropertyInfoForTypeInfo for at this point.
throw new ArgumentException(SR.InitializeTypeInfoAsObjectInvalid, nameof(info));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (propInitFunc == null)
{
throw new ArgumentNullException(nameof(propInitFunc));
}
((JsonTypeInfoInternal<T>)info).InitializeAsObject(options, createObjectFunc, propInitFunc, numberHandling);
Debug.Assert(info.PropertyInfoForTypeInfo!.ConverterStrategy == ConverterStrategy.Object);
}
/// <summary>
/// Creates metadata for a primitive or a type with a custom converter.
/// </summary>
/// <typeparam name="T">The generic type definition.</typeparam>
/// <typeparam name="TConverterReturn">The generic type definition.</typeparam>
/// <returns>A <see cref="JsonTypeInfo{T}"/> instance representing the type.</returns>
public static JsonTypeInfo<T> CreateValueInfo<T, TConverterReturn>(JsonSerializerOptions options, JsonConverter<TConverterReturn> converter)
where TConverterReturn : T
{
JsonTypeInfo<T> info = new JsonTypeInfoInternal<T>(options);
info.PropertyInfoForTypeInfo = JsonPropertyInfo<TConverterReturn>.CreateForSourceGenTypeInfo(typeof(T), runtimeTypeInfo: info, converter, options);
return info;
}
}
}
......@@ -3,9 +3,8 @@
using System.Diagnostics;
using System.Reflection;
using System.Text.Json.Serialization;
namespace System.Text.Json
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Holds relevant state about a method parameter, like the default value of
......@@ -21,7 +20,7 @@ internal abstract class JsonParameterInfo
public bool IgnoreDefaultValuesOnRead { get; private set; }
// Options can be referenced here since all JsonPropertyInfos originate from a JsonClassInfo that is cached on JsonSerializerOptions.
// Options can be referenced here since all JsonPropertyInfos originate from a JsonTypeInfo that is cached on JsonSerializerOptions.
public JsonSerializerOptions? Options { get; set; } // initialized in Init method
// The name of the parameter as UTF-8 bytes.
......@@ -32,19 +31,19 @@ internal abstract class JsonParameterInfo
// The zero-based position of the parameter in the formal parameter list.
public int Position { get; private set; }
private JsonClassInfo? _runtimeClassInfo;
public JsonClassInfo RuntimeClassInfo
private JsonTypeInfo? _runtimeTypeInfo;
public JsonTypeInfo RuntimeTypeInfo
{
get
{
Debug.Assert(ShouldDeserialize);
if (_runtimeClassInfo == null)
if (_runtimeTypeInfo == null)
{
Debug.Assert(Options != null);
_runtimeClassInfo = Options!.GetOrAddClass(RuntimePropertyType);
_runtimeTypeInfo = Options!.GetOrAddClass(RuntimePropertyType);
}
return _runtimeClassInfo;
return _runtimeTypeInfo;
}
}
......
......@@ -4,7 +4,7 @@
using System.Diagnostics;
using System.Reflection;
namespace System.Text.Json
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Represents a strongly-typed parameter to prevent boxing where have less than 4 parameters.
......
......@@ -4,15 +4,14 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text.Json.Serialization;
namespace System.Text.Json
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Represents a strongly-typed property to prevent boxing and to create a direct delegate to the getter\setter.
/// </summary>
/// <typeparamref name="T"/> is the <see cref="JsonConverter{T}.TypeToConvert"/> for either the property's converter,
/// or a type's converter, if the current instance is a <see cref="JsonClassInfo.PropertyInfoForClassInfo"/>.
/// or a type's converter, if the current instance is a <see cref="JsonTypeInfo.PropertyInfoForTypeInfo"/>.
internal sealed class JsonPropertyInfo<T> : JsonPropertyInfo
{
/// <summary>
......@@ -27,16 +26,16 @@ internal sealed class JsonPropertyInfo<T> : JsonPropertyInfo
// the property's type, we track that and whether the property type can be null.
private bool _propertyTypeEqualsTypeToConvert;
public Func<object, T>? Get { get; private set; }
public Action<object, T>? Set { get; private set; }
internal Func<object, T>? Get { get; set; }
internal Action<object, T>? Set { get; set; }
public JsonConverter<T> Converter { get; internal set; } = null!;
public override void Initialize(
internal override void Initialize(
Type parentClassType,
Type declaredPropertyType,
Type? runtimePropertyType,
ClassType runtimeClassType,
ConverterStrategy runtimeClassType,
MemberInfo? memberInfo,
JsonConverter converter,
JsonIgnoreCondition? ignoreCondition,
......@@ -74,6 +73,8 @@ internal sealed class JsonPropertyInfo<T> : JsonPropertyInfo
Set = options.MemberAccessorStrategy.CreatePropertySetter<T>(propertyInfo);
}
MemberType = MemberTypes.Property;
break;
}
......@@ -90,12 +91,14 @@ internal sealed class JsonPropertyInfo<T> : JsonPropertyInfo
Set = options.MemberAccessorStrategy.CreateFieldSetter<T>(fieldInfo);
}
MemberType = MemberTypes.Field;
break;
}
default:
{
IsForClassInfo = true;
IsForTypeInfo = true;
HasGetter = true;
HasSetter = true;
......@@ -107,10 +110,123 @@ internal sealed class JsonPropertyInfo<T> : JsonPropertyInfo
PropertyTypeCanBeNull = DeclaredPropertyType.CanBeNull();
_propertyTypeEqualsTypeToConvert = typeof(T) == DeclaredPropertyType;
GetPolicies(ignoreCondition, parentTypeNumberHandling, defaultValueIsNull: PropertyTypeCanBeNull);
GetPolicies(ignoreCondition, parentTypeNumberHandling);
}
internal void InitializeForSourceGen(
JsonSerializerOptions options,
bool isProperty,
Type declaringType,
JsonTypeInfo typeInfo,
JsonConverter<T> converter,
Func<object, T>? getter,
Action<object, T>? setter,
JsonIgnoreCondition ignoreCondition,
JsonNumberHandling numberHandling,
string propertyName,
JsonEncodedText jsonPropertyName)
{
Options = options;
ClrName = propertyName;
byte[] encodedName = jsonPropertyName._utf8Value;
string encodedNameAsStr = jsonPropertyName._value;
// Property name settings.
if (encodedName != null && options.PropertyNamingPolicy == null && options.Encoder == null)
{
NameAsString = encodedNameAsStr;
NameAsUtf8Bytes = encodedName;
int nameLength = encodedName.Length;
EscapedNameSection = new byte[nameLength + 3];
EscapedNameSection[0] = (byte)'"';
encodedName.CopyTo(EscapedNameSection, 1);
EscapedNameSection[nameLength - 2] = (byte)'"';
EscapedNameSection[nameLength - 1] = (byte)':';
}
else
{
if (encodedNameAsStr != null)
{
NameAsString = encodedNameAsStr;
}
else if (options.PropertyNamingPolicy == null)
{
NameAsString = ClrName;
}
else
{
NameAsString = options.PropertyNamingPolicy.ConvertName(ClrName);
if (NameAsString == null)
{
ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(DeclaringType, this);
}
}
NameAsUtf8Bytes ??= Encoding.UTF8.GetBytes(NameAsString!);
EscapedNameSection ??= JsonHelpers.GetEscapedPropertyNameSection(NameAsUtf8Bytes, Options.Encoder);
}
if (ignoreCondition == JsonIgnoreCondition.Always)
{
IsIgnored = true;
Debug.Assert(!ShouldSerialize);
Debug.Assert(!ShouldDeserialize);
}
else
{
Get = getter;
Set = setter;
HasGetter = Get != null;
HasSetter = Set != null;
ConverterBase = converter;
RuntimeTypeInfo = typeInfo;
DeclaredPropertyType = typeof(T);
DeclaringType = declaringType;
IgnoreCondition = ignoreCondition;
MemberType = isProperty ? MemberTypes.Property : MemberTypes.Field;
_converterIsExternalAndPolymorphic = !converter.IsInternalConverter && DeclaredPropertyType != converter.TypeToConvert;
PropertyTypeCanBeNull = typeof(T).CanBeNull();
_propertyTypeEqualsTypeToConvert = converter.TypeToConvert == typeof(T);
ConverterStrategy = Converter!.ConverterStrategy;
RuntimePropertyType = DeclaredPropertyType;
DetermineIgnoreCondition(IgnoreCondition);
// TODO: this method needs to also take the number handling option for the declaring type.
DetermineNumberHandlingForProperty(numberHandling, declaringTypeNumberHandling: null);
DetermineSerializationCapabilities(IgnoreCondition);
}
}
/// <summary>
/// Create a <see cref="JsonPropertyInfo"/> for a given Type.
/// See <seealso cref="JsonTypeInfo.PropertyInfoForTypeInfo"/>.
/// </summary>
internal static JsonPropertyInfo CreateForSourceGenTypeInfo(
Type declaredPropertyType,
JsonTypeInfo runtimeTypeInfo,
JsonConverter converter,
JsonSerializerOptions options)
{
JsonPropertyInfo<T> jsonPropertyInfo = new JsonPropertyInfo<T>();
jsonPropertyInfo.DeclaredPropertyType = declaredPropertyType;
jsonPropertyInfo.RuntimePropertyType = declaredPropertyType;
jsonPropertyInfo.ConverterStrategy = converter.ConverterStrategy;
jsonPropertyInfo.RuntimeTypeInfo = runtimeTypeInfo;
jsonPropertyInfo.ConverterBase = converter;
jsonPropertyInfo.Options = options;
jsonPropertyInfo.IsForTypeInfo = true;
jsonPropertyInfo.HasGetter = true;
jsonPropertyInfo.HasSetter = true;
// TODO (perf): can we pre-compute some of these values during source gen?
jsonPropertyInfo._converterIsExternalAndPolymorphic = !converter.IsInternalConverter && declaredPropertyType != converter.TypeToConvert;
jsonPropertyInfo.PropertyTypeCanBeNull = declaredPropertyType.CanBeNull();
jsonPropertyInfo._propertyTypeEqualsTypeToConvert = typeof(T) == declaredPropertyType;
return jsonPropertyInfo;
}
public override JsonConverter ConverterBase
internal override JsonConverter ConverterBase
{
get
{
......@@ -123,9 +239,9 @@ public override JsonConverter ConverterBase
}
}
public override object? GetValueAsObject(object obj)
internal override object? GetValueAsObject(object obj)
{
if (IsForClassInfo)
if (IsForTypeInfo)
{
return obj;
}
......@@ -134,7 +250,7 @@ public override JsonConverter ConverterBase
return Get!(obj);
}
public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
internal override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
{
T value = Get!(obj);
......@@ -167,10 +283,10 @@ public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf
}
else
{
Debug.Assert(RuntimeClassInfo.Type == DeclaredPropertyType);
Debug.Assert(RuntimeTypeInfo.Type == DeclaredPropertyType);
// Use a late-bound call to EqualityComparer<DeclaredPropertyType>.
if (RuntimeClassInfo.GenericMethods.IsDefaultValue(value))
if (RuntimeTypeInfo.GenericMethods.IsDefaultValue(value))
{
return true;
}
......@@ -185,7 +301,7 @@ public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf
if (Converter.HandleNullOnWrite)
{
// No object, collection, or re-entrancy converter handles null.
Debug.Assert(Converter.ClassType == ClassType.Value);
Debug.Assert(Converter.ConverterStrategy == ConverterStrategy.Value);
if (state.Current.PropertyState < StackFramePropertyState.Name)
{
......@@ -219,7 +335,7 @@ public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf
}
}
public override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer)
internal override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer)
{
bool success;
T value = Get!(obj);
......@@ -236,7 +352,7 @@ public override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteSta
return success;
}
public override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref Utf8JsonReader reader)
internal override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref Utf8JsonReader reader)
{
bool success;
......@@ -306,7 +422,7 @@ public override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref U
return success;
}
public override bool ReadJsonAsObject(ref ReadStack state, ref Utf8JsonReader reader, out object? value)
internal override bool ReadJsonAsObject(ref ReadStack state, ref Utf8JsonReader reader, out object? value)
{
bool success;
bool isNullToken = reader.TokenType == JsonTokenType.Null;
......@@ -341,7 +457,7 @@ public override bool ReadJsonAsObject(ref ReadStack state, ref Utf8JsonReader re
return success;
}
public override void SetExtensionDictionaryAsObject(object obj, object? extensionDict)
internal override void SetExtensionDictionaryAsObject(object obj, object? extensionDict)
{
Debug.Assert(HasSetter);
T typedValue = (T)extensionDict!;
......
......@@ -6,12 +6,10 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
namespace System.Text.Json
namespace System.Text.Json.Serialization.Metadata
{
[DebuggerDisplay("ClassType.{ClassType}, {Type.Name}")]
internal sealed partial class JsonClassInfo
public partial class JsonTypeInfo
{
/// <summary>
/// Cached typeof(object). It is faster to cache this than to call typeof(object) multiple times.
......@@ -31,18 +29,18 @@ internal sealed partial class JsonClassInfo
// The number of parameters the deserialization constructor has. If this is not equal to ParameterCache.Count, this means
// that not all parameters are bound to object properties, and an exception will be thrown if deserialization is attempted.
public int ParameterCount { get; private set; }
internal int ParameterCount { get; private set; }
// All of the serializable parameters on a POCO constructor keyed on parameter name.
// Only paramaters which bind to properties are cached.
public Dictionary<string, JsonParameterInfo>? ParameterCache;
internal Dictionary<string, JsonParameterInfo>? ParameterCache;
// All of the serializable properties on a POCO (except the optional extension property) keyed on property name.
public Dictionary<string, JsonPropertyInfo>? PropertyCache;
internal Dictionary<string, JsonPropertyInfo>? PropertyCache;
// All of the serializable properties on a POCO including the optional extension property.
// Used for performance during serialization instead of 'PropertyCache' above.
public JsonPropertyInfo[]? PropertyCacheArray;
internal JsonPropertyInfo[]? PropertyCacheArray;
// Fast cache of constructor parameters by first JSON ordering; may not contain all parameters. Accessed before ParameterCache.
// Use an array (instead of List<T>) for highest performance.
......@@ -52,7 +50,9 @@ internal sealed partial class JsonClassInfo
// Use an array (instead of List<T>) for highest performance.
private volatile PropertyRef[]? _propertyRefsSorted;
public static JsonPropertyInfo AddProperty(
internal Func<JsonSerializerContext, JsonPropertyInfo[]>? PropInitFunc;
internal static JsonPropertyInfo AddProperty(
MemberInfo memberInfo,
Type memberType,
Type parentClassType,
......@@ -100,7 +100,7 @@ internal sealed partial class JsonClassInfo
parentClassType,
declaredPropertyType,
runtimePropertyType,
runtimeClassType: converter.ClassType,
runtimeClassType: converter.ConverterStrategy,
memberInfo,
converter,
ignoreCondition,
......@@ -112,33 +112,32 @@ internal sealed partial class JsonClassInfo
/// <summary>
/// Create a <see cref="JsonPropertyInfo"/> for a given Type.
/// See <seealso cref="JsonClassInfo.PropertyInfoForClassInfo"/>.
/// See <seealso cref="JsonTypeInfo.PropertyInfoForTypeInfo"/>.
/// </summary>
internal static JsonPropertyInfo CreatePropertyInfoForClassInfo(
internal static JsonPropertyInfo CreatePropertyInfoForTypeInfo(
Type declaredPropertyType,
Type runtimePropertyType,
JsonConverter converter,
JsonNumberHandling? numberHandling,
JsonSerializerOptions options)
{
JsonNumberHandling? numberHandling = GetNumberHandlingForType(declaredPropertyType);
JsonPropertyInfo jsonPropertyInfo = CreateProperty(
declaredPropertyType: declaredPropertyType,
runtimePropertyType: runtimePropertyType,
memberInfo: null, // Not a real property so this is null.
parentClassType: JsonClassInfo.ObjectType, // a dummy value (not used)
parentClassType: JsonTypeInfo.ObjectType, // a dummy value (not used)
converter: converter,
options,
parentTypeNumberHandling: numberHandling);
Debug.Assert(jsonPropertyInfo.IsForClassInfo);
Debug.Assert(jsonPropertyInfo.IsForTypeInfo);
return jsonPropertyInfo;
}
// AggressiveInlining used although a large method it is only called from one location and is on a hot path.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public JsonPropertyInfo GetProperty(
internal JsonPropertyInfo GetProperty(
ReadOnlySpan<byte> propertyName,
ref ReadStackFrame frame,
out byte[] utf8PropertyName)
......@@ -275,7 +274,7 @@ internal sealed partial class JsonClassInfo
// AggressiveInlining used although a large method it is only called from one location and is on a hot path.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public JsonParameterInfo? GetParameter(
internal JsonParameterInfo? GetParameter(
ReadOnlySpan<byte> propertyName,
ref ReadStackFrame frame,
out byte[] utf8PropertyName)
......@@ -446,7 +445,7 @@ private static bool IsParameterRefEqual(in ParameterRef parameterRef, ReadOnlySp
/// </summary>
// AggressiveInlining used since this method is only called from two locations and is on a hot path.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetKey(ReadOnlySpan<byte> name)
internal static ulong GetKey(ReadOnlySpan<byte> name)
{
ulong key;
......@@ -495,7 +494,7 @@ public static ulong GetKey(ReadOnlySpan<byte> name)
return key;
}
public void UpdateSortedPropertyCache(ref ReadStackFrame frame)
internal void UpdateSortedPropertyCache(ref ReadStackFrame frame)
{
Debug.Assert(frame.PropertyRefCache != null);
......@@ -531,7 +530,7 @@ public void UpdateSortedPropertyCache(ref ReadStackFrame frame)
frame.PropertyRefCache = null;
}
public void UpdateSortedParameterCache(ref ReadStackFrame frame)
internal void UpdateSortedParameterCache(ref ReadStackFrame frame)
{
Debug.Assert(frame.CtorArgumentState!.ParameterRefCache != null);
......@@ -566,5 +565,35 @@ public void UpdateSortedParameterCache(ref ReadStackFrame frame)
frame.CtorArgumentState.ParameterRefCache = null;
}
internal void InitializeSerializePropCache()
{
Debug.Assert(PropInitFunc != null);
Debug.Assert(Options._context != null);
PropertyCacheArray = PropInitFunc(Options._context);
}
internal void InitializeDeserializePropCache()
{
if (PropertyCacheArray == null)
{
InitializeSerializePropCache();
}
PropertyCache = new Dictionary<string, JsonPropertyInfo>(Options.PropertyNameCaseInsensitive
? StringComparer.OrdinalIgnoreCase
: StringComparer.Ordinal);
for (int i = 0; i < PropertyCacheArray!.Length; i++)
{
JsonPropertyInfo jsonPropertyInfo = PropertyCacheArray[i];
if (!JsonHelpers.TryAdd(PropertyCache!, jsonPropertyInfo.NameAsString, jsonPropertyInfo))
{
ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo);
}
}
}
}
}
......@@ -6,91 +6,103 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
namespace System.Text.Json
namespace System.Text.Json.Serialization.Metadata
{
[DebuggerDisplay("ClassType.{ClassType}, {Type.Name}")]
internal sealed partial class JsonClassInfo
/// <summary>
/// Provides JSON serialization-related metadata about a type.
/// </summary>
[DebuggerDisplay("ConverterStrategy.{ConverterStrategy}, {Type.Name}")]
public partial class JsonTypeInfo
{
public delegate object? ConstructorDelegate();
internal delegate object? ConstructorDelegate();
public delegate T ParameterizedConstructorDelegate<T>(object[] arguments);
internal delegate T ParameterizedConstructorDelegate<T>(object[] arguments);
public delegate T ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);
internal delegate T ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);
public ConstructorDelegate? CreateObject { get; private set; }
internal ConstructorDelegate? CreateObject { get; set; }
public object? CreateObjectWithArgs { get; set; }
internal object? CreateObjectWithArgs { get; set; }
// Add method delegate for non-generic Stack and Queue; and types that derive from them.
public object? AddMethodDelegate { get; set; }
internal object? AddMethodDelegate { get; set; }
public ClassType ClassType { get; private set; }
internal JsonPropertyInfo? DataExtensionProperty { get; private set; }
public JsonPropertyInfo? DataExtensionProperty { get; private set; }
// If enumerable or dictionary, the JsonClassInfo for the element type.
private JsonClassInfo? _elementClassInfo;
// If enumerable or dictionary, the JsonTypeInfo for the element type.
private JsonTypeInfo? _elementTypeInfo;
/// <summary>
/// Return the JsonClassInfo for the element type, or null if the type is not an enumerable or dictionary.
/// Return the JsonTypeInfo for the element type, or null if the type is not an enumerable or dictionary.
/// </summary>
/// <remarks>
/// This should not be called during warm-up (initial creation of JsonClassInfos) to avoid recursive behavior
/// This should not be called during warm-up (initial creation of JsonTypeInfos) to avoid recursive behavior
/// which could result in a StackOverflowException.
/// </remarks>
public JsonClassInfo? ElementClassInfo
internal JsonTypeInfo? ElementTypeInfo
{
get
{
if (_elementClassInfo == null && ElementType != null)
if (_elementTypeInfo == null && ElementType != null)
{
Debug.Assert(ClassType == ClassType.Enumerable ||
ClassType == ClassType.Dictionary);
Debug.Assert(PropertyInfoForTypeInfo.ConverterStrategy == ConverterStrategy.Enumerable ||
PropertyInfoForTypeInfo.ConverterStrategy == ConverterStrategy.Dictionary);
_elementClassInfo = Options.GetOrAddClass(ElementType);
_elementTypeInfo = Options.GetOrAddClass(ElementType);
}
return _elementClassInfo;
return _elementTypeInfo;
}
set
{
// Set by JsonMetadataServices.
Debug.Assert(_elementTypeInfo == null);
_elementTypeInfo = value;
}
}
public Type? ElementType { get; set; }
internal Type? ElementType { get; set; }
// If dictionary, the JsonClassInfo for the key type.
private JsonClassInfo? _keyClassInfo;
// If dictionary, the JsonTypeInfo for the key type.
private JsonTypeInfo? _keyTypeInfo;
/// <summary>
/// Return the JsonClassInfo for the key type, or null if the type is not a dictionary.
/// Return the JsonTypeInfo for the key type, or null if the type is not a dictionary.
/// </summary>
/// <remarks>
/// This should not be called during warm-up (initial creation of JsonClassInfos) to avoid recursive behavior
/// This should not be called during warm-up (initial creation of JsonTypeInfos) to avoid recursive behavior
/// which could result in a StackOverflowException.
/// </remarks>
public JsonClassInfo? KeyClassInfo
internal JsonTypeInfo? KeyTypeInfo
{
get
{
if (_keyClassInfo == null && KeyType != null)
if (_keyTypeInfo == null && KeyType != null)
{
Debug.Assert(ClassType == ClassType.Dictionary);
Debug.Assert(PropertyInfoForTypeInfo.ConverterStrategy == ConverterStrategy.Dictionary);
_keyClassInfo = Options.GetOrAddClass(KeyType);
_keyTypeInfo = Options.GetOrAddClass(KeyType);
}
return _keyClassInfo;
return _keyTypeInfo;
}
set
{
// Set by JsonMetadataServices.
Debug.Assert(_keyTypeInfo == null);
_keyTypeInfo = value;
}
}
public Type? KeyType { get; set; }
internal Type? KeyType { get; set; }
public JsonSerializerOptions Options { get; private set; }
internal JsonSerializerOptions Options { get; set; }
public Type Type { get; private set; }
internal Type Type { get; private set; }
/// <summary>
/// The JsonPropertyInfo for this JsonClassInfo. It is used to obtain the converter for the ClassInfo.
/// The JsonPropertyInfo for this JsonTypeInfo. It is used to obtain the converter for the TypeInfo.
/// </summary>
/// <remarks>
/// The returned JsonPropertyInfo does not represent a real property; instead it represents either:
......@@ -99,19 +111,20 @@ internal sealed partial class JsonClassInfo
/// a property type (if pushed to a new stack frame),
/// or the root type passed into the root serialization APIs.
/// For example, for a property returning <see cref="Collections.Generic.List{T}"/> where T is a string,
/// a JsonClassInfo will be created with .Type=typeof(string) and .PropertyInfoForClassInfo=JsonPropertyInfo{string}.
/// Without this property, a "Converter" property would need to be added to JsonClassInfo and there would be several more
/// a JsonTypeInfo will be created with .Type=typeof(string) and .PropertyInfoForTypeInfo=JsonPropertyInfo{string}.
/// Without this property, a "Converter" property would need to be added to JsonTypeInfo and there would be several more
/// `if` statements to obtain the converter from either the actual JsonPropertyInfo (for a real property) or from the
/// ClassInfo (for the cases mentioned above). In addition, methods that have a JsonPropertyInfo argument would also likely
/// need to add an argument for JsonClassInfo.
/// TypeInfo (for the cases mentioned above). In addition, methods that have a JsonPropertyInfo argument would also likely
/// need to add an argument for JsonTypeInfo.
/// </remarks>
public JsonPropertyInfo PropertyInfoForClassInfo { get; private set; }
internal JsonPropertyInfo PropertyInfoForTypeInfo { get; set; }
private GenericMethodHolder? _genericMethods;
/// <summary>
/// Returns a helper class used when generic methods need to be invoked on Type.
/// </summary>
public GenericMethodHolder GenericMethods
internal GenericMethodHolder GenericMethods
{
get
{
......@@ -125,26 +138,47 @@ public GenericMethodHolder GenericMethods
}
}
public JsonClassInfo(Type type, JsonSerializerOptions options)
internal JsonNumberHandling? NumberHandling { get; set; }
internal JsonTypeInfo()
{
Debug.Assert(false, "This constructor should not be called.");
}
internal JsonTypeInfo(Type type, JsonSerializerOptions options, ConverterStrategy converterStrategy)
{
// Options setting for object class types is deferred till initialization.
if (converterStrategy != ConverterStrategy.Object && options == null)
{
throw new ArgumentNullException(nameof(options));
}
Options = options!;
Type = type;
// Setting this option is deferred to the initialization methods of the various metadada info types.
PropertyInfoForTypeInfo = null!;
}
internal JsonTypeInfo(Type type, JsonSerializerOptions options)
{
Type = type;
Options = options;
JsonConverter converter = GetConverter(
Type,
parentClassType: null, // A ClassInfo never has a "parent" class.
memberInfo: null, // A ClassInfo never has a "parent" property.
parentClassType: null, // A TypeInfo never has a "parent" class.
memberInfo: null, // A TypeInfo never has a "parent" property.
out Type runtimeType,
Options);
ClassType = converter.ClassType;
JsonNumberHandling? typeNumberHandling = GetNumberHandlingForType(Type);
PropertyInfoForClassInfo = CreatePropertyInfoForClassInfo(Type, runtimeType, converter, Options);
PropertyInfoForTypeInfo = CreatePropertyInfoForTypeInfo(Type, runtimeType, converter, typeNumberHandling, Options);
switch (ClassType)
switch (PropertyInfoForTypeInfo.ConverterStrategy)
{
case ClassType.Object:
case ConverterStrategy.Object:
{
CreateObject = Options.MemberAccessorStrategy.CreateConstructor(type);
Dictionary<string, JsonPropertyInfo> cache = new Dictionary<string, JsonPropertyInfo>(
......@@ -235,7 +269,7 @@ public JsonClassInfo(Type type, JsonSerializerOptions options)
// Copy the dictionary cache to the array cache.
cache.Values.CopyTo(cacheArray, 0);
// These are not accessed by other threads until the current JsonClassInfo instance
// These are not accessed by other threads until the current JsonTypeInfo instance
// is finished initializing and added to the cache on JsonSerializerOptions.
PropertyCache = cache;
PropertyCacheArray = cacheArray;
......@@ -248,32 +282,31 @@ public JsonClassInfo(Type type, JsonSerializerOptions options)
}
}
break;
case ClassType.Enumerable:
case ConverterStrategy.Enumerable:
{
ElementType = converter.ElementType;
CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType);
}
break;
case ClassType.Dictionary:
case ConverterStrategy.Dictionary:
{
KeyType = converter.KeyType;
ElementType = converter.ElementType;
CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType);
}
break;
case ClassType.Value:
case ClassType.NewValue:
case ConverterStrategy.Value:
{
CreateObject = Options.MemberAccessorStrategy.CreateConstructor(type);
}
break;
case ClassType.None:
case ConverterStrategy.None:
{
ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(type);
}
break;
default:
Debug.Fail($"Unexpected class type: {ClassType}");
Debug.Fail($"Unexpected class type: {PropertyInfoForTypeInfo.ConverterStrategy}");
throw new InvalidOperationException();
}
}
......@@ -461,7 +494,7 @@ private static bool PropertyIsVirtual(PropertyInfo? propertyInfo)
return propertyInfo != null && (propertyInfo.GetMethod?.IsVirtual == true || propertyInfo.SetMethod?.IsVirtual == true);
}
public bool DetermineExtensionDataProperty(Dictionary<string, JsonPropertyInfo> cache)
private bool DetermineExtensionDataProperty(Dictionary<string, JsonPropertyInfo> cache)
{
JsonPropertyInfo? jsonPropertyInfo = GetPropertyWithUniqueAttribute(Type, typeof(JsonExtensionDataAttribute), cache);
if (jsonPropertyInfo != null)
......@@ -535,7 +568,7 @@ public bool DetermineExtensionDataProperty(Dictionary<string, JsonPropertyInfo>
// - runtime type,
// - element type (if the type is a collection),
// - the converter (either native or custom), if one exists.
public static JsonConverter GetConverter(
private static JsonConverter GetConverter(
Type type,
Type? parentClassType,
MemberInfo? memberInfo,
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text.Json.Serialization.Converters;
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Creates and initializes serialization metadata for a type.
/// </summary>
/// <typeparam name="T"></typeparam>
internal sealed class JsonTypeInfoInternal<T> : JsonTypeInfo<T>
{
/// <summary>
/// Creates serialization metadata for a <see cref="ConverterStrategy.Object"/>.
/// </summary>
public JsonTypeInfoInternal() : base(typeof(T), null!, ConverterStrategy.Object)
{
}
/// <summary>
/// Creates serialization metadata for a <see cref="ConverterStrategy.Value"/>.
/// </summary>
public JsonTypeInfoInternal(JsonSerializerOptions options)
: base (typeof(T), options, ConverterStrategy.Value)
{
}
/// <summary>
/// Creates serialization metadata for a <see cref="ConverterStrategy.Enumerable"/>.
/// </summary>
public JsonTypeInfoInternal(
JsonSerializerOptions options,
Func<T>? createObjectFunc,
JsonConverter<T> converter,
JsonTypeInfo elementInfo,
JsonNumberHandling numberHandling) : base(typeof(T), options, ConverterStrategy.Enumerable)
{
ElementType = converter.ElementType;
ElementTypeInfo = elementInfo ?? throw new ArgumentNullException(nameof(elementInfo));
NumberHandling = numberHandling;
PropertyInfoForTypeInfo = JsonPropertyInfo<T>.CreateForSourceGenTypeInfo(Type, runtimeTypeInfo: this, converter, Options);
SetCreateObjectFunc(createObjectFunc);
}
/// <summary>
/// Creates serialization metadata for a <see cref="ConverterStrategy.Dictionary"/>.
/// </summary>
public JsonTypeInfoInternal(
JsonSerializerOptions options,
Func<T>? createObjectFunc,
JsonConverter<T> converter,
JsonTypeInfo keyInfo,
JsonTypeInfo valueInfo,
JsonNumberHandling numberHandling) : base(typeof(T), options, ConverterStrategy.Dictionary)
{
KeyType = converter.KeyType;
KeyTypeInfo = keyInfo ?? throw new ArgumentNullException(nameof(keyInfo)); ;
ElementType = converter.ElementType;
ElementTypeInfo = valueInfo ?? throw new ArgumentNullException(nameof(valueInfo));
NumberHandling = numberHandling;
PropertyInfoForTypeInfo = JsonPropertyInfo<T>.CreateForSourceGenTypeInfo(Type, runtimeTypeInfo: this, converter, Options);
SetCreateObjectFunc(createObjectFunc);
}
/// <summary>
/// Initializes serialization metadata for a <see cref="ConverterStrategy.Object"/>.
/// </summary>
public void InitializeAsObject(
JsonSerializerOptions options,
Func<T>? createObjectFunc,
Func<JsonSerializerContext, JsonPropertyInfo[]> propInitFunc,
JsonNumberHandling numberHandling)
{
Options = options;
#pragma warning disable CS8714
// The type cannot be used as type parameter in the generic type or method.
// Nullability of type argument doesn't match 'notnull' constraint.
JsonConverter converter = new ObjectSourceGenConverter<T>();
#pragma warning restore CS8714
PropertyInfoForTypeInfo = JsonPropertyInfo<T>.CreateForSourceGenTypeInfo(Type, runtimeTypeInfo: this, converter, options);
NumberHandling = numberHandling;
PropInitFunc = propInitFunc;
SetCreateObjectFunc(createObjectFunc);
}
private void SetCreateObjectFunc(Func<T>? createObjectFunc)
{
if (createObjectFunc != null)
{
CreateObject = () => createObjectFunc();
}
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
using System.Diagnostics;
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Provides JSON serialization-related metadata about a type.
/// </summary>
/// <typeparam name="T">The generic definition of the type.</typeparam>
[EditorBrowsable(EditorBrowsableState.Never)]
public abstract class JsonTypeInfo<T> : JsonTypeInfo
{
internal JsonTypeInfo(Type type, JsonSerializerOptions options, ConverterStrategy converterStrategy) :
base(type, options, converterStrategy)
{ }
internal JsonTypeInfo()
{
Debug.Assert(false, "This constructor should not be called.");
}
}
}
......@@ -4,15 +4,15 @@
using System.Collections.Generic;
using System.Reflection;
namespace System.Text.Json
namespace System.Text.Json.Serialization.Metadata
{
internal abstract class MemberAccessor
{
public abstract JsonClassInfo.ConstructorDelegate? CreateConstructor(Type classType);
public abstract JsonTypeInfo.ConstructorDelegate? CreateConstructor(Type classType);
public abstract JsonClassInfo.ParameterizedConstructorDelegate<T>? CreateParameterizedConstructor<T>(ConstructorInfo constructor);
public abstract JsonTypeInfo.ParameterizedConstructorDelegate<T>? CreateParameterizedConstructor<T>(ConstructorInfo constructor);
public abstract JsonClassInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>?
public abstract JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>?
CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor);
public abstract Action<TCollection, object?> CreateAddMethodDelegate<TCollection>();
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Text.Json
namespace System.Text.Json.Serialization.Metadata
{
internal readonly struct ParameterRef
{
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Text.Json
namespace System.Text.Json.Serialization.Metadata
{
internal readonly struct PropertyRef
{
......
......@@ -8,11 +8,11 @@
using System.Reflection;
using System.Reflection.Emit;
namespace System.Text.Json.Serialization
namespace System.Text.Json.Serialization.Metadata
{
internal sealed class ReflectionEmitMemberAccessor : MemberAccessor
{
public override JsonClassInfo.ConstructorDelegate? CreateConstructor(Type type)
public override JsonTypeInfo.ConstructorDelegate? CreateConstructor(Type type)
{
Debug.Assert(type != null);
ConstructorInfo? realMethod = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, binder: null, Type.EmptyTypes, modifiers: null);
......@@ -29,7 +29,7 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor
var dynamicMethod = new DynamicMethod(
ConstructorInfo.ConstructorName,
JsonClassInfo.ObjectType,
JsonTypeInfo.ObjectType,
Type.EmptyTypes,
typeof(ReflectionEmitMemberAccessor).Module,
skipVisibility: true);
......@@ -52,11 +52,11 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor
generator.Emit(OpCodes.Ret);
return (JsonClassInfo.ConstructorDelegate)dynamicMethod.CreateDelegate(typeof(JsonClassInfo.ConstructorDelegate));
return (JsonTypeInfo.ConstructorDelegate)dynamicMethod.CreateDelegate(typeof(JsonTypeInfo.ConstructorDelegate));
}
public override JsonClassInfo.ParameterizedConstructorDelegate<T>? CreateParameterizedConstructor<T>(ConstructorInfo constructor) =>
CreateDelegate<JsonClassInfo.ParameterizedConstructorDelegate<T>>(CreateParameterizedConstructor(constructor));
public override JsonTypeInfo.ParameterizedConstructorDelegate<T>? CreateParameterizedConstructor<T>(ConstructorInfo constructor) =>
CreateDelegate<JsonTypeInfo.ParameterizedConstructorDelegate<T>>(CreateParameterizedConstructor(constructor));
private static DynamicMethod? CreateParameterizedConstructor(ConstructorInfo constructor)
{
......@@ -99,9 +99,9 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor
return dynamicMethod;
}
public override JsonClassInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>?
public override JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>?
CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor) =>
CreateDelegate<JsonClassInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>>(
CreateDelegate<JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>>(
CreateParameterizedConstructor(constructor, typeof(TArg0), typeof(TArg1), typeof(TArg2), typeof(TArg3)));
private static DynamicMethod? CreateParameterizedConstructor(ConstructorInfo constructor, Type parameterType1, Type parameterType2, Type parameterType3, Type parameterType4)
......@@ -156,7 +156,7 @@ private static DynamicMethod CreateAddMethodDelegate(Type collectionType)
var dynamicMethod = new DynamicMethod(
realMethod.Name,
typeof(void),
new[] { collectionType, JsonClassInfo.ObjectType },
new[] { collectionType, JsonTypeInfo.ObjectType },
typeof(ReflectionEmitMemberAccessor).Module,
skipVisibility: true);
......@@ -363,7 +363,7 @@ private static DynamicMethod CreateFieldSetter(FieldInfo fieldInfo, Type runtime
new DynamicMethod(
memberName + "Getter",
memberType,
new[] { JsonClassInfo.ObjectType },
new[] { JsonTypeInfo.ObjectType },
typeof(ReflectionEmitMemberAccessor).Module,
skipVisibility: true);
......@@ -371,7 +371,7 @@ private static DynamicMethod CreateFieldSetter(FieldInfo fieldInfo, Type runtime
new DynamicMethod(
memberName + "Setter",
typeof(void),
new[] { JsonClassInfo.ObjectType, memberType },
new[] { JsonTypeInfo.ObjectType, memberType },
typeof(ReflectionEmitMemberAccessor).Module,
skipVisibility: true);
......
......@@ -5,11 +5,11 @@
using System.Diagnostics;
using System.Reflection;
namespace System.Text.Json.Serialization
namespace System.Text.Json.Serialization.Metadata
{
internal sealed class ReflectionMemberAccessor : MemberAccessor
{
public override JsonClassInfo.ConstructorDelegate? CreateConstructor(Type type)
public override JsonTypeInfo.ConstructorDelegate? CreateConstructor(Type type)
{
Debug.Assert(type != null);
ConstructorInfo? realMethod = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, binder: null, Type.EmptyTypes, modifiers: null);
......@@ -27,7 +27,7 @@ internal sealed class ReflectionMemberAccessor : MemberAccessor
return () => Activator.CreateInstance(type, nonPublic: false);
}
public override JsonClassInfo.ParameterizedConstructorDelegate<T>? CreateParameterizedConstructor<T>(ConstructorInfo constructor)
public override JsonTypeInfo.ParameterizedConstructorDelegate<T>? CreateParameterizedConstructor<T>(ConstructorInfo constructor)
{
Type type = typeof(T);
......@@ -66,7 +66,7 @@ internal sealed class ReflectionMemberAccessor : MemberAccessor
};
}
public override JsonClassInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>?
public override JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>?
CreateParameterizedConstructor<T, TArg0, TArg1, TArg2, TArg3>(ConstructorInfo constructor)
{
Type type = typeof(T);
......@@ -111,7 +111,7 @@ internal sealed class ReflectionMemberAccessor : MemberAccessor
public override Action<TCollection, object?> CreateAddMethodDelegate<TCollection>()
{
Type collectionType = typeof(TCollection);
Type elementType = JsonClassInfo.ObjectType;
Type elementType = JsonTypeInfo.ObjectType;
// We verified this won't be null when we created the converter for the collection type.
MethodInfo addMethod = (collectionType.GetMethod("Push") ?? collectionType.GetMethod("Enqueue"))!;
......
......@@ -6,10 +6,11 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json
{
[DebuggerDisplay("Path:{JsonPath()} Current: ClassType.{Current.JsonClassInfo.ClassType}, {Current.JsonClassInfo.Type.Name}")]
[DebuggerDisplay("Path:{JsonPath()} Current: ConverterStrategy.{Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy}, {Current.JsonTypeInfo.Type.Name}")]
internal struct ReadStack
{
internal static readonly char[] SpecialCharacters = { '.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t', '\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029' };
......@@ -81,11 +82,11 @@ private void AddCurrent()
public void Initialize(Type type, JsonSerializerOptions options, bool supportContinuation)
{
JsonClassInfo jsonClassInfo = options.GetOrAddClassForRootType(type);
Current.JsonClassInfo = jsonClassInfo;
JsonTypeInfo jsonTypeInfo = options.GetOrAddClassForRootType(type);
Current.JsonTypeInfo = jsonTypeInfo;
// The initial JsonPropertyInfo will be used to obtain the converter.
Current.JsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo;
Current.JsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo;
Current.NumberHandling = Current.JsonPropertyInfo.NumberHandling;
......@@ -110,36 +111,37 @@ public void Push()
}
else
{
JsonClassInfo jsonClassInfo;
JsonTypeInfo jsonTypeInfo;
JsonNumberHandling? numberHandling = Current.NumberHandling;
ConverterStrategy converterStrategy = Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy;
if (Current.JsonClassInfo.ClassType == ClassType.Object)
if (converterStrategy == ConverterStrategy.Object)
{
if (Current.JsonPropertyInfo != null)
{
jsonClassInfo = Current.JsonPropertyInfo.RuntimeClassInfo;
jsonTypeInfo = Current.JsonPropertyInfo.RuntimeTypeInfo;
}
else
{
jsonClassInfo = Current.CtorArgumentState!.JsonParameterInfo!.RuntimeClassInfo;
jsonTypeInfo = Current.CtorArgumentState!.JsonParameterInfo!.RuntimeTypeInfo;
}
}
else if (((ClassType.Value | ClassType.NewValue) & Current.JsonClassInfo.ClassType) != 0)
else if (converterStrategy == ConverterStrategy.Value)
{
// Although ClassType.Value doesn't push, a custom custom converter may re-enter serialization.
jsonClassInfo = Current.JsonPropertyInfo!.RuntimeClassInfo;
// Although ConverterStrategy.Value doesn't push, a custom custom converter may re-enter serialization.
jsonTypeInfo = Current.JsonPropertyInfo!.RuntimeTypeInfo;
}
else
{
Debug.Assert(((ClassType.Enumerable | ClassType.Dictionary) & Current.JsonClassInfo.ClassType) != 0);
jsonClassInfo = Current.JsonClassInfo.ElementClassInfo!;
Debug.Assert(((ConverterStrategy.Enumerable | ConverterStrategy.Dictionary) & converterStrategy) != 0);
jsonTypeInfo = Current.JsonTypeInfo.ElementTypeInfo!;
}
AddCurrent();
Current.Reset();
Current.JsonClassInfo = jsonClassInfo;
Current.JsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo;
Current.JsonTypeInfo = jsonTypeInfo;
Current.JsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo;
// Allow number handling on property to win over handling on type.
Current.NumberHandling = numberHandling ?? Current.JsonPropertyInfo.NumberHandling;
}
......@@ -248,7 +250,7 @@ static void AppendStackFrame(StringBuilder sb, in ReadStackFrame frame)
string? propertyName = GetPropertyName(frame);
AppendPropertyName(sb, propertyName);
if (frame.JsonClassInfo != null && frame.IsProcessingEnumerable())
if (frame.JsonTypeInfo != null && frame.IsProcessingEnumerable())
{
IEnumerable? enumerable = (IEnumerable?)frame.ReturnValue;
if (enumerable == null)
......@@ -337,7 +339,7 @@ static void AppendPropertyName(StringBuilder sb, string? propertyName)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetConstructorArgumentState()
{
if (Current.JsonClassInfo.ParameterCount > 0)
if (Current.JsonTypeInfo.ParameterCount > 0)
{
// A zero index indicates a new stack frame.
if (Current.CtorArgumentStateIndex == 0)
......
......@@ -4,10 +4,11 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json
{
[DebuggerDisplay("ClassType.{JsonClassInfo.ClassType}, {JsonClassInfo.Type.Name}")]
[DebuggerDisplay("ConverterStrategy.{JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy}, {JsonTypeInfo.Type.Name}")]
internal struct ReadStackFrame
{
// Current property values.
......@@ -30,7 +31,7 @@ internal struct ReadStackFrame
// Current object (POCO or IEnumerable).
public object? ReturnValue; // The current return value used for re-entry.
public JsonClassInfo JsonClassInfo;
public JsonTypeInfo JsonTypeInfo;
public StackFrameObjectState ObjectState; // State tracking the current object.
// Validate EndObject token on array with preserve semantics.
......@@ -78,7 +79,7 @@ public void EndElement()
/// </summary>
public bool IsProcessingDictionary()
{
return (JsonClassInfo.ClassType & ClassType.Dictionary) != 0;
return (JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy & ConverterStrategy.Dictionary) != 0;
}
/// <summary>
......@@ -86,14 +87,14 @@ public bool IsProcessingDictionary()
/// </summary>
public bool IsProcessingEnumerable()
{
return (JsonClassInfo.ClassType & ClassType.Enumerable) != 0;
return (JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy & ConverterStrategy.Enumerable) != 0;
}
public void Reset()
{
CtorArgumentStateIndex = 0;
CtorArgumentState = null;
JsonClassInfo = null!;
JsonTypeInfo = null!;
ObjectState = StackFrameObjectState.None;
OriginalDepth = 0;
OriginalTokenType = JsonTokenType.None;
......
......@@ -6,12 +6,13 @@
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;
namespace System.Text.Json
{
[DebuggerDisplay("Path:{PropertyPath()} Current: ClassType.{Current.JsonClassInfo.ClassType}, {Current.JsonClassInfo.Type.Name}")]
[DebuggerDisplay("Path:{PropertyPath()} Current: ConverterStrategy.{ConverterStrategy.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy}, {Current.JsonTypeInfo.Type.Name}")]
internal struct WriteStack
{
/// <summary>
......@@ -83,14 +84,14 @@ private void AddCurrent()
}
/// <summary>
/// Initialize the state without delayed initialization of the JsonClassInfo.
/// Initialize the state without delayed initialization of the JsonTypeInfo.
/// </summary>
public JsonConverter Initialize(Type type, JsonSerializerOptions options, bool supportContinuation)
{
JsonClassInfo jsonClassInfo = options.GetOrAddClassForRootType(type);
JsonTypeInfo jsonTypeInfo = options.GetOrAddClassForRootType(type);
Current.JsonClassInfo = jsonClassInfo;
Current.DeclaredJsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo;
Current.JsonTypeInfo = jsonTypeInfo;
Current.DeclaredJsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo;
Current.NumberHandling = Current.DeclaredJsonPropertyInfo.NumberHandling;
if (options.ReferenceHandlingStrategy != ReferenceHandlingStrategy.None)
......@@ -101,7 +102,7 @@ public JsonConverter Initialize(Type type, JsonSerializerOptions options, bool s
SupportContinuation = supportContinuation;
return jsonClassInfo.PropertyInfoForClassInfo.ConverterBase;
return jsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase;
}
public void Push()
......@@ -115,14 +116,14 @@ public void Push()
}
else
{
JsonClassInfo jsonClassInfo = Current.GetPolymorphicJsonPropertyInfo().RuntimeClassInfo;
JsonTypeInfo jsonTypeInfo = Current.GetPolymorphicJsonPropertyInfo().RuntimeTypeInfo;
JsonNumberHandling? numberHandling = Current.NumberHandling;
AddCurrent();
Current.Reset();
Current.JsonClassInfo = jsonClassInfo;
Current.DeclaredJsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo;
Current.JsonTypeInfo = jsonTypeInfo;
Current.DeclaredJsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo;
// Allow number handling on property to win over handling on type.
Current.NumberHandling = numberHandling ?? Current.DeclaredJsonPropertyInfo.NumberHandling;
}
......
......@@ -3,12 +3,12 @@
using System.Collections;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json
{
[DebuggerDisplay("ClassType.{JsonClassInfo.ClassType}, {JsonClassInfo.Type.Name}")]
[DebuggerDisplay("ConverterStrategy.{JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy}, {JsonTypeInfo.Type.Name}")]
internal struct WriteStackFrame
{
/// <summary>
......@@ -31,8 +31,8 @@ internal struct WriteStackFrame
/// The original JsonPropertyInfo that is not changed. It contains all properties.
/// </summary>
/// <remarks>
/// For objects, it is either the actual (real) JsonPropertyInfo or the <see cref="JsonClassInfo.PropertyInfoForClassInfo"/> for the class.
/// For collections, it is the <see cref="JsonClassInfo.PropertyInfoForClassInfo"/> for the class and current element.
/// For objects, it is either the actual (real) JsonPropertyInfo or the <see cref="JsonTypeInfo.PropertyInfoForTypeInfo"/> for the class.
/// For collections, it is the <see cref="JsonTypeInfo.PropertyInfoForTypeInfo"/> for the class and current element.
/// </remarks>
public JsonPropertyInfo? DeclaredJsonPropertyInfo;
......@@ -44,7 +44,7 @@ internal struct WriteStackFrame
/// <summary>
/// The class (POCO or IEnumerable) that is being populated.
/// </summary>
public JsonClassInfo JsonClassInfo;
public JsonTypeInfo JsonTypeInfo;
/// <summary>
/// Validation state for a class.
......@@ -72,11 +72,11 @@ internal struct WriteStackFrame
public MetadataPropertyName MetadataPropertyName;
/// <summary>
/// The run-time JsonPropertyInfo that contains the ClassInfo and ConverterBase for polymorphic scenarios.
/// The run-time JsonPropertyInfo that contains the TypeInfo and ConverterBase for polymorphic scenarios.
/// </summary>
/// <remarks>
/// For objects, it is the <see cref="JsonClassInfo.PropertyInfoForClassInfo"/> for the class and current property.
/// For collections, it is the <see cref="JsonClassInfo.PropertyInfoForClassInfo"/> for the class and current element.
/// For objects, it is the <see cref="JsonTypeInfo.PropertyInfoForTypeInfo"/> for the class and current property.
/// For collections, it is the <see cref="JsonTypeInfo.PropertyInfoForTypeInfo"/> for the class and current element.
/// </remarks>
private JsonPropertyInfo? PolymorphicJsonPropertyInfo;
......@@ -98,7 +98,7 @@ public void EndProperty()
/// <summary>
/// Return the property that contains the correct polymorphic properties including
/// the ClassType and ConverterBase.
/// the ConverterStrategy and ConverterBase.
/// </summary>
public JsonPropertyInfo GetPolymorphicJsonPropertyInfo()
{
......@@ -114,8 +114,8 @@ public JsonConverter InitializeReEntry(Type type, JsonSerializerOptions options)
// if the current element is the same type as the previous element.
if (PolymorphicJsonPropertyInfo?.RuntimePropertyType != type)
{
JsonClassInfo classInfo = options.GetOrAddClass(type);
PolymorphicJsonPropertyInfo = classInfo.PropertyInfoForClassInfo;
JsonTypeInfo typeInfo = options.GetOrAddClass(type);
PolymorphicJsonPropertyInfo = typeInfo.PropertyInfoForTypeInfo;
}
return PolymorphicJsonPropertyInfo.ConverterBase;
......@@ -128,7 +128,7 @@ public void Reset()
AsyncEnumerator = null;
AsyncEnumeratorIsPendingCompletion = false;
IgnoreDictionaryKeyPolicy = false;
JsonClassInfo = null!;
JsonTypeInfo = null!;
OriginalDepth = 0;
ProcessedStartToken = false;
ProcessedEndToken = false;
......
......@@ -7,6 +7,7 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json
{
......@@ -163,9 +164,13 @@ public static void ThrowInvalidOperationException_SerializationConverterOnAttrib
[DoesNotReturn]
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowInvalidOperationException_SerializerOptionsImmutable()
public static void ThrowInvalidOperationException_SerializerOptionsImmutable(JsonSerializerContext? context)
{
throw new InvalidOperationException(SR.SerializerOptionsImmutable);
string message = context == null
? SR.SerializerOptionsImmutable
: SR.SerializerContextOptionsImmutable;
throw new InvalidOperationException(message);
}
[DoesNotReturn]
......@@ -246,10 +251,9 @@ public static void ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(
[DoesNotReturn]
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowInvalidOperationException_IgnoreConditionOnValueTypeInvalid(JsonPropertyInfo jsonPropertyInfo)
public static void ThrowInvalidOperationException_IgnoreConditionOnValueTypeInvalid(string clrPropertyName, Type propertyDeclaringType)
{
MemberInfo memberInfo = jsonPropertyInfo.MemberInfo!;
throw new InvalidOperationException(SR.Format(SR.IgnoreConditionOnValueTypeInvalid, memberInfo.Name, memberInfo.DeclaringType));
throw new InvalidOperationException(SR.Format(SR.IgnoreConditionOnValueTypeInvalid, clrPropertyName, propertyDeclaringType));
}
[DoesNotReturn]
......@@ -263,11 +267,11 @@ public static void ThrowInvalidOperationException_NumberHandlingOnPropertyInvali
throw new InvalidOperationException(SR.Format(
SR.NumberHandlingConverterMustBeBuiltIn,
jsonPropertyInfo.ConverterBase.GetType(),
jsonPropertyInfo.IsForClassInfo ? jsonPropertyInfo.DeclaredPropertyType : memberInfo!.DeclaringType));
jsonPropertyInfo.IsForTypeInfo ? jsonPropertyInfo.DeclaredPropertyType : memberInfo!.DeclaringType));
}
// This exception is only thrown for object properties.
Debug.Assert(!jsonPropertyInfo.IsForClassInfo && memberInfo != null);
Debug.Assert(!jsonPropertyInfo.IsForTypeInfo && memberInfo != null);
throw new InvalidOperationException(SR.Format(
SR.NumberHandlingOnPropertyTypeMustBeNumberOrCollection,
memberInfo.Name,
......@@ -291,7 +295,7 @@ public static void ThrowInvalidOperationException_ConverterCanConvertNullableRed
state.Current.JsonPropertyName = propertyName.ToArray();
NotSupportedException ex = new NotSupportedException(
SR.Format(SR.ObjectWithParameterizedCtorRefMetadataNotHonored, state.Current.JsonClassInfo.Type));
SR.Format(SR.ObjectWithParameterizedCtorRefMetadataNotHonored, state.Current.JsonTypeInfo.Type));
ThrowNotSupportedException(state, reader, ex);
}
......@@ -350,7 +354,7 @@ public static void AddJsonExceptionInformation(in ReadStack state, in Utf8JsonRe
Type? propertyType = state.Current.JsonPropertyInfo?.RuntimePropertyType;
if (propertyType == null)
{
propertyType = state.Current.JsonClassInfo?.Type;
propertyType = state.Current.JsonTypeInfo?.Type;
}
message = SR.Format(SR.DeserializeUnableToConvertValue, propertyType);
......@@ -439,7 +443,7 @@ public static void ThrowNotSupportedException(in ReadStack state, in Utf8JsonRea
Type? propertyType = state.Current.JsonPropertyInfo?.RuntimePropertyType;
if (propertyType == null)
{
propertyType = state.Current.JsonClassInfo.Type;
propertyType = state.Current.JsonTypeInfo.Type;
}
if (!message.Contains(propertyType.ToString()))
......@@ -471,7 +475,7 @@ public static void ThrowNotSupportedException(in WriteStack state, NotSupportedE
Type? propertyType = state.Current.DeclaredJsonPropertyInfo?.RuntimePropertyType;
if (propertyType == null)
{
propertyType = state.Current.JsonClassInfo.Type;
propertyType = state.Current.JsonTypeInfo.Type;
}
if (!message.Contains(propertyType.ToString()))
......@@ -648,7 +652,7 @@ public static void ThrowInvalidOperationException_MetadataReferenceOfTypeCannotB
ref Utf8JsonReader reader,
ref ReadStack state)
{
if (state.Current.JsonClassInfo.PropertyInfoForClassInfo.ConverterBase.ConstructorIsParameterized)
if (state.Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase.ConstructorIsParameterized)
{
ThrowNotSupportedException_ObjectWithParameterizedCtorRefMetadataNotHonored(propertyName, ref reader, ref state);
}
......@@ -667,5 +671,12 @@ public static void ThrowInvalidOperationException_MetadataReferenceOfTypeCannotB
ThrowJsonException_MetadataInvalidPropertyWithLeadingDollarSign(propertyName, ref state, reader);
}
}
[DoesNotReturn]
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowInvalidOperationException_JsonSerializerOptionsAlreadyBoundToContext()
{
throw new InvalidOperationException(SR.Format(SR.OptionsAlreadyBoundToContext));
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Reflection;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Xunit;
namespace System.Text.Json.Tests.Serialization
{
public static partial class MetadataServicesTests
{
[Fact]
public static void JsonSerializerContextCtor()
{
// Pass no options.
MyJsonContext context = new();
JsonSerializerOptions options = context.Options; // New options instance created and binded at this point.
Assert.NotNull(options);
// Pass options.
options = new JsonSerializerOptions();
context = new MyJsonContext(options); // Provided options are binded at this point.
Assert.Same(options, context.Options);
}
[Fact]
public static void AddContext()
{
JsonSerializerOptions options = new();
options.AddContext<MyJsonContext>();
// Options can be binded only once.
CauseInvalidOperationException(() => options.AddContext<MyJsonContext>());
CauseInvalidOperationException(() => options.AddContext<MyJsonContextThatSetsOptionsInParameterlessCtor>());
}
private static void CauseInvalidOperationException(Action action)
{
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(action);
string exAsStr = ex.ToString();
Assert.Contains("JsonSerializerOptions", exAsStr);
Assert.Contains("JsonSerializerContext", exAsStr);
}
[Fact]
public static void AddContextOverwritesOptionsForFreshContext()
{
// Context binds with options when instantiated with parameterless ctor.
MyJsonContextThatSetsOptionsInParameterlessCtor context = new();
FieldInfo optionsField = typeof(JsonSerializerContext).GetField("_options", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(optionsField);
Assert.NotNull((JsonSerializerOptions)optionsField.GetValue(context));
// Those options are overwritten when context is binded via options.AddContext<TContext>();
JsonSerializerOptions options = new();
options.AddContext<MyJsonContextThatSetsOptionsInParameterlessCtor>(); // No error.
FieldInfo contextField = typeof(JsonSerializerOptions).GetField("_context", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(contextField);
Assert.Same(options, ((JsonSerializerContext)contextField.GetValue(options)).Options);
}
[Fact]
public static void AlreadyBindedOptions()
{
// Bind the options.
JsonSerializerOptions options = new();
options.AddContext<MyJsonContext>();
// Attempt to bind the instance again.
Assert.Throws<InvalidOperationException>(() => new MyJsonContext(options));
}
[Fact]
public static void OptionsImmutableAfterBinding()
{
// Bind via AddContext
JsonSerializerOptions options = new();
options.PropertyNameCaseInsensitive = true;
options.AddContext<MyJsonContext>();
CauseInvalidOperationException(() => options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase);
// Bind via context ctor
options = new JsonSerializerOptions();
MyJsonContext context = new MyJsonContext(options);
Assert.Same(options, context.Options);
CauseInvalidOperationException(() => options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase);
}
private class MyJsonContext : JsonSerializerContext
{
public MyJsonContext() : base(null) { }
public MyJsonContext(JsonSerializerOptions options) : base(options) { }
public override JsonTypeInfo? GetTypeInfo(Type type) => throw new NotImplementedException();
}
private class MyJsonContextThatSetsOptionsInParameterlessCtor : JsonSerializerContext
{
public MyJsonContextThatSetsOptionsInParameterlessCtor() : base(new JsonSerializerOptions()) { }
public override JsonTypeInfo? GetTypeInfo(Type type) => throw new NotImplementedException();
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Drawing;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Text.Json.Serialization.Tests;
using Xunit;
namespace System.Text.Json.Tests.Serialization
{
public static partial class MetadataServicesTests
{
[Fact]
public static void CreatePropertyInfo()
{
JsonSerializerOptions options = new();
// Null options
ArgumentNullException ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreatePropertyInfo<int>(
options: null,
isProperty: true,
declaringType: typeof(Point),
propertyTypeInfo: JsonMetadataServices.CreateValueInfo<int, int>(options, JsonMetadataServices.Int32Converter),
converter: null,
getter: null,
setter: null,
ignoreCondition: default,
numberHandling: default,
propertyName: "MyInt",
jsonPropertyName: default));
Assert.Contains("options", ane.ToString());
// Null declaring type
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreatePropertyInfo<int>(
options: options,
isProperty: true,
declaringType: null,
propertyTypeInfo: JsonMetadataServices.CreateValueInfo<int, int>(options, JsonMetadataServices.Int32Converter),
converter: null,
getter: null,
setter: null,
ignoreCondition: default,
numberHandling: default,
propertyName: "MyInt",
jsonPropertyName: default));
Assert.Contains("declaringType", ane.ToString());
// Null property type info
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreatePropertyInfo<int>(
options: options,
isProperty: true,
declaringType: typeof(Point),
propertyTypeInfo: null,
converter: null,
getter: null,
setter: null,
ignoreCondition: default,
numberHandling: default,
propertyName: "MyInt",
jsonPropertyName: default));
Assert.Contains("propertyTypeInfo", ane.ToString());
// Null property name
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreatePropertyInfo<int>(
options: options,
isProperty: true,
declaringType: typeof(Point),
propertyTypeInfo: JsonMetadataServices.CreateValueInfo<int, int>(options, JsonMetadataServices.Int32Converter),
converter: null,
getter: null,
setter: null,
ignoreCondition: default,
numberHandling: default,
propertyName: null,
jsonPropertyName: default));
Assert.Contains("propertyName", ane.ToString());
// Invalid converter
InvalidOperationException ioe = Assert.Throws<InvalidOperationException>(() => JsonMetadataServices.CreatePropertyInfo<MyClass>(
options: options,
isProperty: true,
declaringType: typeof(Point),
// Converter invalid because you'd need to create with JsonMetadataServices.CreatePropertyInfo<MyDerivedClass> instead.
propertyTypeInfo: JsonMetadataServices.CreateValueInfo<MyClass, MyDerivedClass>(options, new DerivedClassConverter()),
converter: null,
getter: null,
setter: null,
ignoreCondition: default,
numberHandling: default,
propertyName: "MyProp",
jsonPropertyName: default));
string ioeAsStr = ioe.ToString();
Assert.Contains("Point.MyProp", ioeAsStr);
Assert.Contains("MyClass", ioeAsStr);
// Source generator tests verify that generated metadata is actually valid.
}
private class MyClass { }
private class MyDerivedClass : MyClass { }
[Fact]
public static void CreateObjectInfo()
{
JsonSerializerOptions options = new();
JsonTypeInfo<MyClass> info = JsonMetadataServices.CreateObjectInfo<MyClass>();
// Null info
ArgumentNullException ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.InitializeObjectInfo<MyClass>(
info: null,
options: options,
createObjectFunc: null,
propInitFunc: (context) => Array.Empty<JsonPropertyInfo>(),
numberHandling: default));
Assert.Contains("info", ane.ToString());
// Info is not for object converter strategy
ArgumentException ae = Assert.Throws<ArgumentException>(() => JsonMetadataServices.InitializeObjectInfo(
info: JsonMetadataServices.CreateValueInfo<MyClass, MyDerivedClass>(options, new DerivedClassConverter()),
options: options,
createObjectFunc: null,
propInitFunc: (context) => Array.Empty<JsonPropertyInfo>(),
numberHandling: default));
Assert.Contains("info", ae.ToString());
// Null options
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.InitializeObjectInfo(
info: info,
options: null,
createObjectFunc: null,
propInitFunc: (context) => Array.Empty<JsonPropertyInfo>(),
numberHandling: default));
Assert.Contains("options", ane.ToString());
// Null prop init func.
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.InitializeObjectInfo(
info: info,
options: options,
createObjectFunc: null,
propInitFunc: null,
numberHandling: default));
Assert.Contains("propInitFunc", ane.ToString());
}
[Fact]
public static void CreateValueInfo()
{
JsonSerializerOptions options = new();
// Use converter that returns same type.
Assert.NotNull(JsonMetadataServices.CreateValueInfo<MyClass, MyClass>(options, new ClassConverter()));
// Use converter that returns derived type.
Assert.NotNull(JsonMetadataServices.CreateValueInfo<MyClass, MyDerivedClass>(options, new DerivedClassConverter()));
// Null options
ArgumentNullException ex = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreateValueInfo<MyClass, MyDerivedClass>(options: null, new DerivedClassConverter()));
Assert.Contains("options", ex.ToString());
}
[Fact]
public static void CreateArrayInfo()
{
JsonSerializerOptions options = new();
// Null options
ArgumentNullException ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreateArrayInfo<int>(
options: null,
elementInfo: JsonMetadataServices.CreateValueInfo<int, int>(options, JsonMetadataServices.Int32Converter),
numberHandling: default));
Assert.Contains("options", ane.ToString());
// Null element info
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreateArrayInfo<int>(
options: options,
elementInfo: null,
numberHandling: default));
Assert.Contains("elementInfo", ane.ToString());
}
[Fact]
public static void CreateListInfo()
{
JsonSerializerOptions options = new();
// Null options
ArgumentNullException ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreateListInfo<List<int>, int>(
options: null,
createObjectFunc: null,
elementInfo: JsonMetadataServices.CreateValueInfo<int, int>(options, JsonMetadataServices.Int32Converter),
numberHandling: default));
Assert.Contains("options", ane.ToString());
// Null element info
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreateListInfo<GenericListWrapper<int>, int>(
options: options,
createObjectFunc: null,
elementInfo: null,
numberHandling: default));
Assert.Contains("elementInfo", ane.ToString());
}
[Fact]
public static void CreateDictionaryInfo()
{
JsonSerializerOptions options = new();
// Null options
ArgumentNullException ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreateDictionaryInfo<Dictionary<string, int>, string, int>(
options: null,
createObjectFunc: null,
keyInfo: JsonMetadataServices.CreateValueInfo<string, string>(options, JsonMetadataServices.StringConverter),
valueInfo: JsonMetadataServices.CreateValueInfo<int, int>(options, JsonMetadataServices.Int32Converter),
numberHandling: default));
Assert.Contains("options", ane.ToString());
// Null key info
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreateDictionaryInfo<StringToGenericDictionaryWrapper<int>, string, int>(
options: options,
createObjectFunc: null,
keyInfo: null,
valueInfo: JsonMetadataServices.CreateValueInfo<int, int>(options, JsonMetadataServices.Int32Converter),
numberHandling: default));
Assert.Contains("valueInfo", ane.ToString());
// Null value info
ane = Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.CreateDictionaryInfo<StringToGenericDictionaryWrapper<int>, string, int>(
options: options,
createObjectFunc: null,
keyInfo: JsonMetadataServices.CreateValueInfo<string, string>(options, JsonMetadataServices.StringConverter),
valueInfo: null,
numberHandling: default));
Assert.Contains("valueInfo", ane.ToString());
}
private class ClassConverter : JsonConverter<MyClass>
{
public override MyClass? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException();
public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options) => throw new NotImplementedException();
}
private class DerivedClassConverter : JsonConverter<MyDerivedClass>
{
public override MyDerivedClass? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException();
public override void Write(Utf8JsonWriter writer, MyDerivedClass value, JsonSerializerOptions options) => throw new NotImplementedException();
}
[Fact]
public static void GetEnumConverter()
{
JsonConverter<DayOfWeek> converter = JsonMetadataServices.GetEnumConverter<DayOfWeek>(new JsonSerializerOptions());
Assert.NotNull(converter);
Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.GetEnumConverter<DayOfWeek>(null!));
}
[Fact]
public static void GetNullableConverter()
{
JsonConverter<DayOfWeek> enumConverter = JsonMetadataServices.GetEnumConverter<DayOfWeek>(new JsonSerializerOptions());
JsonConverter<DayOfWeek?> nullableConverter = JsonMetadataServices.GetNullableConverter(enumConverter);
Assert.NotNull(nullableConverter);
Assert.Throws<ArgumentNullException>(() => JsonMetadataServices.GetNullableConverter<DayOfWeek>(null!));
}
}
}
......@@ -113,6 +113,8 @@
<Compile Include="Serialization\InvalidTypeTests.cs" />
<Compile Include="Serialization\JsonDocumentTests.cs" />
<Compile Include="Serialization\JsonElementTests.cs" />
<Compile Include="Serialization\MetadataServicesTests\MetadataServicesTests.cs" />
<Compile Include="Serialization\MetadataServicesTests\MetadataServicesTests.Options.cs" />
<Compile Include="Serialization\Null.ReadTests.cs" />
<Compile Include="Serialization\Null.WriteTests.cs" />
<Compile Include="Serialization\NullableTests.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册