JsonConverter
Converts an object or value to or from JSON.
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
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 UsesDefaultHandleNull { get; set; }
internal bool HandleNullOnRead { get; set; }
internal bool HandleNullOnWrite { get; set; }
internal virtual JsonConverter SourceConverterForCastingConverter => null;
internal abstract Type ElementType { get; }
internal abstract Type KeyType { get; }
internal bool IsValueType { get; set; }
internal bool IsInternalConverter { get; set; }
internal bool IsInternalConverterForNumberType { get; set; }
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(Utf8JsonWriter writer, ref WriteStack state)
{
if (state.FlushThreshold > 0)
return writer.BytesPending > state.FlushThreshold;
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 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: {
PolymorphicTypeResolver polymorphicTypeResolver = jsonTypeInfo.PolymorphicTypeResolver;
if (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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool SingleValueReadWithReadAhead(bool requiresReadAhead, ref Utf8JsonReader reader, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state)
{
if (!requiresReadAhead || !state.ReadAhead)
return reader.Read();
return DoSingleValueReadWithReadAhead(ref reader);
}
internal static bool DoSingleValueReadWithReadAhead(ref Utf8JsonReader reader)
{
Utf8JsonReader utf8JsonReader = reader;
if (!reader.Read())
return false;
JsonTokenType tokenType = reader.TokenType;
if ((tokenType == JsonTokenType.StartObject || tokenType == JsonTokenType.StartArray) ? true : false) {
bool flag = reader.TrySkip();
reader = utf8JsonReader;
if (!flag)
return false;
ref reader.ReadWithVerify();
}
return true;
}
}
}