< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 73
Coverable lines: 73
Total lines: 138
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 28
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
CanConvert(...)100%110%
CreateConverter(...)0%28280%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectConverterFactory.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Reflection;
 9using System.Text.Json.Reflection;
 10using System.Text.Json.Serialization.Metadata;
 11
 12namespace System.Text.Json.Serialization.Converters
 13{
 14    /// <summary>
 15    /// Converter factory for all object-based types (non-enumerable and non-primitive).
 16    /// </summary>
 17    [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 18    internal sealed class ObjectConverterFactory : JsonConverterFactory
 19    {
 20        // Need to toggle this behavior when generating converters for F# struct records.
 21        private readonly bool _useDefaultConstructorInUnannotatedStructs;
 22
 23        [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 024        public ObjectConverterFactory(bool useDefaultConstructorInUnannotatedStructs = true)
 025        {
 026            _useDefaultConstructorInUnannotatedStructs = useDefaultConstructorInUnannotatedStructs;
 027        }
 28
 29        public override bool CanConvert(Type typeToConvert)
 030        {
 31            // This is the last built-in factory converter, so if the IEnumerableConverterFactory doesn't
 32            // support it, then it is not IEnumerable.
 033            Debug.Assert(!typeof(IEnumerable).IsAssignableFrom(typeToConvert));
 034            return true;
 035        }
 36
 37        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
 38            Justification = "The ctor is marked RequiresUnreferencedCode.")]
 39        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern",
 40            Justification = "The ctor is marked RequiresUnreferencedCode.")]
 41        public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
 042        {
 43            JsonConverter converter;
 44            Type converterType;
 45
 046            bool useDefaultConstructorInUnannotatedStructs = _useDefaultConstructorInUnannotatedStructs && !typeToConver
 047            if (!typeToConvert.TryGetDeserializationConstructor(useDefaultConstructorInUnannotatedStructs, out Construct
 048            {
 049                ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute<JsonConstructorAttribute>
 50            }
 51
 052            ParameterInfo[]? parameters = constructor?.GetParameters();
 53
 054            if (constructor == null || typeToConvert.IsAbstract || parameters!.Length == 0)
 055            {
 056                converterType = typeof(ObjectDefaultConverter<>).MakeGenericType(typeToConvert);
 057            }
 58            else
 059            {
 060                int parameterCount = parameters.Length;
 61
 062                foreach (ParameterInfo parameter in parameters)
 063                {
 64                    // Skip out parameters — they don't receive values from JSON
 65                    // and may reference unsupported types (e.g. Task).
 066                    if (parameter.IsOut)
 067                    {
 068                        continue;
 69                    }
 70
 71                    // Every argument must be of supported type.
 72                    // For byref parameters (in/ref), validate the underlying element type.
 073                    Type parameterType = parameter.ParameterType;
 074                    if (parameterType.IsByRef)
 075                    {
 076                        parameterType = parameterType.GetElementType()!;
 077                    }
 78
 079                    JsonTypeInfo.ValidateType(parameterType);
 080                }
 81
 082                if (parameterCount <= JsonConstants.UnboxedParameterCountThreshold)
 083                {
 084                    Type placeHolderType = typeof(object);
 085                    Type[] typeArguments = new Type[JsonConstants.UnboxedParameterCountThreshold + 1];
 86
 087                    typeArguments[0] = typeToConvert;
 088                    for (int i = 0; i < JsonConstants.UnboxedParameterCountThreshold; i++)
 089                    {
 090                        if (i < parameterCount)
 091                        {
 92                            // out parameters use placeholder type — they aren't deserialized
 93                            // and may reference types that can't be used as generic arguments.
 094                            if (parameters[i].IsOut)
 095                            {
 096                                typeArguments[i + 1] = placeHolderType;
 097                            }
 98                            else
 099                            {
 100                                // For byref parameters (in/ref), use the underlying element type
 101                                // since byref types cannot be used as generic type arguments.
 0102                                Type parameterType = parameters[i].ParameterType;
 0103                                if (parameterType.IsByRef)
 0104                                {
 0105                                    parameterType = parameterType.GetElementType()!;
 0106                                }
 107
 0108                                typeArguments[i + 1] = parameterType;
 0109                            }
 0110                        }
 111                        else
 0112                        {
 113                            // Use placeholder arguments if there are less args than the threshold.
 0114                            typeArguments[i + 1] = placeHolderType;
 0115                        }
 0116                    }
 117
 0118                    converterType = typeof(SmallObjectWithParameterizedConstructorConverter<,,,,>).MakeGenericType(typeA
 0119                }
 120                else
 0121                {
 0122                    converterType = typeof(LargeObjectWithParameterizedConstructorConverterWithReflection<>).MakeGeneric
 0123                }
 0124            }
 125
 0126            converter = (JsonConverter)Activator.CreateInstance(
 0127                    converterType,
 0128                    BindingFlags.Instance | BindingFlags.Public,
 0129                    binder: null,
 0130                    args: null,
 0131                    culture: null)!;
 132
 0133            converter.ConstructorInfo = constructor!;
 0134            return converter;
 0135        }
 136    }
 137}
 138