< Summary

Line coverage
53%
Covered lines: 39
Uncovered lines: 34
Coverable lines: 73
Total lines: 138
Line coverage: 53.4%
Branch coverage
42%
Covered branches: 12
Total branches: 28
Branch coverage: 42.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
CanConvert(...)100%11100%
CreateConverter(...)42.85%282847.69%

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)]
 124        public ObjectConverterFactory(bool useDefaultConstructorInUnannotatedStructs = true)
 125        {
 126            _useDefaultConstructorInUnannotatedStructs = useDefaultConstructorInUnannotatedStructs;
 127        }
 28
 29        public override bool CanConvert(Type typeToConvert)
 99230        {
 31            // This is the last built-in factory converter, so if the IEnumerableConverterFactory doesn't
 32            // support it, then it is not IEnumerable.
 99233            Debug.Assert(!typeof(IEnumerable).IsAssignableFrom(typeToConvert));
 99234            return true;
 99235        }
 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)
 49642        {
 43            JsonConverter converter;
 44            Type converterType;
 45
 49646            bool useDefaultConstructorInUnannotatedStructs = _useDefaultConstructorInUnannotatedStructs && !typeToConver
 49647            if (!typeToConvert.TryGetDeserializationConstructor(useDefaultConstructorInUnannotatedStructs, out Construct
 048            {
 049                ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute<JsonConstructorAttribute>
 50            }
 51
 49652            ParameterInfo[]? parameters = constructor?.GetParameters();
 53
 49654            if (constructor == null || typeToConvert.IsAbstract || parameters!.Length == 0)
 16355            {
 16356                converterType = typeof(ObjectDefaultConverter<>).MakeGenericType(typeToConvert);
 16357            }
 58            else
 33359            {
 33360                int parameterCount = parameters.Length;
 61
 499562                foreach (ParameterInfo parameter in parameters)
 199863                {
 64                    // Skip out parameters — they don't receive values from JSON
 65                    // and may reference unsupported types (e.g. Task).
 199866                    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.
 199873                    Type parameterType = parameter.ParameterType;
 199874                    if (parameterType.IsByRef)
 075                    {
 076                        parameterType = parameterType.GetElementType()!;
 077                    }
 78
 199879                    JsonTypeInfo.ValidateType(parameterType);
 199880                }
 81
 33382                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
 333121                {
 333122                    converterType = typeof(LargeObjectWithParameterizedConstructorConverterWithReflection<>).MakeGeneric
 333123                }
 333124            }
 125
 496126            converter = (JsonConverter)Activator.CreateInstance(
 496127                    converterType,
 496128                    BindingFlags.Instance | BindingFlags.Public,
 496129                    binder: null,
 496130                    args: null,
 496131                    culture: null)!;
 132
 496133            converter.ConstructorInfo = constructor!;
 496134            return converter;
 496135        }
 136    }
 137}
 138