< Summary

Line coverage
49%
Covered lines: 343
Uncovered lines: 356
Coverable lines: 699
Total lines: 1640
Line coverage: 49%
Branch coverage
39%
Covered branches: 123
Total branches: 308
Branch coverage: 39.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
File 1: .cctor()100%11100%
File 1: .ctor(...)100%11100%
File 1: GetProperty(...)0%26260%
File 1: UpdateUtf8PropertyCache(...)0%440%
File 2: .ctor(...)100%11100%
File 2: MakeReadOnly()100%11100%
File 2: ValidateCanBeUsedForPropertyMetadataSerialization()50%2260%
File 2: VerifyMutable()50%2266.66%
File 2: EnsureConfigured()100%22100%
File 2: ConfigureSynchronized()66.66%6677.27%
File 2: Configure()87.5%161690%
File 2: DetermineIsCompatibleWithCurrentOptions()72.22%181860.71%
File 2: IsCurrentNodeCompatible()50%4466.66%
File 2: DetermineUsesParameterizedConstructor()100%22100%
File 2: CreateJsonTypeInfo(...)100%110%
File 2: CreateJsonTypeInfo(...)0%220%
File 2: CreateJsonTypeInfo(...)50%2257.14%
File 2: CreateJsonPropertyInfo(...)0%220%
File 2: CreatePropertyUsingReflection(...)75%44100%
File 2: .ctor(...)50%22100%
File 2: GetHashCode()100%11100%
File 2: Equals(...)50%22100%
File 2: Equals(...)0%220%
File 2: ConfigureProperties()42.85%282868.42%
File 2: PopulateParameterInfoValues(...)75%4484.61%
File 2: ResolveMatchingParameterInfo(...)75%88100%
File 2: ConfigureConstructorParameters()58.33%121264.51%
File 2: ValidateType(...)50%2260%
File 2: IsInvalidForSerialization(...)50%88100%
File 2: PopulatePolymorphismMetadata()50%2255.55%
File 2: MapInterfaceTypesToCallbacks()66.66%121245.45%
File 2: SetCreateObjectIfCompatible(...)100%44100%
File 2: IsByRefLike(...)100%11100%
File 2: IsValidExtensionDataProperty(...)0%10100%
File 2: GetTypeInfoKind(...)83.33%121278.57%
File 2: .ctor(...)100%11100%
File 2: OnCollectionModifying()75%4477.77%
File 2: ValidateAddedValue(...)100%11100%
File 2: SortProperties()100%110%
File 2: AddPropertyWithConflictResolution(...)11.11%181829.72%

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\Metadata\JsonTypeInfo.Cache.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.Generic;
 5using System.Diagnostics;
 6using System.Runtime.CompilerServices;
 7
 8namespace System.Text.Json.Serialization.Metadata
 9{
 10    public abstract partial class JsonTypeInfo
 11    {
 12        /// <summary>
 13        /// Cached typeof(object). It is faster to cache this than to call typeof(object) multiple times.
 14        /// </summary>
 115        internal static readonly Type ObjectType = typeof(object);
 16
 17        // The number of parameters the deserialization constructor has. If this is not equal to ParameterCache.Count, t
 18        // that not all parameters are bound to object properties, and an exception will be thrown if deserialization is
 225519        internal int ParameterCount { get; private protected set; }
 20
 21        // All of the serializable parameters on a POCO constructor
 22        internal ReadOnlySpan<JsonParameterInfo> ParameterCache
 23        {
 24            get
 2425            {
 2426                Debug.Assert(IsConfigured && _parameterCache is not null);
 2427                return _parameterCache;
 2428            }
 29        }
 30
 31        internal bool UsesParameterizedConstructor
 32        {
 33            get
 197034            {
 197035                Debug.Assert(IsConfigured);
 197036                return _parameterCache != null;
 197037            }
 38        }
 39
 40        private JsonParameterInfo[]? _parameterCache;
 41
 42        // All of the serializable properties on a POCO (minus the extension property).
 43        internal ReadOnlySpan<JsonPropertyInfo> PropertyCache
 44        {
 45            get
 046            {
 047                Debug.Assert(IsConfigured && _propertyCache is not null);
 048                return _propertyCache;
 049            }
 50        }
 51
 52        private JsonPropertyInfo[]? _propertyCache;
 53
 54        // All of the serializable properties on a POCO (minus the extension property) keyed on property name.
 55        internal Dictionary<string, JsonPropertyInfo> PropertyIndex
 56        {
 57            get
 058            {
 059                Debug.Assert(IsConfigured && _propertyIndex is not null);
 060                return _propertyIndex;
 061            }
 62        }
 63
 64        private Dictionary<string, JsonPropertyInfo>? _propertyIndex;
 65
 66        /// <summary>
 67        /// Stores a cache of UTF-8 encoded property names and their associated JsonPropertyInfo, if available.
 68        /// Consulted before the <see cref="PropertyIndex" /> lookup to avoid added allocations and decoding costs.
 69        /// The cache is grown on-demand appending encountered unbounded properties or alternative casings.
 70        /// </summary>
 1225471        private PropertyRef[] _utf8PropertyCache = [];
 72
 73        /// <summary>
 74        /// Defines the core property lookup logic for a given unescaped UTF-8 encoded property name.
 75        /// </summary>
 76        internal JsonPropertyInfo? GetProperty(ReadOnlySpan<byte> propertyName, ref ReadStackFrame frame, out byte[] utf
 077        {
 078            Debug.Assert(IsConfigured);
 79
 80            // The logic can be broken up into roughly three stages:
 81            // 1. Look up the UTF-8 property cache for potential exact matches in the encoding.
 82            // 2. If no match is found, decode to UTF-16 and look up the primary dictionary.
 83            // 3. Store the new result for potential inclusion to the UTF-8 cache once deserialization is complete.
 84
 085            PropertyRef[] utf8PropertyCache = _utf8PropertyCache; // Keep a local copy of the cache in case it changes b
 086            ReadOnlySpan<PropertyRef> utf8PropertyCacheSpan = utf8PropertyCache;
 087            ulong key = PropertyRef.GetKey(propertyName);
 88
 089            if (!utf8PropertyCacheSpan.IsEmpty)
 090            {
 91                PropertyRef propertyRef;
 92
 93                // Start with the current property index, and then go forwards\backwards.
 094                int propertyIndex = frame.PropertyIndex;
 95
 096                int count = utf8PropertyCacheSpan.Length;
 097                int iForward = Math.Min(propertyIndex, count);
 098                int iBackward = iForward - 1;
 99
 0100                while (true)
 0101                {
 0102                    if (iForward < count)
 0103                    {
 0104                        propertyRef = utf8PropertyCacheSpan[iForward];
 0105                        if (propertyRef.Equals(propertyName, key))
 0106                        {
 0107                            utf8PropertyName = propertyRef.Utf8PropertyName;
 0108                            return propertyRef.Info;
 109                        }
 110
 0111                        ++iForward;
 112
 0113                        if (iBackward >= 0)
 0114                        {
 0115                            propertyRef = utf8PropertyCacheSpan[iBackward];
 0116                            if (propertyRef.Equals(propertyName, key))
 0117                            {
 0118                                utf8PropertyName = propertyRef.Utf8PropertyName;
 0119                                return propertyRef.Info;
 120                            }
 121
 0122                            --iBackward;
 0123                        }
 0124                    }
 0125                    else if (iBackward >= 0)
 0126                    {
 0127                        propertyRef = utf8PropertyCacheSpan[iBackward];
 0128                        if (propertyRef.Equals(propertyName, key))
 0129                        {
 0130                            utf8PropertyName = propertyRef.Utf8PropertyName;
 0131                            return propertyRef.Info;
 132                        }
 133
 0134                        --iBackward;
 0135                    }
 136                    else
 0137                    {
 138                        // Property was not found.
 0139                        break;
 140                    }
 0141                }
 0142            }
 143
 144            // No cached item was found. Try the main dictionary which has all of the properties.
 0145            if (PropertyIndex.TryLookupUtf8Key(propertyName, out JsonPropertyInfo? info) &&
 0146                (!Options.PropertyNameCaseInsensitive || propertyName.SequenceEqual(info.NameAsUtf8Bytes)))
 0147            {
 148                // We have an exact match in UTF8 encoding.
 0149                utf8PropertyName = info.NameAsUtf8Bytes;
 0150            }
 151            else
 0152            {
 153                // Make a copy of the original Span.
 0154                utf8PropertyName = propertyName.ToArray();
 0155            }
 156
 157            // Assuming there is capacity, store the new result for potential
 158            // inclusion to the UTF-8 cache once deserialization is complete.
 159
 0160            ref PropertyRefCacheBuilder? cacheBuilder = ref frame.PropertyRefCacheBuilder;
 0161            if ((cacheBuilder?.TotalCount ?? utf8PropertyCache.Length) < PropertyRefCacheBuilder.MaxCapacity)
 0162            {
 0163                (cacheBuilder ??= new(utf8PropertyCache)).TryAdd(new(key, info, utf8PropertyName));
 0164            }
 165
 0166            return info;
 0167        }
 168
 169        /// <summary>
 170        /// Attempts to update the UTF-8 property cache with the results gathered in the current deserialization operati
 171        /// The update operation is done optimistically and results are discarded if the cache was updated by another th
 172        /// </summary>
 173        internal void UpdateUtf8PropertyCache(ref ReadStackFrame frame)
 0174        {
 0175            Debug.Assert(frame.PropertyRefCacheBuilder is { Count: > 0 });
 176
 0177            PropertyRef[]? currentCache = _utf8PropertyCache;
 0178            PropertyRefCacheBuilder cacheBuilder = frame.PropertyRefCacheBuilder;
 179
 0180            if (currentCache == cacheBuilder.OriginalCache)
 0181            {
 0182                PropertyRef[] newCache = cacheBuilder.ToArray();
 0183                Debug.Assert(newCache.Length <= PropertyRefCacheBuilder.MaxCapacity);
 0184                _utf8PropertyCache = cacheBuilder.ToArray();
 0185            }
 186
 0187            frame.PropertyRefCacheBuilder = null;
 0188        }
 189    }
 190}

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\Metadata\JsonTypeInfo.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.ComponentModel;
 7using System.Diagnostics;
 8using System.Diagnostics.CodeAnalysis;
 9using System.IO;
 10using System.IO.Pipelines;
 11using System.Reflection;
 12using System.Runtime.CompilerServices;
 13using System.Runtime.ExceptionServices;
 14using System.Text.Json.Reflection;
 15using System.Text.Json.Serialization.Converters;
 16using System.Threading;
 17using System.Threading.Tasks;
 18
 19namespace System.Text.Json.Serialization.Metadata
 20{
 21    /// <summary>
 22    /// Provides JSON serialization-related metadata about a type.
 23    /// </summary>
 24    [DebuggerDisplay("{DebuggerDisplay,nq}")]
 25    public abstract partial class JsonTypeInfo
 26    {
 27        internal const string MetadataFactoryRequiresUnreferencedCode = "JSON serialization and deserialization might re
 28
 29        internal const string JsonObjectTypeName = "System.Text.Json.Nodes.JsonObject";
 30
 31        internal delegate T ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>(TArg0? arg0, TArg1? arg1, TA
 32
 33        /// <summary>
 34        /// Negated bitmask of the required properties, indexed by <see cref="JsonPropertyInfo.PropertyIndex"/>.
 35        /// </summary>
 132936        internal BitArray? OptionalPropertiesMask { get; private set; }
 3037        internal bool ShouldTrackRequiredProperties => OptionalPropertiesMask is not null;
 38
 39        private Action<object>? _onSerializing;
 40        private Action<object>? _onSerialized;
 41        private Action<object>? _onDeserializing;
 42        private Action<object>? _onDeserialized;
 43
 1225444        internal JsonTypeInfo(Type type, JsonConverter converter, JsonSerializerOptions options)
 1225445        {
 1225446            Type = type;
 1225447            Options = options;
 1225448            Converter = converter;
 1225449            Kind = GetTypeInfoKind(type, converter);
 1225450            PropertyInfoForTypeInfo = CreatePropertyInfoForTypeInfo();
 1225451            ElementType = converter.ElementType;
 1225452            KeyType = converter.KeyType;
 1225453        }
 54
 55        /// <summary>
 56        /// Gets the element type corresponding to an enumerable, dictionary or optional type.
 57        /// </summary>
 58        /// <remarks>
 59        /// Returns the element type for enumerable types, the value type for dictionary types,
 60        /// and the underlying type for <see cref="Nullable{T}"/> or F# optional types.
 61        ///
 62        /// Returns <see langword="null"/> for all other types or types using custom converters.
 63        /// </remarks>
 1325664        public Type? ElementType { get; }
 65
 66        /// <summary>
 67        /// Gets the key type corresponding to a dictionary type.
 68        /// </summary>
 69        /// <remarks>
 70        /// Returns the key type for dictionary types.
 71        ///
 72        /// Returns <see langword="null"/> for all other types or types using custom converters.
 73        /// </remarks>
 1261874        public Type? KeyType { get; }
 75
 76        /// <summary>
 77        /// Gets or sets a parameterless factory to be used on deserialization.
 78        /// </summary>
 79        /// <exception cref="InvalidOperationException">
 80        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 81        ///
 82        /// -or-
 83        ///
 84        /// A parameterless factory is not supported for the current metadata <see cref="Kind"/>.
 85        /// </exception>
 86        /// <remarks>
 87        /// If set to <see langword="null" />, any attempt to deserialize instances of the given type will result in an 
 88        ///
 89        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 90        /// types with a single default constructor or default constructors annotated with <see cref="JsonConstructorAtt
 91        /// will be mapped to this delegate.
 92        /// </remarks>
 93        public Func<object>? CreateObject
 94        {
 732995            get => _createObject;
 96            set
 097            {
 098                SetCreateObject(value);
 099            }
 100        }
 101
 102        private protected abstract void SetCreateObject(Delegate? createObject);
 103        private protected Func<object>? _createObject;
 104
 12523105        internal Func<object>? CreateObjectForExtensionDataProperty { get; set; }
 106
 107        /// <summary>
 108        /// Gets or sets a callback to be invoked before serialization occurs.
 109        /// </summary>
 110        /// <exception cref="InvalidOperationException">
 111        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 112        ///
 113        /// -or-
 114        ///
 115        /// Serialization callbacks are only supported for <see cref="JsonTypeInfoKind.Object"/> metadata.
 116        /// </exception>
 117        /// <remarks>
 118        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 119        /// the value of this callback will be mapped from any <see cref="IJsonOnSerializing"/> implementation on the ty
 120        /// </remarks>
 121        public Action<object>? OnSerializing
 122        {
 0123            get => _onSerializing;
 124            set
 0125            {
 0126                VerifyMutable();
 127
 0128                if (Kind is not (JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary))
 0129                {
 0130                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 131                }
 132
 0133                _onSerializing = value;
 0134            }
 135        }
 136
 137        /// <summary>
 138        /// Gets or sets a callback to be invoked after serialization occurs.
 139        /// </summary>
 140        /// <exception cref="InvalidOperationException">
 141        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 142        ///
 143        /// -or-
 144        ///
 145        /// Serialization callbacks are only supported for <see cref="JsonTypeInfoKind.Object"/> metadata.
 146        /// </exception>
 147        /// <remarks>
 148        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 149        /// the value of this callback will be mapped from any <see cref="IJsonOnSerialized"/> implementation on the typ
 150        /// </remarks>
 151        public Action<object>? OnSerialized
 152        {
 0153            get => _onSerialized;
 154            set
 0155            {
 0156                VerifyMutable();
 157
 0158                if (Kind is not (JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary))
 0159                {
 0160                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 161                }
 162
 0163                _onSerialized = value;
 0164            }
 165        }
 166
 167        /// <summary>
 168        /// Gets or sets a callback to be invoked before deserialization occurs.
 169        /// </summary>
 170        /// <exception cref="InvalidOperationException">
 171        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 172        ///
 173        /// -or-
 174        ///
 175        /// Serialization callbacks are only supported for <see cref="JsonTypeInfoKind.Object"/> metadata.
 176        /// </exception>
 177        /// <remarks>
 178        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 179        /// the value of this callback will be mapped from any <see cref="IJsonOnDeserializing"/> implementation on the 
 180        /// </remarks>
 181        public Action<object>? OnDeserializing
 182        {
 294183            get => _onDeserializing;
 184            set
 0185            {
 0186                VerifyMutable();
 187
 0188                if (Kind is not (JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary))
 0189                {
 0190                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 191                }
 192
 0193                if (Converter.IsConvertibleCollection)
 0194                {
 195                    // The values for convertible collections aren't available at the start of deserialization.
 0196                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOnDeserializingCallbacksNotSupported(Type);
 197                }
 198
 0199                _onDeserializing = value;
 0200            }
 201        }
 202
 203        /// <summary>
 204        /// Gets or sets a callback to be invoked after deserialization occurs.
 205        /// </summary>
 206        /// <exception cref="InvalidOperationException">
 207        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 208        ///
 209        /// -or-
 210        ///
 211        /// Serialization callbacks are only supported for <see cref="JsonTypeInfoKind.Object"/> metadata.
 212        /// </exception>
 213        /// <remarks>
 214        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 215        /// the value of this callback will be mapped from any <see cref="IJsonOnDeserialized"/> implementation on the t
 216        /// </remarks>
 217        public Action<object>? OnDeserialized
 218        {
 34219            get => _onDeserialized;
 220            set
 0221            {
 0222                VerifyMutable();
 223
 0224                if (Kind is not (JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary))
 0225                {
 0226                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 227                }
 228
 0229                _onDeserialized = value;
 0230            }
 231        }
 232
 233        /// <summary>
 234        /// Gets the list of <see cref="JsonPropertyInfo"/> metadata corresponding to the current type.
 235        /// </summary>
 236        /// <remarks>
 237        /// Property is only applicable to metadata of kind <see cref="JsonTypeInfoKind.Object"/>.
 238        /// For other kinds an empty, read-only list will be returned.
 239        ///
 240        /// The order of <see cref="JsonPropertyInfo"/> entries in the list determines the serialization order,
 241        /// unless either of the entries specifies a non-zero <see cref="JsonPropertyInfo.Order"/> value,
 242        /// in which case the properties will be stable sorted by <see cref="JsonPropertyInfo.Order"/>.
 243        ///
 244        /// It is required that added <see cref="JsonPropertyInfo"/> entries are unique up to <see cref="JsonPropertyInf
 245        /// however this will only be validated on serialization, once the metadata instance gets locked for further mod
 246        /// </remarks>
 0247        public IList<JsonPropertyInfo> Properties => PropertyList;
 248
 249        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 250        internal JsonPropertyInfoList PropertyList
 251        {
 252            get
 9093253            {
 9093254                return _properties ?? CreatePropertyList();
 255                JsonPropertyInfoList CreatePropertyList()
 1299256                {
 1299257                    var list = new JsonPropertyInfoList(this);
 1299258                    if (_sourceGenDelayedPropertyInitializer is { } propInit)
 0259                    {
 260                        // .NET 6 source gen backward compatibility -- ensure that the
 261                        // property initializer delegate is invoked lazily.
 0262                        JsonMetadataServices.PopulateProperties(this, list, propInit);
 0263                    }
 264
 1299265                    JsonPropertyInfoList? result = Interlocked.CompareExchange(ref _properties, list, null);
 1299266                    _sourceGenDelayedPropertyInitializer = null;
 1299267                    return result ?? list;
 1299268                }
 9093269            }
 270        }
 271
 272        /// <summary>
 273        /// Stores the .NET 6-style property initialization delegate for delayed evaluation.
 274        /// </summary>
 275        internal Func<JsonSerializerContext, JsonPropertyInfo[]>? SourceGenDelayedPropertyInitializer
 276        {
 277            get => _sourceGenDelayedPropertyInitializer;
 278            set
 0279            {
 0280                Debug.Assert(!IsReadOnly);
 0281                Debug.Assert(_properties is null, "must not be set if a property list has been initialized.");
 0282                _sourceGenDelayedPropertyInitializer = value;
 0283            }
 284        }
 285
 286        private Func<JsonSerializerContext, JsonPropertyInfo[]>? _sourceGenDelayedPropertyInitializer;
 287        private JsonPropertyInfoList? _properties;
 288
 289        /// <summary>
 290        /// Gets or sets a configuration object specifying polymorphism metadata.
 291        /// </summary>
 292        /// <exception cref="ArgumentException">
 293        /// <paramref name="value" /> has been associated with a different <see cref="JsonTypeInfo"/> instance.
 294        /// </exception>
 295        /// <exception cref="InvalidOperationException">
 296        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 297        ///
 298        /// -or-
 299        ///
 300        /// Polymorphic serialization is not supported for the current metadata <see cref="Kind"/>.
 301        /// </exception>
 302        /// <remarks>
 303        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 304        /// the configuration of this setting will be mapped from any <see cref="JsonDerivedTypeAttribute"/> or <see cre
 305        /// </remarks>
 306        public JsonPolymorphismOptions? PolymorphismOptions
 307        {
 12254308            get => _polymorphismOptions;
 309            set
 0310            {
 0311                VerifyMutable();
 312
 0313                if (value != null)
 0314                {
 0315                    if (Kind == JsonTypeInfoKind.None)
 0316                    {
 0317                        ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 318                    }
 319
 0320                    if (value.DeclaringTypeInfo != null && value.DeclaringTypeInfo != this)
 0321                    {
 0322                        ThrowHelper.ThrowArgumentException_JsonPolymorphismOptionsAssociatedWithDifferentJsonTypeInfo(na
 323                    }
 324
 0325                    value.DeclaringTypeInfo = this;
 0326                }
 327
 0328                _polymorphismOptions = value;
 0329            }
 330        }
 331
 332        /// <summary>
 333        /// Specifies whether the current instance has been locked for modification.
 334        /// </summary>
 335        /// <remarks>
 336        /// A <see cref="JsonTypeInfo"/> instance can be locked either if
 337        /// it has been passed to one of the <see cref="JsonSerializer"/> methods,
 338        /// has been associated with a <see cref="JsonSerializerContext"/> instance,
 339        /// or a user explicitly called the <see cref="MakeReadOnly"/> method on the instance.
 340        /// </remarks>
 180499341        public bool IsReadOnly { get; private set; }
 342
 343        /// <summary>
 344        /// Locks the current instance for further modification.
 345        /// </summary>
 346        /// <remarks>This method is idempotent.</remarks>
 24508347        public void MakeReadOnly() => IsReadOnly = true;
 348
 349        private protected JsonPolymorphismOptions? _polymorphismOptions;
 350
 10095351        internal object? CreateObjectWithArgs { get; set; }
 352
 353        // Add method delegate for non-generic Stack and Queue; and types that derive from them.
 0354        internal object? AddMethodDelegate { get; set; }
 355
 3347356        internal JsonPropertyInfo? ExtensionDataProperty { get; private set; }
 357
 55928358        internal PolymorphicTypeResolver? PolymorphicTypeResolver { get; private set; }
 359
 360        // Indicates that SerializeHandler is populated.
 12254361        internal bool HasSerializeHandler { get; private protected set; }
 362
 363        // Indicates that SerializeHandler is populated and is compatible with the associated contract metadata.
 12254364        internal bool CanUseSerializeHandler { get; private set; }
 365
 366        // Configure would normally have thrown why initializing properties for source gen but type had SerializeHandler
 367        // so it is allowed to be used for fast-path serialization but it will throw if used for metadata-based serializ
 8368        internal bool PropertyMetadataSerializationNotSupported { get; set; }
 369
 1299370        internal bool IsNullable => Converter.NullableElementConverter is not null;
 371        internal bool CanBeNull => PropertyInfoForTypeInfo.PropertyTypeCanBeNull;
 372
 373        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 374        internal void ValidateCanBeUsedForPropertyMetadataSerialization()
 8375        {
 8376            if (PropertyMetadataSerializationNotSupported)
 0377            {
 0378                ThrowHelper.ThrowInvalidOperationException_NoMetadataForTypeProperties(Options.TypeInfoResolver, Type);
 379            }
 8380        }
 381
 382        /// <summary>
 383        /// Return the JsonTypeInfo for the element type, or null if the type is not an enumerable or dictionary.
 384        /// </summary>
 385        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 386        internal JsonTypeInfo? ElementTypeInfo
 387        {
 388            get
 1362389            {
 1362390                Debug.Assert(IsConfigured);
 1362391                Debug.Assert(_elementTypeInfo is null or { IsConfigurationStarted: true });
 392                // Even though this instance has already been configured,
 393                // it is possible for contending threads to call the property
 394                // while the wider JsonTypeInfo graph is still being configured.
 395                // Call EnsureConfigured() to force synchronization if necessary.
 1362396                JsonTypeInfo? elementTypeInfo = _elementTypeInfo;
 1362397                elementTypeInfo?.EnsureConfigured();
 1362398                return elementTypeInfo;
 1362399            }
 400            set
 0401            {
 0402                Debug.Assert(!IsReadOnly);
 0403                Debug.Assert(value is null || value.Type == ElementType);
 0404                _elementTypeInfo = value;
 0405            }
 406        }
 407
 408        /// <summary>
 409        /// Return the JsonTypeInfo for the key type, or null if the type is not a dictionary.
 410        /// </summary>
 411        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 412        internal JsonTypeInfo? KeyTypeInfo
 413        {
 414            get
 650415            {
 650416                Debug.Assert(IsConfigured);
 650417                Debug.Assert(_keyTypeInfo is null or { IsConfigurationStarted: true });
 418                // Even though this instance has already been configured,
 419                // it is possible for contending threads to call the property
 420                // while the wider JsonTypeInfo graph is still being configured.
 421                // Call EnsureConfigured() to force synchronization if necessary.
 650422                JsonTypeInfo? keyTypeInfo = _keyTypeInfo;
 650423                keyTypeInfo?.EnsureConfigured();
 650424                return keyTypeInfo;
 650425            }
 426            set
 0427            {
 0428                Debug.Assert(!IsReadOnly);
 0429                Debug.Assert(value is null || value.Type == KeyType);
 0430                _keyTypeInfo = value;
 0431            }
 432        }
 433
 434        private JsonTypeInfo? _elementTypeInfo;
 435        private JsonTypeInfo? _keyTypeInfo;
 436
 437        /// <summary>
 438        /// Gets the <see cref="JsonSerializerOptions"/> value associated with the current <see cref="JsonTypeInfo" /> i
 439        /// </summary>
 334695440        public JsonSerializerOptions Options { get; }
 441
 442        /// <summary>
 443        /// Gets the <see cref="Type"/> for which the JSON serialization contract is being defined.
 444        /// </summary>
 186982445        public Type Type { get; }
 446
 447        /// <summary>
 448        /// Gets the <see cref="JsonConverter"/> associated with the current type.
 449        /// </summary>
 450        /// <remarks>
 451        /// The <see cref="JsonConverter"/> associated with the type determines the value of <see cref="Kind"/>,
 452        /// and by extension the types of metadata that are configurable in the current JSON contract.
 453        /// As such, the value of the converter cannot be changed once a <see cref="JsonTypeInfo"/> instance has been cr
 454        /// </remarks>
 43598455        public JsonConverter Converter { get; }
 456
 457        /// <summary>
 458        /// Determines the kind of contract metadata that the current instance is specifying.
 459        /// </summary>
 460        /// <remarks>
 461        /// The value of <see cref="Kind"/> determines what aspects of the JSON contract are configurable.
 462        /// For example, it is only possible to configure the <see cref="Properties"/> list for metadata
 463        /// of kind <see cref="JsonTypeInfoKind.Object"/>.
 464        ///
 465        /// The value of <see cref="Kind"/> is determined exclusively by the <see cref="JsonConverter"/>
 466        /// resolved for the current type, and cannot be changed once resolution has happened.
 467        /// User-defined custom converters (specified either via <see cref="JsonConverterAttribute"/> or <see cref="Json
 468        /// are metadata-agnostic and thus always resolve to <see cref="JsonTypeInfoKind.None"/>.
 469        /// </remarks>
 106961470        public JsonTypeInfoKind Kind { get; }
 471
 472        /// <summary>
 473        /// Dummy <see cref="JsonPropertyInfo"/> instance corresponding to the declaring type of this <see cref="JsonTyp
 474        /// </summary>
 475        /// <remarks>
 476        /// Used as convenience in cases where we want to serialize property-like values that do not define property met
 477        /// 1. a collection element type,
 478        /// 2. a dictionary key or value type or,
 479        /// 3. the property metadata for the root-level value.
 480        /// For example, for a property returning <see cref="List{T}"/> where T is a string,
 481        /// a JsonTypeInfo will be created with .Type=typeof(string) and .PropertyInfoForTypeInfo=JsonPropertyInfo{strin
 482        /// </remarks>
 68394483        internal JsonPropertyInfo PropertyInfoForTypeInfo { get; }
 484
 485        private protected abstract JsonPropertyInfo CreatePropertyInfoForTypeInfo();
 486
 487        /// <summary>
 488        /// Gets or sets the type-level <see cref="JsonSerializerOptions.NumberHandling"/> override.
 489        /// </summary>
 490        /// <exception cref="InvalidOperationException">
 491        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 492        /// </exception>
 493        /// <exception cref="ArgumentOutOfRangeException">
 494        /// Specified an invalid <see cref="JsonNumberHandling"/> value.
 495        /// </exception>
 496        /// <remarks>
 497        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 498        /// the value of this callback will be mapped from any <see cref="JsonNumberHandlingAttribute"/> annotations.
 499        /// </remarks>
 500        public JsonNumberHandling? NumberHandling
 501        {
 25028502            get => _numberHandling;
 503            set
 0504            {
 0505                VerifyMutable();
 506
 0507                if (value is not null && !JsonSerializer.IsValidNumberHandlingValue(value.Value))
 0508                {
 0509                    throw new ArgumentOutOfRangeException(nameof(value));
 510                }
 511
 0512                _numberHandling = value;
 0513            }
 514        }
 515
 0516        internal JsonNumberHandling EffectiveNumberHandling => _numberHandling ?? Options.NumberHandling;
 517        private JsonNumberHandling? _numberHandling;
 518
 519        /// <summary>
 520        /// Gets or sets the type-level <see cref="JsonUnmappedMemberHandling"/> override.
 521        /// </summary>
 522        /// <exception cref="InvalidOperationException">
 523        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 524        ///
 525        /// -or-
 526        ///
 527        /// Unmapped member handling only supported for <see cref="JsonTypeInfoKind.Object"/>.
 528        /// </exception>
 529        /// <exception cref="ArgumentOutOfRangeException">
 530        /// Specified an invalid <see cref="JsonUnmappedMemberHandling"/> value.
 531        /// </exception>
 532        /// <remarks>
 533        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 534        /// the value of this callback will be mapped from any <see cref="JsonUnmappedMemberHandlingAttribute"/> annotat
 535        /// </remarks>
 536        public JsonUnmappedMemberHandling? UnmappedMemberHandling
 537        {
 1299538            get => _unmappedMemberHandling;
 539            set
 0540            {
 0541                VerifyMutable();
 542
 0543                if (Kind != JsonTypeInfoKind.Object)
 0544                {
 0545                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 546                }
 547
 0548                if (value is not null && !JsonSerializer.IsValidUnmappedMemberHandlingValue(value.Value))
 0549                {
 0550                    throw new ArgumentOutOfRangeException(nameof(value));
 551                }
 552
 0553                _unmappedMemberHandling = value;
 0554            }
 555        }
 556
 557        private JsonUnmappedMemberHandling? _unmappedMemberHandling;
 558
 1299559        internal JsonUnmappedMemberHandling EffectiveUnmappedMemberHandling { get; private set; }
 560
 561        private JsonObjectCreationHandling? _preferredPropertyObjectCreationHandling;
 562
 563        /// <summary>
 564        /// Gets or sets the preferred <see cref="JsonObjectCreationHandling"/> value for properties contained in the ty
 565        /// </summary>
 566        /// <exception cref="InvalidOperationException">
 567        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 568        ///
 569        /// -or-
 570        ///
 571        /// Unmapped member handling only supported for <see cref="JsonTypeInfoKind.Object"/>.
 572        /// </exception>
 573        /// <exception cref="ArgumentOutOfRangeException">
 574        /// Specified an invalid <see cref="JsonObjectCreationHandling"/> value.
 575        /// </exception>
 576        /// <remarks>
 577        /// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext
 578        /// the value of this callback will be mapped from <see cref="JsonObjectCreationHandlingAttribute"/> annotations
 579        /// </remarks>
 580        public JsonObjectCreationHandling? PreferredPropertyObjectCreationHandling
 581        {
 20048582            get => _preferredPropertyObjectCreationHandling;
 583            set
 0584            {
 0585                VerifyMutable();
 586
 0587                if (Kind != JsonTypeInfoKind.Object)
 0588                {
 0589                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(Kind);
 590                }
 591
 0592                if (value is not null && !JsonSerializer.IsValidCreationHandlingValue(value.Value))
 0593                {
 0594                    throw new ArgumentOutOfRangeException(nameof(value));
 595                }
 596
 0597                _preferredPropertyObjectCreationHandling = value;
 0598            }
 599        }
 600
 601        /// <summary>
 602        /// Gets or sets the <see cref="IJsonTypeInfoResolver"/> from which this metadata instance originated.
 603        /// </summary>
 604        /// <exception cref="InvalidOperationException">
 605        /// The <see cref="JsonTypeInfo"/> instance has been locked for further modification.
 606        /// </exception>
 607        /// <remarks>
 608        /// Metadata used to determine the <see cref="JsonSerializerContext.GeneratedSerializerOptions"/>
 609        /// configuration for the current metadata instance.
 610        /// </remarks>
 611        [EditorBrowsable(EditorBrowsableState.Never)]
 612        public IJsonTypeInfoResolver? OriginatingResolver
 613        {
 0614            get => _originatingResolver;
 615            set
 12254616            {
 12254617                VerifyMutable();
 618
 12254619                if (value is JsonSerializerContext)
 0620                {
 621                    // The source generator uses this property setter to brand the metadata instance as user-unmodified.
 622                    // Even though users could call the same property setter to unset this flag, this is generally speak
 623                    // This flag is only used to determine fast-path invalidation, worst case scenario this would lead t
 0624                    IsCustomized = false;
 0625                }
 626
 12254627                _originatingResolver = value;
 12254628            }
 629        }
 630
 631        private IJsonTypeInfoResolver? _originatingResolver;
 632
 633        /// <summary>
 634        /// Gets or sets an attribute provider corresponding to the deserialization constructor.
 635        /// </summary>
 636        /// <exception cref="InvalidOperationException">
 637        /// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
 638        /// </exception>
 639        /// <remarks>
 640        /// When resolving metadata via the built-in resolvers this will be populated with
 641        /// the underlying <see cref="ConstructorInfo" /> of the serialized property or field.
 642        /// </remarks>
 643        public ICustomAttributeProvider? ConstructorAttributeProvider
 644        {
 645            get
 0646            {
 0647                Func<ICustomAttributeProvider>? ctorAttrProviderFactory = Volatile.Read(ref ConstructorAttributeProvider
 0648                ICustomAttributeProvider? ctorAttrProvider = _constructorAttributeProvider;
 649
 0650                if (ctorAttrProvider is null && ctorAttrProviderFactory is not null)
 0651                {
 0652                    _constructorAttributeProvider = ctorAttrProvider = ctorAttrProviderFactory();
 0653                    Volatile.Write(ref ConstructorAttributeProviderFactory, null);
 0654                }
 655
 0656                return ctorAttrProvider;
 0657            }
 658            internal set
 2851659            {
 2851660                Debug.Assert(!IsReadOnly);
 661
 2851662                _constructorAttributeProvider = value;
 2851663                Volatile.Write(ref ConstructorAttributeProviderFactory, null);
 2851664            }
 665        }
 666
 667        // Metadata emanating from the source generator use delayed attribute provider initialization
 668        // ensuring that reflection metadata resolution remains pay-for-play and is trimmable.
 669        internal Func<ICustomAttributeProvider>? ConstructorAttributeProviderFactory;
 670        private ICustomAttributeProvider? _constructorAttributeProvider;
 671
 672        internal void VerifyMutable()
 89272673        {
 89272674            if (IsReadOnly)
 0675            {
 0676                ThrowHelper.ThrowInvalidOperationException_TypeInfoImmutable();
 677            }
 678
 89272679            IsCustomized = true;
 89272680        }
 681
 682        /// <summary>
 683        /// Indicates that the current JsonTypeInfo might contain user modifications.
 684        /// Defaults to true, and is only unset by the built-in contract resolvers.
 685        /// </summary>
 126034686        internal bool IsCustomized { get; set; } = true;
 687
 161817688        internal bool IsConfigured => _configurationState == ConfigurationState.Configured;
 9810689        internal bool IsConfigurationStarted => _configurationState is not ConfigurationState.NotConfigured;
 690        private volatile ConfigurationState _configurationState;
 691        private enum ConfigurationState : byte
 692        {
 693            NotConfigured = 0,
 694            Configuring = 1,
 695            Configured = 2
 696        };
 697
 698        private ExceptionDispatchInfo? _cachedConfigureError;
 699
 700        internal void EnsureConfigured()
 61791701        {
 61791702            if (!IsConfigured)
 24508703                ConfigureSynchronized();
 704
 705            void ConfigureSynchronized()
 24508706            {
 24508707                Options.MakeReadOnly();
 24508708                MakeReadOnly();
 709
 24508710                _cachedConfigureError?.Throw();
 711
 24508712                lock (Options.CacheContext)
 24508713                {
 24508714                    if (_configurationState != ConfigurationState.NotConfigured)
 12254715                    {
 716                        // The value of _configurationState is either
 717                        //    'Configuring': recursive instance configured by this thread or
 718                        //    'Configured' : instance already configured by another thread.
 719                        // We can safely yield the configuration operation in both cases.
 12254720                        return;
 721                    }
 722
 12254723                    _cachedConfigureError?.Throw();
 724
 725                    try
 12254726                    {
 12254727                        _configurationState = ConfigurationState.Configuring;
 12254728                        Configure();
 12254729                        _configurationState = ConfigurationState.Configured;
 12254730                    }
 0731                    catch (Exception e)
 0732                    {
 0733                        _cachedConfigureError = ExceptionDispatchInfo.Capture(e);
 0734                        _configurationState = ConfigurationState.NotConfigured;
 0735                        throw;
 736                    }
 12254737                }
 24508738            }
 61791739        }
 740
 741        private void Configure()
 12254742        {
 12254743            Debug.Assert(Monitor.IsEntered(Options.CacheContext), "Configure called directly, use EnsureConfigured which
 12254744            Debug.Assert(Options.IsReadOnly);
 12254745            Debug.Assert(IsReadOnly);
 746
 12254747            PropertyInfoForTypeInfo.Configure();
 748
 12254749            if (PolymorphismOptions != null)
 0750            {
 751                // This needs to be done before ConfigureProperties() is called
 752                // JsonPropertyInfo.Configure() must have this value available in order to detect Polymoprhic + cyclic c
 0753                PolymorphicTypeResolver = new PolymorphicTypeResolver(Options, PolymorphismOptions, Type, Converter.CanH
 0754            }
 755
 12254756            if (Kind == JsonTypeInfoKind.Object)
 1299757            {
 1299758                ConfigureProperties();
 759
 1299760                if (DetermineUsesParameterizedConstructor())
 749761                {
 749762                    ConfigureConstructorParameters();
 749763                }
 1299764            }
 765
 12254766            if (ElementType != null)
 1002767            {
 1002768                _elementTypeInfo ??= Options.GetTypeInfoInternal(ElementType);
 1002769                _elementTypeInfo.EnsureConfigured();
 1002770            }
 771
 12254772            if (KeyType != null)
 364773            {
 364774                _keyTypeInfo ??= Options.GetTypeInfoInternal(KeyType);
 364775                _keyTypeInfo.EnsureConfigured();
 364776            }
 777
 12254778            DetermineIsCompatibleWithCurrentOptions();
 12254779            CanUseSerializeHandler = HasSerializeHandler && IsCompatibleWithCurrentOptions;
 12254780        }
 781
 782        /// <summary>
 783        /// Gets any ancestor polymorphic types that declare
 784        /// a type discriminator for the current type. Consulted
 785        /// when serializing polymorphic values as objects.
 786        /// </summary>
 787        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 788        internal JsonTypeInfo? AncestorPolymorphicType
 789        {
 790            get
 0791            {
 0792                Debug.Assert(IsConfigured);
 0793                Debug.Assert(Type != typeof(object));
 794
 0795                if (!_isAncestorPolymorphicTypeResolved)
 0796                {
 0797                    _ancestorPolymorhicType = PolymorphicTypeResolver.FindNearestPolymorphicBaseType(this);
 0798                    _isAncestorPolymorphicTypeResolved = true;
 0799                }
 800
 0801                return _ancestorPolymorhicType;
 0802            }
 803        }
 804
 805        private JsonTypeInfo? _ancestorPolymorhicType;
 806        private volatile bool _isAncestorPolymorphicTypeResolved;
 807
 808        /// <summary>
 809        /// Determines if the transitive closure of all JsonTypeInfo metadata referenced
 810        /// by the current type (property types, key types, element types, ...) are
 811        /// compatible with the settings as specified in JsonSerializerOptions.
 812        /// </summary>
 813        private void DetermineIsCompatibleWithCurrentOptions()
 12254814        {
 815            // Defines a recursive algorithm validating that the `IsCurrentNodeCompatible`
 816            // predicate is valid for every node in the type graph. This method only checks
 817            // the immediate children, with recursion being driven by the Configure() method.
 818            // Therefore, this method must be called _after_ the child nodes have been configured.
 819
 12254820            Debug.Assert(IsReadOnly);
 12254821            Debug.Assert(!IsConfigured);
 822
 12254823            if (!IsCurrentNodeCompatible())
 0824            {
 0825                IsCompatibleWithCurrentOptions = false;
 0826                return;
 827            }
 828
 12254829            if (_properties != null)
 1299830            {
 19485831                foreach (JsonPropertyInfo property in _properties)
 7794832                {
 7794833                    Debug.Assert(property.IsConfigured);
 834
 7794835                    if (!property.IsPropertyTypeInfoConfigured)
 0836                    {
 837                        // Either an ignored property or property is part of a cycle.
 838                        // In both cases we can ignore these instances.
 0839                        continue;
 840                    }
 841
 7794842                    if (!property.JsonTypeInfo.IsCompatibleWithCurrentOptions)
 0843                    {
 0844                        IsCompatibleWithCurrentOptions = false;
 0845                        return;
 846                    }
 7794847                }
 1299848            }
 849
 12254850            if (_elementTypeInfo?.IsCompatibleWithCurrentOptions == false ||
 12254851                _keyTypeInfo?.IsCompatibleWithCurrentOptions == false)
 0852            {
 0853                IsCompatibleWithCurrentOptions = false;
 0854                return;
 855            }
 856
 12254857            Debug.Assert(IsCompatibleWithCurrentOptions);
 858
 859            // Defines the core predicate that must be checked for every node in the type graph.
 860            bool IsCurrentNodeCompatible()
 12254861            {
 12254862                if (IsCustomized)
 0863                {
 864                    // Return false if we have detected contract customization by the user.
 0865                    return false;
 866                }
 867
 12254868                if (Options.CanUseFastPathSerializationLogic)
 12254869                {
 870                    // Simple case/backward compatibility: options uses a combination of compatible built-in converters.
 12254871                    return true;
 872                }
 873
 0874                return OriginatingResolver.IsCompatibleWithOptions(Options);
 12254875            }
 12254876        }
 877
 878        /// <summary>
 879        /// Holds the result of the above algorithm -- NB must default to true
 880        /// to establish a base case for recursive types and any JsonIgnored property types.
 881        /// </summary>
 33668882        private bool IsCompatibleWithCurrentOptions { get; set; } = true;
 883
 884        /// <summary>
 885        /// Determine if the current configuration is compatible with using a parameterized constructor.
 886        /// </summary>
 887        internal bool DetermineUsesParameterizedConstructor()
 22096888            => Converter.ConstructorIsParameterized && CreateObject is null;
 889
 890        /// <summary>
 891        /// Creates a blank <see cref="JsonTypeInfo{T}"/> instance.
 892        /// </summary>
 893        /// <typeparam name="T">The type for which contract metadata is specified.</typeparam>
 894        /// <param name="options">The <see cref="JsonSerializerOptions"/> instance the metadata is associated with.</par
 895        /// <returns>A blank <see cref="JsonTypeInfo{T}"/> instance.</returns>
 896        /// <exception cref="ArgumentNullException"><paramref name="options"/> is null.</exception>
 897        /// <remarks>
 898        /// The returned <see cref="JsonTypeInfo{T}"/> will be blank, with the exception of the
 899        /// <see cref="Converter"/> property which will be resolved either from
 900        /// <see cref="JsonSerializerOptions.Converters"/> or the built-in converters for the type.
 901        /// Any converters specified via <see cref="JsonConverterAttribute"/> on the type declaration
 902        /// will not be resolved by this method.
 903        ///
 904        /// What converter does get resolved influences the value of <see cref="Kind"/>,
 905        /// which constrains the type of metadata that can be modified in the <see cref="JsonTypeInfo"/> instance.
 906        /// </remarks>
 907        [RequiresUnreferencedCode(MetadataFactoryRequiresUnreferencedCode)]
 908        [RequiresDynamicCode(MetadataFactoryRequiresUnreferencedCode)]
 909        public static JsonTypeInfo<T> CreateJsonTypeInfo<T>(JsonSerializerOptions options)
 0910        {
 0911            ArgumentNullException.ThrowIfNull(options);
 912
 0913            JsonConverter converter = DefaultJsonTypeInfoResolver.GetConverterForType(typeof(T), options, resolveJsonCon
 0914            return new JsonTypeInfo<T>(converter, options);
 0915        }
 916
 917        /// <summary>
 918        /// Creates a blank <see cref="JsonTypeInfo"/> instance.
 919        /// </summary>
 920        /// <param name="type">The type for which contract metadata is specified.</param>
 921        /// <param name="options">The <see cref="JsonSerializerOptions"/> instance the metadata is associated with.</par
 922        /// <returns>A blank <see cref="JsonTypeInfo"/> instance.</returns>
 923        /// <exception cref="ArgumentNullException"><paramref name="type"/> or <paramref name="options"/> is null.</exce
 924        /// <exception cref="ArgumentException"><paramref name="type"/> cannot be used for serialization.</exception>
 925        /// <remarks>
 926        /// The returned <see cref="JsonTypeInfo"/> will be blank, with the exception of the
 927        /// <see cref="Converter"/> property which will be resolved either from
 928        /// <see cref="JsonSerializerOptions.Converters"/> or the built-in converters for the type.
 929        /// Any converters specified via <see cref="JsonConverterAttribute"/> on the type declaration
 930        /// will not be resolved by this method.
 931        ///
 932        /// What converter does get resolved influences the value of <see cref="Kind"/>,
 933        /// which constrains the type of metadata that can be modified in the <see cref="JsonTypeInfo"/> instance.
 934        /// </remarks>
 935        [RequiresUnreferencedCode(MetadataFactoryRequiresUnreferencedCode)]
 936        [RequiresDynamicCode(MetadataFactoryRequiresUnreferencedCode)]
 937        public static JsonTypeInfo CreateJsonTypeInfo(Type type, JsonSerializerOptions options)
 0938        {
 0939            ArgumentNullException.ThrowIfNull(type);
 0940            ArgumentNullException.ThrowIfNull(options);
 941
 0942            if (IsInvalidForSerialization(type))
 0943            {
 0944                ThrowHelper.ThrowArgumentException_CannotSerializeInvalidType(nameof(type), type, null, null);
 945            }
 946
 0947            JsonConverter converter = DefaultJsonTypeInfoResolver.GetConverterForType(type, options, resolveJsonConverte
 0948            return CreateJsonTypeInfo(type, converter, options);
 0949        }
 950
 951        [RequiresUnreferencedCode(MetadataFactoryRequiresUnreferencedCode)]
 952        [RequiresDynamicCode(MetadataFactoryRequiresUnreferencedCode)]
 953        internal static JsonTypeInfo CreateJsonTypeInfo(Type type, JsonConverter converter, JsonSerializerOptions option
 12254954        {
 955            JsonTypeInfo jsonTypeInfo;
 956
 12254957            if (converter.Type == type)
 12254958            {
 959                // For performance, avoid doing a reflection-based instantiation
 960                // if the converter type matches that of the declared type.
 12254961                jsonTypeInfo = converter.CreateJsonTypeInfo(options);
 12254962            }
 963            else
 0964            {
 0965                Type jsonTypeInfoType = typeof(JsonTypeInfo<>).MakeGenericType(type);
 0966                jsonTypeInfo = (JsonTypeInfo)jsonTypeInfoType.CreateInstanceNoWrapExceptions(
 0967                    parameterTypes: [typeof(JsonConverter), typeof(JsonSerializerOptions)],
 0968                    parameters: new object[] { converter, options })!;
 0969            }
 970
 12254971            Debug.Assert(jsonTypeInfo.Type == type);
 12254972            return jsonTypeInfo;
 12254973        }
 974
 975        /// <summary>
 976        /// Creates a blank <see cref="JsonPropertyInfo"/> instance for the current <see cref="JsonTypeInfo"/>.
 977        /// </summary>
 978        /// <param name="propertyType">The declared type for the property.</param>
 979        /// <param name="name">The property name used in JSON serialization and deserialization.</param>
 980        /// <returns>A blank <see cref="JsonPropertyInfo"/> instance.</returns>
 981        /// <exception cref="ArgumentNullException"><paramref name="propertyType"/> or <paramref name="name"/> is null.<
 982        /// <exception cref="ArgumentException"><paramref name="propertyType"/> cannot be used for serialization.</excep
 983        /// <exception cref="InvalidOperationException">The <see cref="JsonTypeInfo"/> instance has been locked for furt
 984        [RequiresUnreferencedCode(MetadataFactoryRequiresUnreferencedCode)]
 985        [RequiresDynamicCode(MetadataFactoryRequiresUnreferencedCode)]
 986        public JsonPropertyInfo CreateJsonPropertyInfo(Type propertyType, string name)
 0987        {
 0988            ArgumentNullException.ThrowIfNull(propertyType);
 0989            ArgumentNullException.ThrowIfNull(name);
 990
 0991            if (IsInvalidForSerialization(propertyType))
 0992            {
 0993                ThrowHelper.ThrowArgumentException_CannotSerializeInvalidType(nameof(propertyType), propertyType, Type, 
 994            }
 995
 0996            VerifyMutable();
 0997            JsonPropertyInfo propertyInfo = CreatePropertyUsingReflection(propertyType, declaringType: null);
 0998            propertyInfo.Name = name;
 999
 01000            return propertyInfo;
 01001        }
 1002
 1003        [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 1004        [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 1005        internal JsonPropertyInfo CreatePropertyUsingReflection(Type propertyType, Type? declaringType)
 77941006        {
 1007            JsonPropertyInfo jsonPropertyInfo;
 1008
 77941009            if (Options.TryGetTypeInfoCached(propertyType, out JsonTypeInfo? jsonTypeInfo))
 64371010            {
 1011                // If a JsonTypeInfo has already been cached for the property type,
 1012                // avoid reflection-based initialization by delegating construction
 1013                // of JsonPropertyInfo<T> construction to the property type metadata.
 64371014                jsonPropertyInfo = jsonTypeInfo.CreateJsonPropertyInfo(declaringTypeInfo: this, declaringType, Options);
 64371015            }
 1016            else
 13571017            {
 1018                // Metadata for `propertyType` has not been registered yet.
 1019                // Use reflection to instantiate the correct JsonPropertyInfo<T>
 13571020                Type propertyInfoType = typeof(JsonPropertyInfo<>).MakeGenericType(propertyType);
 13571021                jsonPropertyInfo = (JsonPropertyInfo)propertyInfoType.CreateInstanceNoWrapExceptions(
 13571022                    parameterTypes: [typeof(Type), typeof(JsonTypeInfo), typeof(JsonSerializerOptions)],
 13571023                    parameters: new object[] { declaringType ?? Type, this, Options })!;
 13571024            }
 1025
 77941026            Debug.Assert(jsonPropertyInfo.PropertyType == propertyType);
 77941027            return jsonPropertyInfo;
 77941028        }
 1029
 1030        /// <summary>
 1031        /// Creates a JsonPropertyInfo whose property type matches the type of this JsonTypeInfo instance.
 1032        /// </summary>
 1033        private protected abstract JsonPropertyInfo CreateJsonPropertyInfo(JsonTypeInfo declaringTypeInfo, Type? declari
 1034
 1035        private protected Dictionary<ParameterLookupKey, JsonParameterInfoValues>? _parameterInfoValuesIndex;
 1036
 1037        // Untyped, root-level serialization methods
 1038        internal abstract void SerializeAsObject(Utf8JsonWriter writer, object? rootValue);
 1039        internal abstract Task SerializeAsObjectAsync(PipeWriter pipeWriter, object? rootValue, int flushThreshold, Canc
 1040        internal abstract Task SerializeAsObjectAsync(Stream utf8Json, object? rootValue, CancellationToken cancellation
 1041        internal abstract Task SerializeAsObjectAsync(PipeWriter utf8Json, object? rootValue, CancellationToken cancella
 1042        internal abstract void SerializeAsObject(Stream utf8Json, object? rootValue);
 1043
 1044        // Untyped, root-level deserialization methods
 1045        internal abstract object? DeserializeAsObject(ref Utf8JsonReader reader, ref ReadStack state);
 1046        internal abstract ValueTask<object?> DeserializeAsObjectAsync(PipeReader utf8Json, CancellationToken cancellatio
 1047        internal abstract ValueTask<object?> DeserializeAsObjectAsync(Stream utf8Json, CancellationToken cancellationTok
 1048        internal abstract object? DeserializeAsObject(Stream utf8Json);
 1049
 1050        internal ref struct PropertyHierarchyResolutionState(JsonSerializerOptions options)
 1051        {
 12991052            public Dictionary<string, (JsonPropertyInfo, int index)> AddedProperties = new(options.PropertyNameCaseInsen
 1053            public Dictionary<string, JsonPropertyInfo>? IgnoredProperties;
 1054            public bool IsPropertyOrderSpecified;
 1055        }
 1056
 1057        private protected readonly struct ParameterLookupKey(Type type, string name) : IEquatable<ParameterLookupKey>
 1058        {
 224701059            public Type Type { get; } = type;
 359521060            public string Name { get; } = name;
 134821061            public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Name);
 44941062            public bool Equals(ParameterLookupKey other) => Type == other.Type && string.Equals(Name, other.Name, String
 01063            public override bool Equals([NotNullWhen(true)] object? obj) => obj is ParameterLookupKey key && Equals(key)
 1064        }
 1065
 1066        internal void ConfigureProperties()
 12991067        {
 12991068            Debug.Assert(Kind == JsonTypeInfoKind.Object);
 12991069            Debug.Assert(_propertyCache is null);
 12991070            Debug.Assert(_propertyIndex is null);
 12991071            Debug.Assert(ExtensionDataProperty is null);
 1072
 12991073            JsonPropertyInfoList properties = PropertyList;
 12991074            StringComparer comparer = Options.PropertyNameCaseInsensitive ? StringComparer.OrdinalIgnoreCase : StringCom
 12991075            Dictionary<string, JsonPropertyInfo> propertyIndex = new(properties.Count, comparer);
 12991076            List<JsonPropertyInfo> propertyCache = new(properties.Count);
 1077
 12991078            bool arePropertiesSorted = true;
 12991079            int previousPropertyOrder = int.MinValue;
 12991080            BitArray? requiredPropertiesMask = null;
 1081
 181861082            for (int i = 0; i < properties.Count; i++)
 77941083            {
 77941084                JsonPropertyInfo property = properties[i];
 77941085                Debug.Assert(property.DeclaringTypeInfo == this);
 1086
 77941087                if (property.IsExtensionData)
 01088                {
 01089                    if (UnmappedMemberHandling is JsonUnmappedMemberHandling.Disallow)
 01090                    {
 01091                        ThrowHelper.ThrowInvalidOperationException_ExtensionDataConflictsWithUnmappedMemberHandling(Type
 1092                    }
 1093
 01094                    if (ExtensionDataProperty != null)
 01095                    {
 01096                        ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(Type, typeof(Json
 1097                    }
 1098
 01099                    ExtensionDataProperty = property;
 01100                }
 1101                else
 77941102                {
 77941103                    property.PropertyIndex = i;
 1104
 77941105                    if (property.IsRequired)
 01106                    {
 01107                        (requiredPropertiesMask ??= new BitArray(properties.Count))[i] = true;
 01108                    }
 1109
 77941110                    if (arePropertiesSorted)
 77941111                    {
 77941112                        arePropertiesSorted = previousPropertyOrder <= property.Order;
 77941113                        previousPropertyOrder = property.Order;
 77941114                    }
 1115
 77941116                    if (!propertyIndex.TryAdd(property.Name, property))
 01117                    {
 01118                        ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, property.Name);
 1119                    }
 1120
 77941121                    propertyCache.Add(property);
 77941122                }
 1123
 77941124                property.Configure();
 77941125            }
 1126
 12991127            if (!arePropertiesSorted)
 01128            {
 1129                // Properties have been configured by the user and require sorting.
 01130                properties.SortProperties();
 01131                propertyCache.StableSortByKey(static propInfo => propInfo.Order);
 01132            }
 1133
 12991134            OptionalPropertiesMask = requiredPropertiesMask?.Not();
 12991135            _propertyCache = propertyCache.ToArray();
 12991136            _propertyIndex = propertyIndex;
 1137
 1138            // Override global UnmappedMemberHandling configuration
 1139            // if type specifies an extension data property.
 12991140            EffectiveUnmappedMemberHandling = UnmappedMemberHandling ??
 12991141                (ExtensionDataProperty is null
 12991142                    ? Options.UnmappedMemberHandling
 12991143                    : JsonUnmappedMemberHandling.Skip);
 12991144        }
 1145
 1146        internal void PopulateParameterInfoValues(JsonParameterInfoValues[] parameterInfoValues)
 7491147        {
 7491148            if (parameterInfoValues.Length == 0)
 01149            {
 01150                return;
 1151            }
 1152
 7491153            Dictionary<ParameterLookupKey, JsonParameterInfoValues> parameterIndex = new(parameterInfoValues.Length);
 112351154            foreach (JsonParameterInfoValues parameterInfoValue in parameterInfoValues)
 44941155            {
 44941156                ParameterLookupKey paramKey = new(parameterInfoValue.ParameterType, parameterInfoValue.Name);
 44941157                parameterIndex.TryAdd(paramKey, parameterInfoValue); // Ignore conflicts since they are reported at seri
 44941158            }
 1159
 7491160            ParameterCount = parameterInfoValues.Length;
 7491161            _parameterInfoValuesIndex = parameterIndex;
 7491162        }
 1163
 1164        internal void ResolveMatchingParameterInfo(JsonPropertyInfo propertyInfo)
 77941165        {
 77941166            Debug.Assert(
 77941167                CreateObjectWithArgs is null || _parameterInfoValuesIndex is not null,
 77941168                "Metadata with parameterized constructors must have populated parameter info metadata.");
 1169
 77941170            if (_parameterInfoValuesIndex is not { } index)
 33001171            {
 33001172                return;
 1173            }
 1174
 44941175            string propertyName = propertyInfo.MemberName ?? propertyInfo.Name;
 44941176            ParameterLookupKey propKey = new(propertyInfo.PropertyType, propertyName);
 44941177            if (index.TryGetValue(propKey, out JsonParameterInfoValues? matchingParameterInfoValues))
 44941178            {
 44941179                propertyInfo.AddJsonParameterInfo(matchingParameterInfoValues);
 44941180            }
 77941181        }
 1182
 1183        internal void ConfigureConstructorParameters()
 7491184        {
 7491185            Debug.Assert(Kind == JsonTypeInfoKind.Object);
 7491186            Debug.Assert(DetermineUsesParameterizedConstructor());
 7491187            Debug.Assert(_propertyCache is not null);
 7491188            Debug.Assert(_parameterCache is null);
 1189
 7491190            List<JsonParameterInfo> parameterCache = new(ParameterCount);
 7491191            Dictionary<ParameterLookupKey, JsonParameterInfo> parameterIndex = new(ParameterCount);
 1192
 112351193            foreach (JsonPropertyInfo propertyInfo in _propertyCache)
 44941194            {
 44941195                JsonParameterInfo? parameterInfo = propertyInfo.AssociatedParameter;
 44941196                if (parameterInfo is null)
 01197                {
 01198                    continue;
 1199                }
 1200
 44941201                string propertyName = propertyInfo.MemberName ?? propertyInfo.Name;
 44941202                ParameterLookupKey paramKey = new(propertyInfo.PropertyType, propertyName);
 44941203                if (!parameterIndex.TryAdd(paramKey, parameterInfo))
 01204                {
 1205                    // Multiple object properties cannot bind to the same constructor parameter.
 01206                    ThrowHelper.ThrowInvalidOperationException_MultiplePropertiesBindToConstructorParameters(
 01207                        Type,
 01208                        parameterInfo.Name,
 01209                        propertyInfo.Name,
 01210                        parameterIndex[paramKey].MatchingProperty.Name);
 1211                }
 1212
 44941213                parameterCache.Add(parameterInfo);
 44941214            }
 1215
 7491216            if (ExtensionDataProperty is { AssociatedParameter: not null })
 01217            {
 01218                Debug.Assert(ExtensionDataProperty.MemberName != null, "Custom property info cannot be data extension pr
 01219                ThrowHelper.ThrowInvalidOperationException_ExtensionDataCannotBindToCtorParam(ExtensionDataProperty.Memb
 1220            }
 1221
 7491222            _parameterCache = parameterCache.ToArray();
 7491223            _parameterInfoValuesIndex = null;
 7491224        }
 1225
 1226        internal static void ValidateType(Type type)
 181141227        {
 181141228            if (IsInvalidForSerialization(type))
 01229            {
 01230                ThrowHelper.ThrowInvalidOperationException_CannotSerializeInvalidType(type, declaringType: null, memberI
 1231            }
 181141232        }
 1233
 1234        internal static bool IsInvalidForSerialization(Type type)
 259081235        {
 259081236            return type == typeof(void) || type.IsPointer || type.IsByRef || IsByRefLike(type) || type.ContainsGenericPa
 259081237        }
 1238
 1239        internal void PopulatePolymorphismMetadata()
 122541240        {
 122541241            Debug.Assert(!IsReadOnly);
 1242
 122541243            JsonPolymorphismOptions? options = JsonPolymorphismOptions.CreateFromAttributeDeclarations(Type);
 122541244            if (options != null)
 01245            {
 01246                options.DeclaringTypeInfo = this;
 01247                _polymorphismOptions = options;
 01248            }
 122541249        }
 1250
 1251        internal void MapInterfaceTypesToCallbacks()
 122541252        {
 122541253            Debug.Assert(!IsReadOnly);
 1254
 122541255            if (Kind is JsonTypeInfoKind.Object or JsonTypeInfoKind.Enumerable or JsonTypeInfoKind.Dictionary)
 23011256            {
 23011257                if (typeof(IJsonOnSerializing).IsAssignableFrom(Type))
 01258                {
 01259                    OnSerializing = static obj => ((IJsonOnSerializing)obj).OnSerializing();
 01260                }
 1261
 23011262                if (typeof(IJsonOnSerialized).IsAssignableFrom(Type))
 01263                {
 01264                    OnSerialized = static obj => ((IJsonOnSerialized)obj).OnSerialized();
 01265                }
 1266
 23011267                if (typeof(IJsonOnDeserializing).IsAssignableFrom(Type))
 01268                {
 01269                    OnDeserializing = static obj => ((IJsonOnDeserializing)obj).OnDeserializing();
 01270                }
 1271
 23011272                if (typeof(IJsonOnDeserialized).IsAssignableFrom(Type))
 01273                {
 01274                    OnDeserialized = static obj => ((IJsonOnDeserialized)obj).OnDeserialized();
 01275                }
 23011276            }
 122541277        }
 1278
 1279        internal void SetCreateObjectIfCompatible(Delegate? createObject)
 122541280        {
 122541281            Debug.Assert(!IsReadOnly);
 1282
 1283            // Guard against the reflection resolver/source generator attempting to pass
 1284            // a CreateObject delegate to converters/metadata that do not support it.
 122541285            if (Converter.SupportsCreateObjectDelegate && !Converter.ConstructorIsParameterized)
 15521286            {
 15521287                SetCreateObject(createObject);
 15521288            }
 122541289        }
 1290
 1291        private static bool IsByRefLike(Type type)
 259081292        {
 1293#if NET
 259081294            return type.IsByRefLike;
 1295#else
 1296            if (!type.IsValueType)
 1297            {
 1298                return false;
 1299            }
 1300
 1301            object[] attributes = type.GetCustomAttributes(inherit: false);
 1302
 1303            for (int i = 0; i < attributes.Length; i++)
 1304            {
 1305                if (attributes[i].GetType().FullName == "System.Runtime.CompilerServices.IsByRefLikeAttribute")
 1306                {
 1307                    return true;
 1308                }
 1309            }
 1310
 1311            return false;
 1312#endif
 259081313        }
 1314
 1315        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 1316        internal bool SupportsPolymorphicDeserialization
 1317        {
 1318            get
 01319            {
 01320                Debug.Assert(IsConfigurationStarted);
 01321                return PolymorphicTypeResolver?.UsesTypeDiscriminators == true;
 01322            }
 1323        }
 1324
 1325        internal static bool IsValidExtensionDataProperty(Type propertyType)
 01326        {
 01327            return typeof(IDictionary<string, object>).IsAssignableFrom(propertyType) ||
 01328                typeof(IDictionary<string, JsonElement>).IsAssignableFrom(propertyType) ||
 01329                propertyType == typeof(IReadOnlyDictionary<string, object>) ||
 01330                propertyType == typeof(IReadOnlyDictionary<string, JsonElement>) ||
 01331                // Avoid a reference to typeof(JsonNode) to support trimming.
 01332                (propertyType.FullName == JsonObjectTypeName && ReferenceEquals(propertyType.Assembly, typeof(JsonTypeIn
 01333        }
 1334
 1335        private static JsonTypeInfoKind GetTypeInfoKind(Type type, JsonConverter converter)
 122541336        {
 122541337            if (type == typeof(object) && converter.CanBePolymorphic)
 2691338            {
 1339                // System.Object is polymorphic and will not respect Properties
 2691340                Debug.Assert(converter is ObjectConverter);
 2691341                return JsonTypeInfoKind.None;
 1342            }
 1343
 119851344            switch (converter.ConverterStrategy)
 1345            {
 96841346                case ConverterStrategy.Value: return JsonTypeInfoKind.None;
 12991347                case ConverterStrategy.Object: return JsonTypeInfoKind.Object;
 6381348                case ConverterStrategy.Enumerable: return JsonTypeInfoKind.Enumerable;
 3641349                case ConverterStrategy.Dictionary: return JsonTypeInfoKind.Dictionary;
 1350                case ConverterStrategy.None:
 01351                    Debug.Assert(converter is JsonConverterFactory);
 01352                    ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(type);
 1353                    return default;
 1354                default:
 01355                    Debug.Fail($"Unexpected class type: {converter.ConverterStrategy}");
 1356                    throw new InvalidOperationException();
 1357            }
 122541358        }
 1359
 1360        internal sealed class JsonPropertyInfoList : ConfigurationList<JsonPropertyInfo>
 1361        {
 1362            private readonly JsonTypeInfo _jsonTypeInfo;
 1363
 12991364            public JsonPropertyInfoList(JsonTypeInfo jsonTypeInfo)
 12991365            {
 12991366                _jsonTypeInfo = jsonTypeInfo;
 12991367            }
 1368
 01369            public override bool IsReadOnly => _jsonTypeInfo._properties == this && _jsonTypeInfo.IsReadOnly || _jsonTyp
 1370            protected override void OnCollectionModifying()
 77941371            {
 77941372                if (_jsonTypeInfo._properties == this)
 77941373                {
 77941374                    _jsonTypeInfo.VerifyMutable();
 77941375                }
 1376
 77941377                if (_jsonTypeInfo.Kind != JsonTypeInfoKind.Object)
 01378                {
 01379                    ThrowHelper.ThrowInvalidOperationException_JsonTypeInfoOperationNotPossibleForKind(_jsonTypeInfo.Kin
 1380                }
 77941381            }
 1382
 1383            protected override void ValidateAddedValue(JsonPropertyInfo item)
 77941384            {
 77941385                item.EnsureChildOf(_jsonTypeInfo);
 77941386            }
 1387
 1388            public void SortProperties()
 01389            {
 01390                _list.StableSortByKey(static propInfo => propInfo.Order);
 01391            }
 1392
 1393            /// <summary>
 1394            /// Used by the built-in resolvers to add property metadata applying conflict resolution.
 1395            /// </summary>
 1396            public void AddPropertyWithConflictResolution(JsonPropertyInfo jsonPropertyInfo, ref PropertyHierarchyResolu
 77941397            {
 77941398                Debug.Assert(!_jsonTypeInfo.IsConfigured);
 77941399                Debug.Assert(jsonPropertyInfo.MemberName != null, "MemberName can be null in custom JsonPropertyInfo ins
 1400
 1401                // Algorithm should be kept in sync with the Roslyn equivalent in JsonSourceGenerator.Parser.cs
 77941402                string memberName = jsonPropertyInfo.MemberName;
 1403
 77941404                if (state.AddedProperties.TryAdd(jsonPropertyInfo.Name, (jsonPropertyInfo, Count)))
 77941405                {
 77941406                    Add(jsonPropertyInfo);
 77941407                    state.IsPropertyOrderSpecified |= jsonPropertyInfo.Order != 0;
 77941408                }
 1409                else
 01410                {
 1411                    // The JsonPropertyNameAttribute or naming policy resulted in a collision.
 01412                    (JsonPropertyInfo other, int index) = state.AddedProperties[jsonPropertyInfo.Name];
 1413
 01414                    if (other.IsIgnored)
 01415                    {
 1416                        // Overwrite previously cached property since it has [JsonIgnore].
 01417                        state.AddedProperties[jsonPropertyInfo.Name] = (jsonPropertyInfo, index);
 01418                        this[index] = jsonPropertyInfo;
 01419                        state.IsPropertyOrderSpecified |= jsonPropertyInfo.Order != 0;
 01420                    }
 1421                    else
 01422                    {
 01423                        bool ignoreCurrentProperty =
 01424                            // Does the current property have `JsonIgnoreAttribute`?
 01425                            jsonPropertyInfo.IsIgnored ||
 01426                            // Is the current property hidden by the previously cached property
 01427                            // (with `new` keyword, or by overriding)?
 01428                            jsonPropertyInfo.IsOverriddenOrShadowedBy(other) ||
 01429                            // Was a property with the same CLR name ignored? That property hid the current property,
 01430                            // thus, if it was ignored, the current property should be ignored too.
 01431                            (state.IgnoredProperties?.TryGetValue(memberName, out JsonPropertyInfo? ignored) == true && 
 1432
 01433                        if (!ignoreCurrentProperty)
 01434                        {
 01435                            ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(_jsonTypeInfo.Type
 1436                        }
 01437                    }
 01438                }
 1439
 77941440                if (jsonPropertyInfo.IsIgnored)
 01441                {
 01442                    (state.IgnoredProperties ??= new())[memberName] = jsonPropertyInfo;
 01443                }
 77941444            }
 1445        }
 1446
 1447        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
 01448        private string DebuggerDisplay => $"Type = {Type.Name}, Kind = {Kind}";
 1449    }
 1450}

Methods/Properties

.cctor()
ParameterCount()
ParameterCache()
UsesParameterizedConstructor()
PropertyCache()
PropertyIndex()
.ctor(System.Type,System.Text.Json.Serialization.JsonConverter,System.Text.Json.JsonSerializerOptions)
GetProperty(System.ReadOnlySpan`1<System.Byte>,System.Text.Json.ReadStackFrame&,System.Byte[]&)
UpdateUtf8PropertyCache(System.Text.Json.ReadStackFrame&)
OptionalPropertiesMask()
ShouldTrackRequiredProperties()
.ctor(System.Type,System.Text.Json.Serialization.JsonConverter,System.Text.Json.JsonSerializerOptions)
ElementType()
KeyType()
CreateObject()
CreateObject(System.Func`1<System.Object>)
CreateObjectForExtensionDataProperty()
OnSerializing()
OnSerializing(System.Action`1<System.Object>)
OnSerialized()
OnSerialized(System.Action`1<System.Object>)
OnDeserializing()
OnDeserializing(System.Action`1<System.Object>)
OnDeserialized()
OnDeserialized(System.Action`1<System.Object>)
Properties()
PropertyList()
tePropertyList()
SourceGenDelayedPropertyInitializer(System.Func`2<System.Text.Json.Serialization.JsonSerializerContext,System.Text.Json.Serialization.Metadata.JsonPropertyInfo[]>)
PolymorphismOptions()
PolymorphismOptions(System.Text.Json.Serialization.Metadata.JsonPolymorphismOptions)
IsReadOnly()
MakeReadOnly()
CreateObjectWithArgs()
AddMethodDelegate()
ExtensionDataProperty()
PolymorphicTypeResolver()
HasSerializeHandler()
CanUseSerializeHandler()
PropertyMetadataSerializationNotSupported()
IsNullable()
ValidateCanBeUsedForPropertyMetadataSerialization()
ElementTypeInfo()
ElementTypeInfo(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
KeyTypeInfo()
KeyTypeInfo(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
Options()
Type()
Converter()
Kind()
PropertyInfoForTypeInfo()
NumberHandling()
NumberHandling(System.Nullable`1<System.Text.Json.Serialization.JsonNumberHandling>)
EffectiveNumberHandling()
UnmappedMemberHandling()
UnmappedMemberHandling(System.Nullable`1<System.Text.Json.Serialization.JsonUnmappedMemberHandling>)
EffectiveUnmappedMemberHandling()
PreferredPropertyObjectCreationHandling()
PreferredPropertyObjectCreationHandling(System.Nullable`1<System.Text.Json.Serialization.JsonObjectCreationHandling>)
OriginatingResolver()
OriginatingResolver(System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver)
ConstructorAttributeProvider()
ConstructorAttributeProvider(System.Reflection.ICustomAttributeProvider)
VerifyMutable()
IsCustomized()
IsConfigured()
IsConfigurationStarted()
EnsureConfigured()
ConfigureSynchronized()
Configure()
AncestorPolymorphicType()
DetermineIsCompatibleWithCurrentOptions()
IsCurrentNodeCompatible()
IsCompatibleWithCurrentOptions()
DetermineUsesParameterizedConstructor()
CreateJsonTypeInfo(System.Text.Json.JsonSerializerOptions)
CreateJsonTypeInfo(System.Type,System.Text.Json.JsonSerializerOptions)
CreateJsonTypeInfo(System.Type,System.Text.Json.Serialization.JsonConverter,System.Text.Json.JsonSerializerOptions)
CreateJsonPropertyInfo(System.Type,System.String)
CreatePropertyUsingReflection(System.Type,System.Type)
.ctor(System.Text.Json.JsonSerializerOptions)
Type()
Name()
GetHashCode()
Equals(System.Text.Json.Serialization.Metadata.JsonTypeInfo/ParameterLookupKey)
Equals(System.Object)
ConfigureProperties()
PopulateParameterInfoValues(System.Text.Json.Serialization.Metadata.JsonParameterInfoValues[])
ResolveMatchingParameterInfo(System.Text.Json.Serialization.Metadata.JsonPropertyInfo)
ConfigureConstructorParameters()
ValidateType(System.Type)
IsInvalidForSerialization(System.Type)
PopulatePolymorphismMetadata()
MapInterfaceTypesToCallbacks()
SetCreateObjectIfCompatible(System.Delegate)
IsByRefLike(System.Type)
SupportsPolymorphicDeserialization()
IsValidExtensionDataProperty(System.Type)
GetTypeInfoKind(System.Type,System.Text.Json.Serialization.JsonConverter)
.ctor(System.Text.Json.Serialization.Metadata.JsonTypeInfo)
IsReadOnly()
OnCollectionModifying()
ValidateAddedValue(System.Text.Json.Serialization.Metadata.JsonPropertyInfo)
SortProperties()
AddPropertyWithConflictResolution(System.Text.Json.Serialization.Metadata.JsonPropertyInfo,System.Text.Json.Serialization.Metadata.JsonTypeInfo/PropertyHierarchyResolutionState&)
DebuggerDisplay()