private JsonConverter GetConverterFromOptionsOrReflectionConverter(Type typeToConvert) { Debug.Assert(typeToConvert != null); // Priority 1: Attempt to get custom converter from the Converters list. JsonConverter?converter = GetConverterFromOptions(typeToConvert); // Priority 2: Attempt to get converter from [JsonConverter] on the type being converted. if (converter == null) { JsonConverterAttribute?converterAttribute = (JsonConverterAttribute?) GetAttributeThatCanHaveMultiple(typeToConvert, typeof(JsonConverterAttribute)); if (converterAttribute != null) { converter = GetConverterFromAttribute(converterAttribute, typeToConvert: typeToConvert, classTypeAttributeIsOn: typeToConvert, memberInfo: null); } } // Priority 3: Attempt to get built-in converter. converter ??= DefaultJsonTypeInfoResolver.GetDefaultConverter(typeToConvert); // Allow redirection for generic types or the enum converter. if (converter is JsonConverterFactory factory) { converter = factory.GetConverterInternal(typeToConvert, this); // A factory cannot return null; GetConverterInternal checked for that. Debug.Assert(converter != null); } Type converterTypeToConvert = converter.TypeToConvert; if (!converterTypeToConvert.IsAssignableFromInternal(typeToConvert) && !typeToConvert.IsAssignableFromInternal(converterTypeToConvert)) { ThrowHelper.ThrowInvalidOperationException_SerializationConverterNotCompatible(converter.GetType(), typeToConvert); } return(converter); }
internal JsonConverter GetConverterInternal(Type typeToConvert) { Debug.Assert(typeToConvert != null); if (_converters.TryGetValue(typeToConvert, out JsonConverter? converter)) { Debug.Assert(converter != null); return(converter); } // Priority 1: If there is a JsonSerializerContext, fetch the converter from there. converter = _context?.GetTypeInfo(typeToConvert)?.PropertyInfoForTypeInfo?.ConverterBase; // Priority 2: Attempt to get custom converter added at runtime. // Currently there is not a way at runtime to override the [JsonConverter] when applied to a property. foreach (JsonConverter item in Converters) { if (item.CanConvert(typeToConvert)) { converter = item; break; } } // Priority 3: Attempt to get converter from [JsonConverter] on the type being converted. if (converter == null) { JsonConverterAttribute?converterAttribute = (JsonConverterAttribute?) GetAttributeThatCanHaveMultiple(typeToConvert, typeof(JsonConverterAttribute)); if (converterAttribute != null) { converter = GetConverterFromAttribute(converterAttribute, typeToConvert: typeToConvert, classTypeAttributeIsOn: typeToConvert, memberInfo: null); } } // Priority 4: Attempt to get built-in converter. if (converter == null) { if (s_defaultSimpleConverters == null || s_defaultFactoryConverters == null) { // (De)serialization using serializer's options-based methods has not yet occurred, so the built-in converters are not rooted. // Even though source-gen code paths do not call this method <i.e. JsonSerializerOptions.GetConverter(Type)>, we do not root all the // built-in converters here since we fetch converters for any type included for source generation from the binded context (Priority 1). Debug.Assert(s_defaultSimpleConverters == null); Debug.Assert(s_defaultFactoryConverters == null); ThrowHelper.ThrowNotSupportedException_BuiltInConvertersNotRooted(typeToConvert); return(null !); } if (s_defaultSimpleConverters.TryGetValue(typeToConvert, out JsonConverter? foundConverter)) { converter = foundConverter; } else { foreach (JsonConverter item in s_defaultFactoryConverters) { if (item.CanConvert(typeToConvert)) { converter = item; break; } } // Since the object and IEnumerable converters cover all types, we should have a converter. Debug.Assert(converter != null); } } // Allow redirection for generic types or the enum converter. if (converter is JsonConverterFactory factory) { converter = factory.GetConverterInternal(typeToConvert, this); // A factory cannot return null; GetConverterInternal checked for that. Debug.Assert(converter != null); } Type converterTypeToConvert = converter.TypeToConvert; if (!converterTypeToConvert.IsAssignableFromInternal(typeToConvert) && !typeToConvert.IsAssignableFromInternal(converterTypeToConvert)) { ThrowHelper.ThrowInvalidOperationException_SerializationConverterNotCompatible(converter.GetType(), typeToConvert); } // Only cache the value once (de)serialization has occurred since new converters can be added that may change the result. if (_haveTypesBeenCreated) { // A null converter is allowed here and cached. // Ignore failure case here in multi-threaded cases since the cached item will be equivalent. _converters.TryAdd(typeToConvert, converter); } return(converter); }
/// <summary> /// Returns the converter for the specified type. /// </summary> /// <param name="typeToConvert">The type to return a converter for.</param> /// <returns> /// The first converter that supports the given type, or null if there is no converter. /// </returns> public JsonConverter?GetConverter(Type typeToConvert) { if (_converters.TryGetValue(typeToConvert, out JsonConverter? converter)) { return(converter); } // Priority 2: Attempt to get custom converter added at runtime. // Currently there is not a way at runtime to overide the [JsonConverter] when applied to a property. foreach (JsonConverter item in Converters) { if (item.CanConvert(typeToConvert)) { converter = item; break; } } // Priority 3: Attempt to get converter from [JsonConverter] on the type being converted. if (converter == null) { JsonConverterAttribute?converterAttribute = (JsonConverterAttribute?) GetAttributeThatCanHaveMultiple(typeToConvert, typeof(JsonConverterAttribute)); if (converterAttribute != null) { converter = GetConverterFromAttribute(converterAttribute, typeToConvert: typeToConvert, classTypeAttributeIsOn: typeToConvert, propertyInfo: null); } } // Priority 4: Attempt to get built-in converter. if (converter == null) { if (s_defaultSimpleConverters.TryGetValue(typeToConvert, out JsonConverter? foundConverter)) { converter = foundConverter; } else { foreach (JsonConverter item in s_defaultFactoryConverters) { if (item.CanConvert(typeToConvert)) { converter = item; break; } } } } // Allow redirection for generic types or the enum converter. if (converter is JsonConverterFactory factory) { converter = factory.GetConverterInternal(typeToConvert, this); // Allow null converters from the factory. This will result in a NotSupportedException later // and with a nice exception that indicates the parent type. } if (converter != null) { Type converterTypeToConvert = converter.TypeToConvert !; if (!converterTypeToConvert.IsAssignableFrom(typeToConvert) && !typeToConvert.IsAssignableFrom(converterTypeToConvert)) { ThrowHelper.ThrowInvalidOperationException_SerializationConverterNotCompatible(converter.GetType(), typeToConvert); } } // Only cache the value once (de)serialization has occurred since new converters can be added that may change the result. if (_haveTypesBeenCreated) { // A null converter is allowed here and cached. // Ignore failure case here in multi-threaded cases since the cached item will be equivalent. _converters.TryAdd(typeToConvert, converter); } return(converter); }