| | | 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 | | |
| | | 4 | | using System.Diagnostics; |
| | | 5 | | using System.Text.Json.Nodes; |
| | | 6 | | using System.Text.Json.Schema; |
| | | 7 | | using System.Text.Json.Serialization.Metadata; |
| | | 8 | | |
| | | 9 | | namespace System.Text.Json.Serialization.Converters |
| | | 10 | | { |
| | | 11 | | internal abstract class ObjectConverter : JsonConverter<object?> |
| | | 12 | | { |
| | | 13 | | private protected override ConverterStrategy GetDefaultConverterStrategy() => ConverterStrategy.Object; |
| | | 14 | | |
| | | 15 | | public ObjectConverter() |
| | | 16 | | { |
| | | 17 | | CanBePolymorphic = true; |
| | | 18 | | } |
| | | 19 | | |
| | | 20 | | public sealed override object ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOp |
| | | 21 | | { |
| | | 22 | | ThrowHelper.ThrowNotSupportedException_DictionaryKeyTypeNotSupported(Type, this); |
| | | 23 | | return null!; |
| | | 24 | | } |
| | | 25 | | |
| | | 26 | | internal sealed override object ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial |
| | | 27 | | { |
| | | 28 | | ThrowHelper.ThrowNotSupportedException_DictionaryKeyTypeNotSupported(Type, this); |
| | | 29 | | return null!; |
| | | 30 | | } |
| | | 31 | | |
| | | 32 | | public sealed override void Write(Utf8JsonWriter writer, object? value, JsonSerializerOptions options) |
| | | 33 | | { |
| | | 34 | | if (value is null) |
| | | 35 | | { |
| | | 36 | | writer.WriteNullValue(); |
| | | 37 | | return; |
| | | 38 | | } |
| | | 39 | | |
| | | 40 | | writer.WriteStartObject(); |
| | | 41 | | writer.WriteEndObject(); |
| | | 42 | | } |
| | | 43 | | |
| | | 44 | | public sealed override void WriteAsPropertyName(Utf8JsonWriter writer, object value, JsonSerializerOptions optio |
| | | 45 | | { |
| | | 46 | | WriteAsPropertyNameCore(writer, value, options, isWritingExtensionDataProperty: false); |
| | | 47 | | } |
| | | 48 | | |
| | | 49 | | internal sealed override void WriteAsPropertyNameCore(Utf8JsonWriter writer, object value, JsonSerializerOptions |
| | | 50 | | { |
| | | 51 | | ArgumentNullException.ThrowIfNull(value); |
| | | 52 | | |
| | | 53 | | Type runtimeType = value.GetType(); |
| | | 54 | | if (runtimeType == Type) |
| | | 55 | | { |
| | | 56 | | ThrowHelper.ThrowNotSupportedException_DictionaryKeyTypeNotSupported(runtimeType, this); |
| | | 57 | | } |
| | | 58 | | |
| | | 59 | | JsonConverter runtimeConverter = options.GetConverterInternal(runtimeType); |
| | | 60 | | runtimeConverter.WriteAsPropertyNameCoreAsObject(writer, value, options, isWritingExtensionDataProperty); |
| | | 61 | | } |
| | | 62 | | } |
| | | 63 | | |
| | | 64 | | /// <summary> |
| | | 65 | | /// Defines an object converter that only supports (polymorphic) serialization but not deserialization. |
| | | 66 | | /// This is done to avoid rooting dependencies to JsonNode/JsonElement necessary to drive object deserialization. |
| | | 67 | | /// Source generator users need to explicitly declare support for object so that the derived converter gets used. |
| | | 68 | | /// </summary> |
| | | 69 | | internal sealed class SlimObjectConverter : ObjectConverter |
| | | 70 | | { |
| | | 71 | | // Keep track of the originating resolver so that the converter surfaces |
| | | 72 | | // an accurate error message whenever deserialization is attempted. |
| | | 73 | | private readonly IJsonTypeInfoResolver _originatingResolver; |
| | | 74 | | |
| | | 75 | | public SlimObjectConverter(IJsonTypeInfoResolver originatingResolver) |
| | | 76 | | => _originatingResolver = originatingResolver; |
| | | 77 | | |
| | | 78 | | public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
| | | 79 | | { |
| | | 80 | | ThrowHelper.ThrowNotSupportedException_NoMetadataForType(typeToConvert, _originatingResolver); |
| | | 81 | | return null; |
| | | 82 | | } |
| | | 83 | | } |
| | | 84 | | |
| | | 85 | | /// <summary> |
| | | 86 | | /// Defines an object converter that supports deserialization via JsonElement/JsonNode representations. |
| | | 87 | | /// Used as the default in reflection or if object is declared in the JsonSerializerContext type graph. |
| | | 88 | | /// </summary> |
| | | 89 | | internal sealed class DefaultObjectConverter : ObjectConverter |
| | | 90 | | { |
| | 1 | 91 | | public DefaultObjectConverter() |
| | 1 | 92 | | { |
| | | 93 | | // JsonElement/JsonNode parsing does not support async; force read ahead for now. |
| | 1 | 94 | | RequiresReadAhead = true; |
| | 1 | 95 | | } |
| | | 96 | | |
| | | 97 | | public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
| | 0 | 98 | | { |
| | 0 | 99 | | if (options.UnknownTypeHandling == JsonUnknownTypeHandling.JsonElement) |
| | 0 | 100 | | { |
| | 0 | 101 | | return JsonElement.ParseValue(ref reader, options.AllowDuplicateProperties); |
| | | 102 | | } |
| | | 103 | | |
| | 0 | 104 | | Debug.Assert(options.UnknownTypeHandling == JsonUnknownTypeHandling.JsonNode); |
| | 0 | 105 | | return JsonNodeConverter.Instance.Read(ref reader, typeToConvert, options); |
| | 0 | 106 | | } |
| | | 107 | | |
| | | 108 | | internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, s |
| | 634 | 109 | | { |
| | | 110 | | object? referenceValue; |
| | | 111 | | |
| | 634 | 112 | | if (options.UnknownTypeHandling == JsonUnknownTypeHandling.JsonElement) |
| | 634 | 113 | | { |
| | 634 | 114 | | JsonElement element = JsonElement.ParseValue(ref reader, options.AllowDuplicateProperties); |
| | | 115 | | |
| | | 116 | | // Edge case where we want to lookup for a reference when parsing into typeof(object) |
| | 428 | 117 | | if (options.ReferenceHandlingStrategy == JsonKnownReferenceHandler.Preserve && |
| | 428 | 118 | | JsonSerializer.TryHandleReferenceFromJsonElement(ref reader, ref state, element, out referenceValue) |
| | 0 | 119 | | { |
| | 0 | 120 | | value = referenceValue; |
| | 0 | 121 | | } |
| | | 122 | | else |
| | 428 | 123 | | { |
| | 428 | 124 | | value = element; |
| | 428 | 125 | | } |
| | | 126 | | |
| | 428 | 127 | | return true; |
| | | 128 | | } |
| | | 129 | | |
| | 0 | 130 | | Debug.Assert(options.UnknownTypeHandling == JsonUnknownTypeHandling.JsonNode); |
| | | 131 | | |
| | 0 | 132 | | JsonNode? node = JsonNodeConverter.Instance.Read(ref reader, typeToConvert, options); |
| | | 133 | | |
| | 0 | 134 | | if (options.ReferenceHandlingStrategy == JsonKnownReferenceHandler.Preserve && |
| | 0 | 135 | | JsonSerializer.TryHandleReferenceFromJsonNode(ref reader, ref state, node, out referenceValue)) |
| | 0 | 136 | | { |
| | 0 | 137 | | value = referenceValue; |
| | 0 | 138 | | } |
| | | 139 | | else |
| | 0 | 140 | | { |
| | 0 | 141 | | value = node; |
| | 0 | 142 | | } |
| | | 143 | | |
| | 0 | 144 | | return true; |
| | 428 | 145 | | } |
| | | 146 | | |
| | 0 | 147 | | internal override JsonSchema? GetSchema(JsonNumberHandling _) => JsonSchema.CreateTrueSchema(); |
| | | 148 | | } |
| | | 149 | | } |