JsonConverter<T>
Converts an object or value to or from JSON.
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization.Converters;
using System.Text.Json.Serialization.Metadata;
namespace System.Text.Json.Serialization
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public abstract class JsonConverter<[System.Runtime.CompilerServices.Nullable(2)] T> : JsonConverter
{
internal override ConverterStrategy ConverterStrategy => ConverterStrategy.Value;
[System.Runtime.CompilerServices.Nullable(2)]
internal virtual JsonConverter SourceConverterForCastingConverter {
get {
return null;
}
}
[System.Runtime.CompilerServices.Nullable(2)]
internal override Type KeyType {
get {
return null;
}
}
[System.Runtime.CompilerServices.Nullable(2)]
internal override Type ElementType {
get {
return null;
}
}
public virtual bool HandleNull {
get {
HandleNullOnRead = (default(T) != null);
HandleNullOnWrite = false;
return false;
}
}
internal bool HandleNullOnRead { get; set; }
internal bool HandleNullOnWrite { get; set; }
internal sealed override Type TypeToConvert { get; } = typeof(T);
internal sealed override object ReadCoreAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state)
{
return ReadCore(ref reader, options, ref state);
}
internal T ReadCore(ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state)
{
try {
if (!state.IsContinuation) {
if (!JsonConverter.SingleValueReadWithReadAhead(base.RequiresReadAhead, ref reader, ref state)) {
if (!state.SupportContinuation) {
state.BytesConsumed += reader.BytesConsumed;
return default(T);
}
state.BytesConsumed += reader.BytesConsumed;
if (state.Current.ReturnValue != null)
return (T)state.Current.ReturnValue;
return default(T);
}
} else if (!JsonConverter.SingleValueReadWithReadAhead(true, ref reader, ref state)) {
state.BytesConsumed += reader.BytesConsumed;
return default(T);
}
if (TryRead(ref reader, state.Current.JsonTypeInfo.Type, options, ref state, out T value) && !reader.Read() && !reader.IsFinalBlock)
state.Current.ReturnValue = value;
state.BytesConsumed += reader.BytesConsumed;
return value;
} catch (JsonReaderException ex) {
ThrowHelper.ReThrowWithPath(ref state, ex);
return default(T);
} catch (FormatException ex2) when (ex2.Source == "System.Text.Json.Rethrowable") {
ThrowHelper.ReThrowWithPath(ref state, ref reader, ex2);
return default(T);
} catch (InvalidOperationException ex3) when (ex3.Source == "System.Text.Json.Rethrowable") {
ThrowHelper.ReThrowWithPath(ref state, ref reader, ex3);
return default(T);
} catch (JsonException ex4) when (ex4.Path == null) {
ThrowHelper.AddJsonExceptionInformation(ref state, ref reader, ex4);
throw;
} catch (NotSupportedException ex5) {
if (ex5.Message.Contains(" Path: "))
throw;
ThrowHelper.ThrowNotSupportedException(ref state, ref reader, ex5);
return default(T);
}
}
internal sealed override bool WriteCoreAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, ref WriteStack state)
{
if (base.IsValueType) {
if (default(T) != null && value == null)
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.IgnoreCycles && value != null)
state.ReferenceResolver.PushReferenceForCycleDetection(value);
}
T value2 = (T)value;
return WriteCore(writer, ref value2, options, ref state);
}
internal bool WriteCore(Utf8JsonWriter writer, [In] [System.Runtime.CompilerServices.IsReadOnly] ref T value, JsonSerializerOptions options, ref WriteStack state)
{
try {
return TryWrite(writer, ref value, options, ref state);
} catch (InvalidOperationException ex) when (ex.Source == "System.Text.Json.Rethrowable") {
ThrowHelper.ReThrowWithPath(ref state, ex);
throw;
} catch (JsonException ex2) when (ex2.Path == null) {
ThrowHelper.AddJsonExceptionInformation(ref state, ex2);
throw;
} catch (NotSupportedException ex3) {
if (ex3.Message.Contains(" Path: "))
throw;
ThrowHelper.ThrowNotSupportedException(ref state, ex3);
return false;
}
}
protected internal JsonConverter()
: this(true)
{
}
internal JsonConverter(bool initialize)
{
base.IsValueType = typeof(T).IsValueType;
base.IsInternalConverter = (GetType().Assembly == typeof(JsonConverter).Assembly);
if (initialize)
Initialize();
}
private protected void Initialize()
{
if (HandleNull) {
HandleNullOnRead = true;
HandleNullOnWrite = true;
}
base.CanUseDirectReadOrWrite = (ConverterStrategy == ConverterStrategy.Value && base.IsInternalConverter);
base.RequiresReadAhead = (ConverterStrategy == ConverterStrategy.Value);
}
public override bool CanConvert(Type typeToConvert)
{
return typeToConvert == typeof(T);
}
[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.")]
[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.")]
internal sealed override JsonTypeInfo CreateReflectionJsonTypeInfo(JsonSerializerOptions options)
{
return new ReflectionJsonTypeInfo<T>(this, options);
}
internal sealed override JsonTypeInfo CreateCustomJsonTypeInfo(JsonSerializerOptions options)
{
return new CustomJsonTypeInfo<T>(this, options);
}
internal sealed override JsonParameterInfo CreateJsonParameterInfo()
{
return new JsonParameterInfo<T>();
}
internal sealed override JsonConverter<TTarget> CreateCastingConverter<TTarget>()
{
JsonConverter<TTarget> jsonConverter = this as JsonConverter<TTarget>;
if (jsonConverter != null)
return jsonConverter;
JsonSerializerOptions.CheckConverterNullabilityIsSameAsPropertyType(this, typeof(TTarget));
return this.SourceConverterForCastingConverter?.CreateCastingConverter<TTarget>() ?? new CastingConverter<TTarget, T>(this);
}
internal sealed override bool TryWriteAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, ref WriteStack state)
{
T value2 = (T)value;
return TryWrite(writer, ref value2, options, ref state);
}
internal virtual bool OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state)
{
Write(writer, value, options);
return true;
}
internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out T value)
{
value = Read(ref reader, typeToConvert, options);
return true;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public abstract T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);
internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out T value)
{
if (reader.TokenType == JsonTokenType.Null && !HandleNullOnRead && !state.IsContinuation) {
if (default(T) != null)
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
value = default(T);
return true;
}
if (ConverterStrategy == ConverterStrategy.Value) {
if (base.IsInternalConverter) {
if (state.Current.NumberHandling.HasValue && IsInternalConverterForNumberType)
value = ReadNumberWithCustomHandling(ref reader, state.Current.NumberHandling.Value, options);
else
value = Read(ref reader, typeToConvert, options);
} else {
JsonTokenType tokenType = reader.TokenType;
int currentDepth = reader.CurrentDepth;
long bytesConsumed = reader.BytesConsumed;
if (state.Current.NumberHandling.HasValue && IsInternalConverterForNumberType)
value = ReadNumberWithCustomHandling(ref reader, state.Current.NumberHandling.Value, options);
else
value = Read(ref reader, typeToConvert, options);
VerifyRead(tokenType, currentDepth, bytesConsumed, true, ref reader);
}
return true;
}
bool isContinuation = state.IsContinuation;
bool flag;
if (base.CanBePolymorphic) {
flag = OnTryRead(ref reader, typeToConvert, options, ref state, out value);
return true;
}
state.Push();
flag = OnTryRead(ref reader, typeToConvert, options, ref state, out value);
state.Pop(flag);
return flag;
}
internal sealed override bool OnTryReadAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out object value)
{
T value2;
bool result = OnTryRead(ref reader, TypeToConvert, options, ref state, out value2);
value = value2;
return result;
}
internal sealed override bool TryReadAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, [System.Runtime.CompilerServices.ScopedRef] ref ReadStack state, out object value)
{
T value2;
bool result = TryRead(ref reader, TypeToConvert, options, ref state, out value2);
value = value2;
return result;
}
private static bool IsNull(T value)
{
return value == null;
}
internal bool TryWrite(Utf8JsonWriter writer, [In] [System.Runtime.CompilerServices.IsReadOnly] ref T value, JsonSerializerOptions options, ref WriteStack state)
{
if (writer.CurrentDepth >= options.EffectiveMaxDepth)
ThrowHelper.ThrowJsonException_SerializerCycleDetected(options.EffectiveMaxDepth);
if (default(T) == null && !HandleNullOnWrite && IsNull(value)) {
writer.WriteNullValue();
return true;
}
if (ConverterStrategy == ConverterStrategy.Value) {
int currentDepth = writer.CurrentDepth;
if (state.Current.NumberHandling.HasValue && IsInternalConverterForNumberType)
WriteNumberWithCustomHandling(writer, value, state.Current.NumberHandling.Value);
else
Write(writer, value, options);
VerifyWrite(currentDepth, writer);
return true;
}
bool isContinuation = state.IsContinuation;
bool flag;
if (!base.IsValueType && value != null && state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted) {
JsonTypeInfo jsonTypeInfo = state.PeekNestedJsonTypeInfo();
JsonConverter jsonConverter = (base.CanBePolymorphic || jsonTypeInfo.PolymorphicTypeResolver != null) ? ResolvePolymorphicConverter(value, jsonTypeInfo, options, ref state) : null;
if (!isContinuation && options.ReferenceHandlingStrategy != 0 && TryHandleSerializedObjectReference(writer, value, options, jsonConverter, ref state))
return true;
if (jsonConverter != null) {
flag = jsonConverter.TryWriteAsObject(writer, value, options, ref state);
state.Current.ExitPolymorphicConverter(flag);
if (flag && state.Current.IsPushedReferenceForCycleDetection) {
state.ReferenceResolver.PopReferenceForCycleDetection();
state.Current.IsPushedReferenceForCycleDetection = false;
}
return flag;
}
}
state.Push();
flag = OnTryWrite(writer, value, options, ref state);
state.Pop(flag);
if (flag && state.Current.IsPushedReferenceForCycleDetection) {
state.ReferenceResolver.PopReferenceForCycleDetection();
state.Current.IsPushedReferenceForCycleDetection = false;
}
return flag;
}
internal bool TryWriteDataExtensionProperty(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state)
{
if (!base.IsInternalConverter)
return TryWrite(writer, ref value, options, ref state);
object obj = this as JsonDictionaryConverter<T>;
if (obj == null) {
JsonMetadataServicesConverter<T> obj2 = this as JsonMetadataServicesConverter<T>;
obj = (((obj2 != null) ? obj2.Converter : null) as JsonDictionaryConverter<T>);
}
JsonDictionaryConverter<T> jsonDictionaryConverter = (JsonDictionaryConverter<T>)obj;
if (jsonDictionaryConverter == null)
return TryWrite(writer, ref value, options, ref state);
if (writer.CurrentDepth >= options.EffectiveMaxDepth)
ThrowHelper.ThrowJsonException_SerializerCycleDetected(options.EffectiveMaxDepth);
bool isContinuation = state.IsContinuation;
state.Push();
if (!isContinuation)
state.Current.OriginalDepth = writer.CurrentDepth;
state.Current.IsWritingExtensionDataProperty = true;
state.Current.JsonPropertyInfo = state.Current.JsonTypeInfo.ElementTypeInfo.PropertyInfoForTypeInfo;
bool flag = jsonDictionaryConverter.OnWriteResume(writer, value, options, ref state);
if (flag)
VerifyWrite(state.Current.OriginalDepth, writer);
state.Pop(flag);
return flag;
}
internal void VerifyRead(JsonTokenType tokenType, int depth, long bytesConsumed, bool isValueConverter, ref Utf8JsonReader reader)
{
switch (tokenType) {
case JsonTokenType.StartArray:
if (reader.TokenType != JsonTokenType.EndArray)
ThrowHelper.ThrowJsonException_SerializationConverterRead(this);
else if (depth != reader.CurrentDepth) {
ThrowHelper.ThrowJsonException_SerializationConverterRead(this);
}
break;
case JsonTokenType.StartObject:
if (reader.TokenType != JsonTokenType.EndObject)
ThrowHelper.ThrowJsonException_SerializationConverterRead(this);
else if (depth != reader.CurrentDepth) {
ThrowHelper.ThrowJsonException_SerializationConverterRead(this);
}
break;
default:
if (isValueConverter) {
if (reader.BytesConsumed != bytesConsumed)
ThrowHelper.ThrowJsonException_SerializationConverterRead(this);
} else if (!base.CanBePolymorphic && (!HandleNullOnRead || tokenType != JsonTokenType.Null)) {
ThrowHelper.ThrowJsonException_SerializationConverterRead(this);
}
break;
}
}
internal void VerifyWrite(int originalDepth, Utf8JsonWriter writer)
{
if (originalDepth != writer.CurrentDepth)
ThrowHelper.ThrowJsonException_SerializationConverterWrite(this);
}
public abstract void Write(Utf8JsonWriter writer, [System.Runtime.CompilerServices.Nullable(0)] T value, JsonSerializerOptions options);
public virtual T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (!base.IsInternalConverter && options.SerializerContext == null && DefaultJsonTypeInfoResolver.TryGetDefaultSimpleConverter(TypeToConvert, out JsonConverter converter))
return ((JsonConverter<T>)converter).ReadAsPropertyNameCore(ref reader, TypeToConvert, options);
ThrowHelper.ThrowNotSupportedException_DictionaryKeyTypeNotSupported(TypeToConvert, this);
return default(T);
}
internal virtual T ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
long bytesConsumed = reader.BytesConsumed;
T result = ReadAsPropertyName(ref reader, typeToConvert, options);
if (reader.BytesConsumed != bytesConsumed)
ThrowHelper.ThrowJsonException_SerializationConverterRead(this);
return result;
}
public virtual void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
if (!base.IsInternalConverter && options.SerializerContext == null && DefaultJsonTypeInfoResolver.TryGetDefaultSimpleConverter(TypeToConvert, out JsonConverter converter))
((JsonConverter<T>)converter).WriteAsPropertyNameCore(writer, value, options, false);
else
ThrowHelper.ThrowNotSupportedException_DictionaryKeyTypeNotSupported(TypeToConvert, this);
}
internal virtual void WriteAsPropertyNameCore(Utf8JsonWriter writer, T value, JsonSerializerOptions options, bool isWritingExtensionDataProperty)
{
if (isWritingExtensionDataProperty)
writer.WritePropertyName((string)(object)value);
else {
int currentDepth = writer.CurrentDepth;
WriteAsPropertyName(writer, value, options);
if (currentDepth != writer.CurrentDepth || writer.TokenType != JsonTokenType.PropertyName)
ThrowHelper.ThrowJsonException_SerializationConverterWrite(this);
}
}
internal sealed override void WriteAsPropertyNameCoreAsObject(Utf8JsonWriter writer, object value, JsonSerializerOptions options, bool isWritingExtensionDataProperty)
{
WriteAsPropertyNameCore(writer, (T)value, options, isWritingExtensionDataProperty);
}
internal virtual T ReadNumberWithCustomHandling(ref Utf8JsonReader reader, JsonNumberHandling handling, JsonSerializerOptions options)
{
throw new InvalidOperationException();
}
internal virtual void WriteNumberWithCustomHandling(Utf8JsonWriter writer, T value, JsonNumberHandling handling)
{
throw new InvalidOperationException();
}
}
}