JsonConverter
Converts an object or value to or from JSON.
using System.Diagnostics.CodeAnalysis;
using System.IO.Pipelines;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json.Schema;
using System.Text.Json.Serialization.Converters;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
[System.Runtime.CompilerServices.NullableContext(2)]
[System.Runtime.CompilerServices.Nullable(0)]
public abstract class JsonConverter
{
private ConverterStrategy _converterStrategy;
public abstract Type Type { get; }
internal ConverterStrategy ConverterStrategy {
get {
return _converterStrategy;
}
set {
CanUseDirectReadOrWrite = (value == ConverterStrategy.Value && IsInternalConverter);
RequiresReadAhead = (value == ConverterStrategy.Value);
_converterStrategy = value;
}
}
internal virtual bool SupportsCreateObjectDelegate => false;
internal virtual bool CanPopulate => false;
internal bool CanUseDirectReadOrWrite { get; set; }
internal virtual bool CanHaveMetadata => false;
internal bool CanBePolymorphic { get; set; }
internal bool RequiresReadAhead { get; set; }
internal bool IsRootLevelMultiContentStreamingConverter { get; set; }
internal bool UsesDefaultHandleNull { get; set; }
internal bool HandleNullOnRead { get; set; }
internal bool HandleNullOnWrite { get; set; }
internal virtual JsonConverter SourceConverterForCastingConverter => null;
internal virtual Type ElementType => null;
internal virtual Type KeyType => null;
internal virtual JsonConverter NullableElementConverter => null;
internal bool IsValueType { get; set; }
internal bool IsInternalConverter { get; set; }
internal bool IsInternalConverterForNumberType { get; set; }
internal virtual bool IsConvertibleCollection => false;
internal virtual bool ConstructorIsParameterized { get; }
internal ConstructorInfo ConstructorInfo { get; set; }
internal JsonConverter()
{
IsInternalConverter = (GetType().Assembly == typeof(JsonConverter).Assembly);
ConverterStrategy = GetDefaultConverterStrategy();
}
[System.Runtime.CompilerServices.NullableContext(1)]
public abstract bool CanConvert(Type typeToConvert);
private protected abstract ConverterStrategy GetDefaultConverterStrategy();
internal virtual void ReadElementAndSetProperty(object obj, string propertyName, ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state)
{
throw new InvalidOperationException();
}
internal virtual JsonTypeInfo CreateJsonTypeInfo(JsonSerializerOptions options)
{
throw new InvalidOperationException();
}
internal JsonConverter<TTarget> CreateCastingConverter<TTarget>()
{
JsonConverter<TTarget> jsonConverter = this as JsonConverter<TTarget>;
if (jsonConverter != null)
return jsonConverter;
JsonSerializerOptions.CheckConverterNullabilityIsSameAsPropertyType(this, typeof(TTarget));
return SourceConverterForCastingConverter?.CreateCastingConverter<TTarget>() ?? new CastingConverter<TTarget>(this);
}
internal static bool ShouldFlush(ref WriteStack state, Utf8JsonWriter writer)
{
PipeWriter pipeWriter = state.PipeWriter;
if (pipeWriter != null) {
if (state.FlushThreshold > 0)
return pipeWriter.UnflushedBytes > state.FlushThreshold - writer.BytesPending;
return false;
}
return false;
}
internal abstract object ReadAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);
internal abstract bool OnTryReadAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out object value);
internal abstract bool TryReadAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out object value);
internal abstract object ReadAsPropertyNameAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);
internal abstract object ReadAsPropertyNameCoreAsObject(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);
internal abstract object ReadNumberWithCustomHandlingAsObject(ref Utf8JsonReader reader, JsonNumberHandling handling, JsonSerializerOptions options);
internal abstract void WriteAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options);
internal abstract bool OnTryWriteAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, ref WriteStack state);
internal abstract bool TryWriteAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, ref WriteStack state);
internal abstract void WriteAsPropertyNameAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options);
internal abstract void WriteAsPropertyNameCoreAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, bool isWritingExtensionDataProperty);
internal abstract void WriteNumberWithCustomHandlingAsObject(Utf8JsonWriter writer, object value, JsonNumberHandling handling);
internal virtual JsonSchema GetSchema(JsonNumberHandling numberHandling)
{
return null;
}
internal virtual void ConfigureJsonTypeInfo(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options)
{
}
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.")]
internal virtual void ConfigureJsonTypeInfoUsingReflection(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options)
{
}
internal JsonConverter ResolvePolymorphicConverter(JsonTypeInfo jsonTypeInfo, ref ReadStack state)
{
JsonConverter jsonConverter = null;
switch (state.Current.PolymorphicSerializationState) {
case PolymorphicSerializationState.None:
if (jsonTypeInfo.PolymorphicTypeResolver.TryGetDerivedJsonTypeInfo(state.PolymorphicTypeDiscriminator, out JsonTypeInfo jsonTypeInfo2)) {
jsonConverter = state.InitializePolymorphicReEntry(jsonTypeInfo2);
if (!jsonConverter.CanHaveMetadata)
ThrowHelper.ThrowNotSupportedException_DerivedConverterDoesNotSupportMetadata(jsonTypeInfo2.Type);
} else
state.Current.PolymorphicSerializationState = PolymorphicSerializationState.PolymorphicReEntryNotFound;
state.PolymorphicTypeDiscriminator = null;
break;
case PolymorphicSerializationState.PolymorphicReEntrySuspended:
jsonConverter = state.ResumePolymorphicReEntry();
break;
}
return jsonConverter;
}
internal JsonConverter ResolvePolymorphicConverter(object value, JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options, ref WriteStack state)
{
JsonConverter jsonConverter = null;
switch (state.Current.PolymorphicSerializationState) {
case PolymorphicSerializationState.None: {
Type type = value.GetType();
if (CanBePolymorphic && type != Type) {
jsonTypeInfo = state.Current.InitializePolymorphicReEntry(type, options);
jsonConverter = jsonTypeInfo.Converter;
}
PolymorphicTypeResolver polymorphicTypeResolver = jsonTypeInfo.PolymorphicTypeResolver;
if (polymorphicTypeResolver != null && polymorphicTypeResolver.TryGetDerivedJsonTypeInfo(type, out JsonTypeInfo jsonTypeInfo2, out object typeDiscriminator)) {
jsonConverter = state.Current.InitializePolymorphicReEntry(jsonTypeInfo2);
if (typeDiscriminator != null) {
if (!jsonConverter.CanHaveMetadata)
ThrowHelper.ThrowNotSupportedException_DerivedConverterDoesNotSupportMetadata(jsonTypeInfo2.Type);
state.PolymorphicTypeDiscriminator = typeDiscriminator;
state.PolymorphicTypeResolver = polymorphicTypeResolver;
}
}
if (jsonConverter == null)
state.Current.PolymorphicSerializationState = PolymorphicSerializationState.PolymorphicReEntryNotFound;
break;
}
case PolymorphicSerializationState.PolymorphicReEntrySuspended:
jsonConverter = state.Current.ResumePolymorphicReEntry();
break;
}
return jsonConverter;
}
internal bool TryHandleSerializedObjectReference(Utf8JsonWriter writer, object value, JsonSerializerOptions options, JsonConverter polymorphicConverter, ref WriteStack state)
{
switch (options.ReferenceHandlingStrategy) {
case ReferenceHandlingStrategy.IgnoreCycles: {
ReferenceResolver referenceResolver = state.ReferenceResolver;
if (referenceResolver.ContainsReferenceForCycleDetection(value)) {
writer.WriteNullValue();
return true;
}
referenceResolver.PushReferenceForCycleDetection(value);
state.Current.IsPushedReferenceForCycleDetection = (state.CurrentDepth > 0);
break;
}
case ReferenceHandlingStrategy.Preserve:
if ((polymorphicConverter?.CanHaveMetadata ?? CanHaveMetadata) && JsonSerializer.TryGetReferenceForValue(value, ref state, writer))
return true;
break;
}
return false;
}
}
}