< Summary

Line coverage
21%
Covered lines: 35
Uncovered lines: 125
Coverable lines: 160
Total lines: 423
Line coverage: 21.8%
Branch coverage
4%
Covered branches: 3
Total branches: 64
Branch coverage: 4.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\JsonConverter.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.Diagnostics;
 5using System.Diagnostics.CodeAnalysis;
 6using System.Reflection;
 7using System.Text.Json.Schema;
 8using System.Text.Json.Serialization.Converters;
 9using System.Text.Json.Serialization.Metadata;
 10
 11namespace System.Text.Json.Serialization
 12{
 13    /// <summary>
 14    /// Converts an object or value to or from JSON.
 15    /// </summary>
 16    public abstract partial class JsonConverter
 17    {
 315218        internal JsonConverter()
 315219        {
 315220            IsInternalConverter = GetType().Assembly == typeof(JsonConverter).Assembly;
 315221            ConverterStrategy = GetDefaultConverterStrategy();
 315222        }
 23
 24        /// <summary>
 25        /// Gets the type being converted by the current converter instance.
 26        /// </summary>
 27        /// <remarks>
 28        /// For instances of type <see cref="JsonConverter{T}"/> returns typeof(T),
 29        /// and for instances of type <see cref="JsonConverterFactory"/> returns <see langword="null" />.
 30        /// </remarks>
 31        public abstract Type? Type { get; }
 32
 33        /// <summary>
 34        /// Determines whether the type can be converted.
 35        /// </summary>
 36        /// <param name="typeToConvert">The type is checked as to whether it can be converted.</param>
 37        /// <returns>True if the type can be converted, false otherwise.</returns>
 38        public abstract bool CanConvert(Type typeToConvert);
 39
 40        internal ConverterStrategy ConverterStrategy
 41        {
 7313942            get => _converterStrategy;
 43            init
 315244            {
 315245                CanUseDirectReadOrWrite = value == ConverterStrategy.Value && IsInternalConverter;
 315246                RequiresReadAhead = value == ConverterStrategy.Value;
 315247                _converterStrategy = value;
 315248            }
 49        }
 50
 51        private ConverterStrategy _converterStrategy;
 52
 53        /// <summary>
 54        /// Invoked by the base contructor to populate the initial value of the <see cref="ConverterStrategy"/> property
 55        /// Used for declaring the default strategy for specific converter hierarchies without explicitly setting in a c
 56        /// </summary>
 57        private protected abstract ConverterStrategy GetDefaultConverterStrategy();
 58
 59        /// <summary>
 60        /// Indicates that the converter can consume the <see cref="JsonTypeInfo.CreateObject"/> delegate.
 61        /// Needed because certain collection converters cannot support arbitrary delegates.
 62        /// TODO remove once https://github.com/dotnet/runtime/pull/73395/ and
 63        /// https://github.com/dotnet/runtime/issues/71944 have been addressed.
 64        /// </summary>
 995365        internal virtual bool SupportsCreateObjectDelegate => false;
 66
 67        /// <summary>
 68        /// Indicates that the converter is compatible with <see cref="JsonObjectCreationHandling.Populate"/>.
 69        /// </summary>
 070        internal virtual bool CanPopulate => false;
 71
 72        /// <summary>
 73        /// Can direct Read or Write methods be called (for performance).
 74        /// </summary>
 315275        internal bool CanUseDirectReadOrWrite { get; set; }
 76
 77        /// <summary>
 78        /// The converter supports writing and reading metadata.
 79        /// </summary>
 080        internal virtual bool CanHaveMetadata => false;
 81
 82        /// <summary>
 83        /// The converter supports polymorphic writes; only reserved for System.Object types.
 84        /// </summary>
 264085        internal bool CanBePolymorphic { get; init; }
 86
 87        /// <summary>
 88        /// The serializer must read ahead all contents of the next JSON value
 89        /// before calling into the converter for deserialization.
 90        /// </summary>
 5929991        internal bool RequiresReadAhead { get; private protected set; }
 92
 93        /// <summary>
 94        /// Whether the converter is a special root-level value streaming converter.
 95        /// </summary>
 5592496        internal bool IsRootLevelMultiContentStreamingConverter { get; init; }
 97
 98        /// <summary>
 99        /// Used to support JsonObject as an extension property in a loosely-typed, trimmable manner.
 100        /// </summary>
 101        internal virtual void ReadElementAndSetProperty(
 102            object obj,
 103            string propertyName,
 104            ref Utf8JsonReader reader,
 105            JsonSerializerOptions options,
 106            scoped ref ReadStack state)
 0107        {
 0108            Debug.Fail("Should not be reachable.");
 109
 110            throw new InvalidOperationException();
 111        }
 112
 113        internal virtual JsonTypeInfo CreateJsonTypeInfo(JsonSerializerOptions options)
 0114        {
 0115            Debug.Fail("Should not be reachable.");
 116
 117            throw new InvalidOperationException();
 118        }
 119
 120        internal JsonConverter<TTarget> CreateCastingConverter<TTarget>()
 12254121        {
 12254122            Debug.Assert(this is not JsonConverterFactory);
 123
 12254124            if (this is JsonConverter<TTarget> conv)
 12254125            {
 12254126                return conv;
 127            }
 128            else
 0129            {
 0130                JsonSerializerOptions.CheckConverterNullabilityIsSameAsPropertyType(this, typeof(TTarget));
 131
 132                // Avoid layering casting converters by consulting any source converters directly.
 0133                return
 0134                    SourceConverterForCastingConverter?.CreateCastingConverter<TTarget>()
 0135                    ?? new CastingConverter<TTarget>(this);
 136            }
 12254137        }
 138
 139        /// <summary>
 140        /// Tracks whether the JsonConverter&lt;T&gt;.HandleNull property has been overridden by a derived converter.
 141        /// </summary>
 3441142        internal bool UsesDefaultHandleNull { get; private protected set; }
 143
 144        /// <summary>
 145        /// Does the converter want to be called when reading null tokens.
 146        /// When JsonConverter&lt;T&gt;.HandleNull isn't overridden this can still be true for non-nullable structs.
 147        /// </summary>
 573148        internal bool HandleNullOnRead { get; private protected init; }
 149
 150        /// <summary>
 151        /// Does the converter want to be called for null values.
 152        /// Should always match the precise value of the JsonConverter&lt;T&gt;.HandleNull virtual property.
 153        /// </summary>
 573154        internal bool HandleNullOnWrite { get; private protected init; }
 155
 156        /// <summary>
 157        /// Set if this converter is itself a casting converter.
 158        /// </summary>
 0159        internal virtual JsonConverter? SourceConverterForCastingConverter => null;
 160
 11252161        internal virtual Type? ElementType => null;
 162
 11890163        internal virtual Type? KeyType => null;
 164
 1299165        internal virtual JsonConverter? NullableElementConverter => null;
 166
 167        /// <summary>
 168        /// Cached value of TypeToConvert.IsValueType, which is an expensive call.
 169        /// </summary>
 10137170        internal bool IsValueType { get; init; }
 171
 172        /// <summary>
 173        /// Whether the converter is built-in.
 174        /// </summary>
 29394175        internal bool IsInternalConverter { get; init; }
 176
 177        /// <summary>
 178        /// Whether the converter is built-in and handles a number type.
 179        /// </summary>
 39086180        internal bool IsInternalConverterForNumberType { get; init; }
 181
 182        /// <summary>
 183        /// Whether the converter handles collection deserialization by converting from
 184        /// an intermediate buffer such as immutable collections, arrays or memory types.
 185        /// Used in conjunction with <see cref="JsonCollectionConverter{TCollection, TElement}.ConvertCollection(ref Rea
 186        /// </summary>
 0187        internal virtual bool IsConvertibleCollection => false;
 188
 189        internal static bool ShouldFlush(ref WriteStack state, Utf8JsonWriter writer)
 0190        {
 0191            Debug.Assert(state.FlushThreshold == 0 || (state.PipeWriter is { CanGetUnflushedBytes: true }),
 0192                "ShouldFlush should only be called by resumable serializers, all of which use the PipeWriter abstraction
 193            // If surpassed flush threshold then return true which will flush stream.
 0194            if (state.PipeWriter is { } pipeWriter)
 0195            {
 0196                return state.FlushThreshold > 0 && pipeWriter.UnflushedBytes > state.FlushThreshold - writer.BytesPendin
 197            }
 198
 0199            return false;
 0200        }
 201
 202        internal abstract object? ReadAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions opti
 203        internal abstract bool OnTryReadAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions op
 204        internal abstract bool TryReadAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions opti
 205        internal abstract object? ReadAsPropertyNameAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializ
 206        internal abstract object? ReadAsPropertyNameCoreAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSeri
 207        internal abstract object? ReadNumberWithCustomHandlingAsObject(ref Utf8JsonReader reader, JsonNumberHandling han
 208
 209        internal abstract void WriteAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions options);
 210        internal abstract bool OnTryWriteAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions options, r
 211        internal abstract bool TryWriteAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions options, ref
 212        internal abstract void WriteAsPropertyNameAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions o
 213        internal abstract void WriteAsPropertyNameCoreAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptio
 214        internal abstract void WriteNumberWithCustomHandlingAsObject(Utf8JsonWriter writer, object? value, JsonNumberHan
 215
 216        /// <summary>
 217        /// Gets a schema from the type being converted
 218        /// </summary>
 0219        internal virtual JsonSchema? GetSchema(JsonNumberHandling numberHandling) => null;
 220
 221        // Whether a type (ConverterStrategy.Object) is deserialized using a parameterized constructor.
 18007222        internal virtual bool ConstructorIsParameterized { get; }
 223
 18948224        internal ConstructorInfo? ConstructorInfo { get; set; }
 225
 226        /// <summary>
 227        /// Used for hooking custom configuration to a newly created associated JsonTypeInfo instance.
 228        /// </summary>
 23970229        internal virtual void ConfigureJsonTypeInfo(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options) { }
 230
 231        /// <summary>
 232        /// Additional reflection-specific configuration required by certain collection converters.
 233        /// </summary>
 234        [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
 235        [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
 23010236        internal virtual void ConfigureJsonTypeInfoUsingReflection(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions opti
 237    }
 238}

C:\h\w\B31A098C\w\BB5A0A33\e\runtime-utils\Runner\runtime\src\libraries\System.Text.Json\src\System\Text\Json\Serialization\JsonConverter.MetadataHandling.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.Diagnostics;
 5using System.Text.Json.Serialization.Metadata;
 6
 7namespace System.Text.Json.Serialization
 8{
 9    public partial class JsonConverter
 10    {
 11        /// <summary>
 12        /// Initializes the state for polymorphic cases and returns the appropriate derived converter.
 13        /// </summary>
 14        internal JsonConverter? ResolvePolymorphicConverter(JsonTypeInfo jsonTypeInfo, ref ReadStack state)
 015        {
 016            Debug.Assert(!IsValueType);
 017            Debug.Assert(CanHaveMetadata);
 018            Debug.Assert((state.Current.MetadataPropertyNames & MetadataPropertyName.Type) != 0);
 019            Debug.Assert(state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntry
 020            Debug.Assert(jsonTypeInfo.PolymorphicTypeResolver?.UsesTypeDiscriminators == true);
 21
 022            JsonConverter? polymorphicConverter = null;
 23
 024            switch (state.Current.PolymorphicSerializationState)
 25            {
 26                case PolymorphicSerializationState.None:
 027                    Debug.Assert(!state.IsContinuation);
 028                    Debug.Assert(state.PolymorphicTypeDiscriminator != null);
 29
 030                    PolymorphicTypeResolver resolver = jsonTypeInfo.PolymorphicTypeResolver;
 031                    if (resolver.TryGetDerivedJsonTypeInfo(state.PolymorphicTypeDiscriminator, out JsonTypeInfo? resolve
 032                    {
 033                        Debug.Assert(Type!.IsAssignableFrom(resolvedType.Type));
 34
 035                        polymorphicConverter = state.InitializePolymorphicReEntry(resolvedType);
 036                        if (!polymorphicConverter.CanHaveMetadata)
 037                        {
 038                            ThrowHelper.ThrowNotSupportedException_DerivedConverterDoesNotSupportMetadata(resolvedType.T
 39                        }
 040                    }
 41                    else
 042                    {
 043                        state.Current.PolymorphicSerializationState = PolymorphicSerializationState.PolymorphicReEntryNo
 044                    }
 45
 046                    state.PolymorphicTypeDiscriminator = null;
 047                    break;
 48
 49                case PolymorphicSerializationState.PolymorphicReEntrySuspended:
 050                    polymorphicConverter = state.ResumePolymorphicReEntry();
 051                    Debug.Assert(Type!.IsAssignableFrom(polymorphicConverter.Type));
 052                    break;
 53
 54                case PolymorphicSerializationState.PolymorphicReEntryNotFound:
 055                    Debug.Assert(state.Current.PolymorphicJsonTypeInfo is null);
 056                    break;
 57
 58                default:
 059                    Debug.Fail("Unexpected PolymorphicSerializationState.");
 60                    break;
 61            }
 62
 063            return polymorphicConverter;
 064        }
 65
 66        /// <summary>
 67        /// Initializes the state for polymorphic cases and returns the appropriate derived converter.
 68        /// </summary>
 69        internal JsonConverter? ResolvePolymorphicConverter(object value, JsonTypeInfo jsonTypeInfo, JsonSerializerOptio
 070        {
 071            Debug.Assert(!IsValueType);
 072            Debug.Assert(value != null && Type!.IsAssignableFrom(value.GetType()));
 073            Debug.Assert(CanBePolymorphic || jsonTypeInfo.PolymorphicTypeResolver != null);
 074            Debug.Assert(state.PolymorphicTypeDiscriminator is null);
 75
 076            JsonConverter? polymorphicConverter = null;
 77
 078            switch (state.Current.PolymorphicSerializationState)
 79            {
 80                case PolymorphicSerializationState.None:
 081                    Debug.Assert(!state.IsContinuation);
 82
 083                    Type runtimeType = value.GetType();
 84
 085                    if (CanBePolymorphic && runtimeType != Type)
 086                    {
 087                        Debug.Assert(Type == typeof(object));
 088                        jsonTypeInfo = state.Current.InitializePolymorphicReEntry(runtimeType, options);
 089                        polymorphicConverter = jsonTypeInfo.Converter;
 090                    }
 91
 092                    if (jsonTypeInfo.PolymorphicTypeResolver is PolymorphicTypeResolver resolver)
 093                    {
 094                        Debug.Assert(jsonTypeInfo.Converter.CanHaveMetadata);
 95
 096                        if (resolver.TryGetDerivedJsonTypeInfo(runtimeType, out JsonTypeInfo? derivedJsonTypeInfo, out o
 097                        {
 098                            polymorphicConverter = state.Current.InitializePolymorphicReEntry(derivedJsonTypeInfo);
 99
 0100                            if (typeDiscriminator is not null)
 0101                            {
 0102                                if (!polymorphicConverter.CanHaveMetadata)
 0103                                {
 0104                                    ThrowHelper.ThrowNotSupportedException_DerivedConverterDoesNotSupportMetadata(derive
 105                                }
 106
 0107                                state.PolymorphicTypeDiscriminator = typeDiscriminator;
 0108                                state.PolymorphicTypeResolver = resolver;
 0109                            }
 0110                        }
 0111                    }
 112
 0113                    if (polymorphicConverter is null)
 0114                    {
 0115                        state.Current.PolymorphicSerializationState = PolymorphicSerializationState.PolymorphicReEntryNo
 0116                    }
 117
 0118                    break;
 119
 120                case PolymorphicSerializationState.PolymorphicReEntrySuspended:
 0121                    Debug.Assert(state.IsContinuation);
 0122                    polymorphicConverter = state.Current.ResumePolymorphicReEntry();
 0123                    Debug.Assert(Type.IsAssignableFrom(polymorphicConverter.Type));
 0124                    break;
 125
 126                case PolymorphicSerializationState.PolymorphicReEntryNotFound:
 0127                    Debug.Assert(state.IsContinuation);
 0128                    break;
 129
 130                default:
 0131                    Debug.Fail("Unexpected PolymorphicSerializationState.");
 132                    break;
 133            }
 134
 0135            return polymorphicConverter;
 0136        }
 137
 138        internal bool TryHandleSerializedObjectReference(Utf8JsonWriter writer, object value, JsonSerializerOptions opti
 0139        {
 0140            Debug.Assert(!IsValueType);
 0141            Debug.Assert(!state.IsContinuation);
 0142            Debug.Assert(value != null);
 143
 0144            switch (options.ReferenceHandlingStrategy)
 145            {
 146                case JsonKnownReferenceHandler.IgnoreCycles:
 0147                    ReferenceResolver resolver = state.ReferenceResolver;
 0148                    if (resolver.ContainsReferenceForCycleDetection(value))
 0149                    {
 0150                        writer.WriteNullValue();
 151
 0152                        if (polymorphicConverter is not null)
 0153                        {
 154                            // Clear out any polymorphic state.
 0155                            state.PolymorphicTypeDiscriminator = null;
 0156                            state.PolymorphicTypeResolver = null;
 0157                        }
 0158                        return true;
 159                    }
 160
 0161                    resolver.PushReferenceForCycleDetection(value);
 162                    // WriteStack reuses root-level stack frames for its children as a performance optimization;
 163                    // we want to avoid writing any data for the root-level object to avoid corrupting the stack.
 164                    // This is fine since popping the root object at the end of serialization is not essential.
 0165                    state.Current.IsPushedReferenceForCycleDetection = state.CurrentDepth > 0;
 0166                    break;
 167
 168                case JsonKnownReferenceHandler.Preserve:
 0169                    bool canHaveIdMetadata = polymorphicConverter?.CanHaveMetadata ?? CanHaveMetadata;
 0170                    if (canHaveIdMetadata && JsonSerializer.TryGetReferenceForValue(value, ref state, writer))
 0171                    {
 172                        // We found a repeating reference and wrote the relevant metadata; serialization complete.
 0173                        return true;
 174                    }
 0175                    break;
 176
 177                default:
 0178                    Debug.Fail("Unexpected ReferenceHandlingStrategy.");
 179                    break;
 180            }
 181
 0182            return false;
 0183        }
 184    }
 185}

Methods/Properties

.ctor()
ConverterStrategy()
ConverterStrategy(System.Text.Json.ConverterStrategy)
SupportsCreateObjectDelegate()
CanPopulate()
CanUseDirectReadOrWrite()
CanHaveMetadata()
CanBePolymorphic()
RequiresReadAhead()
IsRootLevelMultiContentStreamingConverter()
ReadElementAndSetProperty(System.Object,System.String,System.Text.Json.Utf8JsonReader&,System.Text.Json.JsonSerializerOptions,System.Text.Json.ReadStack&)
CreateJsonTypeInfo(System.Text.Json.JsonSerializerOptions)
CreateCastingConverter()
UsesDefaultHandleNull()
HandleNullOnRead()
HandleNullOnWrite()
SourceConverterForCastingConverter()
ElementType()
KeyType()
NullableElementConverter()
IsValueType()
IsInternalConverter()
IsInternalConverterForNumberType()
IsConvertibleCollection()
ShouldFlush(System.Text.Json.WriteStack&,System.Text.Json.Utf8JsonWriter)
GetSchema(System.Text.Json.Serialization.JsonNumberHandling)
ConstructorIsParameterized()
ConstructorInfo()
ConfigureJsonTypeInfo(System.Text.Json.Serialization.Metadata.JsonTypeInfo,System.Text.Json.JsonSerializerOptions)
ConfigureJsonTypeInfoUsingReflection(System.Text.Json.Serialization.Metadata.JsonTypeInfo,System.Text.Json.JsonSerializerOptions)
ResolvePolymorphicConverter(System.Text.Json.Serialization.Metadata.JsonTypeInfo,System.Text.Json.ReadStack&)
ResolvePolymorphicConverter(System.Object,System.Text.Json.Serialization.Metadata.JsonTypeInfo,System.Text.Json.JsonSerializerOptions,System.Text.Json.WriteStack&)
TryHandleSerializedObjectReference(System.Text.Json.Utf8JsonWriter,System.Object,System.Text.Json.JsonSerializerOptions,System.Text.Json.Serialization.JsonConverter,System.Text.Json.WriteStack&)