|
// 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.Json.Reflection;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization.Converters
{
/// <summary>
/// Converter factory for all object-based types (non-enumerable and non-primitive).
/// </summary>
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
internal sealed class ObjectConverterFactory : JsonConverterFactory
{
// Need to toggle this behavior when generating converters for F# struct records.
private readonly bool _useDefaultConstructorInUnannotatedStructs;
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
public ObjectConverterFactory(bool useDefaultConstructorInUnannotatedStructs = true)
{
_useDefaultConstructorInUnannotatedStructs = useDefaultConstructorInUnannotatedStructs;
}
public override bool CanConvert(Type typeToConvert)
{
// This is the last built-in factory converter, so if the IEnumerableConverterFactory doesn't
// support it, then it is not IEnumerable.
Debug.Assert(!typeof(IEnumerable).IsAssignableFrom(typeToConvert));
return true;
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern",
Justification = "The ctor is marked RequiresUnreferencedCode.")]
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
JsonConverter converter;
Type converterType;
bool useDefaultConstructorInUnannotatedStructs = _useDefaultConstructorInUnannotatedStructs && !typeToConvert.IsKeyValuePair();
if (!typeToConvert.TryGetDeserializationConstructor(useDefaultConstructorInUnannotatedStructs, out ConstructorInfo? constructor))
{
ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute<JsonConstructorAttribute>(typeToConvert);
}
ParameterInfo[]? parameters = constructor?.GetParameters();
if (constructor == null || typeToConvert.IsAbstract || parameters!.Length == 0)
{
converterType = typeof(ObjectDefaultConverter<>).MakeGenericType(typeToConvert);
}
else
{
int parameterCount = parameters.Length;
foreach (ParameterInfo parameter in parameters)
{
// Every argument must be of supported type.
JsonTypeInfo.ValidateType(parameter.ParameterType);
}
if (parameterCount <= JsonConstants.UnboxedParameterCountThreshold)
{
Type placeHolderType = JsonTypeInfo.ObjectType;
Type[] typeArguments = new Type[JsonConstants.UnboxedParameterCountThreshold + 1];
typeArguments[0] = typeToConvert;
for (int i = 0; i < JsonConstants.UnboxedParameterCountThreshold; i++)
{
if (i < parameterCount)
{
typeArguments[i + 1] = parameters[i].ParameterType;
}
else
{
// Use placeholder arguments if there are less args than the threshold.
typeArguments[i + 1] = placeHolderType;
}
}
converterType = typeof(SmallObjectWithParameterizedConstructorConverter<,,,,>).MakeGenericType(typeArguments);
}
else
{
converterType = typeof(LargeObjectWithParameterizedConstructorConverterWithReflection<>).MakeGenericType(typeToConvert);
}
}
converter = (JsonConverter)Activator.CreateInstance(
converterType,
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: null,
culture: null)!;
converter.ConstructorInfo = constructor!;
return converter;
}
}
}
|