private void CacheMember( Type declaringType, Type memberType, MemberInfo memberInfo, bool isVirtual, JsonNumberHandling?typeNumberHandling, ref bool propertyOrderSpecified, ref Dictionary <string, JsonPropertyInfo>?ignoredMembers) { bool hasExtensionAttribute = memberInfo.GetCustomAttribute(typeof(JsonExtensionDataAttribute)) != null; if (hasExtensionAttribute && DataExtensionProperty != null) { ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(Type, typeof(JsonExtensionDataAttribute)); } JsonPropertyInfo jsonPropertyInfo = AddProperty(memberInfo, memberType, declaringType, isVirtual, Options); Debug.Assert(jsonPropertyInfo.Name != null); if (hasExtensionAttribute) { Debug.Assert(DataExtensionProperty == null); ValidateAndAssignDataExtensionProperty(jsonPropertyInfo); Debug.Assert(DataExtensionProperty != null); } else { CacheMember(jsonPropertyInfo, PropertyCache, ref ignoredMembers); propertyOrderSpecified |= jsonPropertyInfo.Order != 0; } }
public static JsonPropertyInfo AddProperty( MemberInfo memberInfo, Type memberType, Type parentClassType, JsonNumberHandling?parentTypeNumberHandling, JsonSerializerOptions options) { JsonIgnoreCondition?ignoreCondition = JsonPropertyInfo.GetAttribute <JsonIgnoreAttribute>(memberInfo)?.Condition; if (ignoreCondition == JsonIgnoreCondition.Always) { return(JsonPropertyInfo.CreateIgnoredPropertyPlaceholder(memberInfo, options)); } JsonConverter converter = GetConverter( memberType, parentClassType, memberInfo, out Type runtimeType, options); return(CreateProperty( declaredPropertyType: memberType, runtimePropertyType: runtimeType, memberInfo, parentClassType, converter, options, parentTypeNumberHandling, ignoreCondition)); }
internal static JsonPropertyInfo CreateProperty( Type declaredPropertyType, Type?runtimePropertyType, MemberInfo?memberInfo, Type parentClassType, JsonConverter converter, JsonSerializerOptions options, JsonNumberHandling?parentTypeNumberHandling = null, JsonIgnoreCondition?ignoreCondition = null) { // Create the JsonPropertyInfo instance. JsonPropertyInfo jsonPropertyInfo = converter.CreateJsonPropertyInfo(); jsonPropertyInfo.Initialize( parentClassType, declaredPropertyType, runtimePropertyType, runtimeClassType: converter.ClassType, memberInfo, converter, ignoreCondition, parentTypeNumberHandling, options); return(jsonPropertyInfo); }
public virtual void GetPolicies(JsonIgnoreCondition?ignoreCondition, JsonNumberHandling?parentTypeNumberHandling, bool defaultValueIsNull) { DetermineSerializationCapabilities(ignoreCondition); DeterminePropertyName(); DetermineIgnoreCondition(ignoreCondition, defaultValueIsNull); DetermineNumberHandling(parentTypeNumberHandling); }
public void Initialize( JsonSourceGenerationMode generationMode, string typeRef, string typeInfoPropertyName, Type type, ClassType classType, bool isValueType, JsonNumberHandling?numberHandling, List <PropertyGenerationSpec>?propertiesMetadata, CollectionType collectionType, TypeGenerationSpec?collectionKeyTypeMetadata, TypeGenerationSpec?collectionValueTypeMetadata, ObjectConstructionStrategy constructionStrategy, TypeGenerationSpec?nullableUnderlyingTypeMetadata, string?converterInstantiationLogic) { GenerationMode = generationMode; TypeRef = $"global::{typeRef}"; TypeInfoPropertyName = typeInfoPropertyName; Type = type; ClassType = classType; IsValueType = isValueType; CanBeNull = !isValueType || nullableUnderlyingTypeMetadata != null; NumberHandling = numberHandling; PropertiesMetadata = propertiesMetadata; CollectionType = collectionType; CollectionKeyTypeMetadata = collectionKeyTypeMetadata; CollectionValueTypeMetadata = collectionValueTypeMetadata; ConstructionStrategy = constructionStrategy; NullableUnderlyingTypeMetadata = nullableUnderlyingTypeMetadata; ConverterInstantiationLogic = converterInstantiationLogic; }
public void Initialize( JsonSourceGenerationMode generationMode, Type type, ClassType classType, JsonNumberHandling?numberHandling, List <PropertyGenerationSpec>?propertyGenSpecList, ParameterGenerationSpec[]?ctorParamGenSpecArray, CollectionType collectionType, TypeGenerationSpec?collectionKeyTypeMetadata, TypeGenerationSpec?collectionValueTypeMetadata, ObjectConstructionStrategy constructionStrategy, TypeGenerationSpec?nullableUnderlyingTypeMetadata, string?converterInstantiationLogic, bool implementsIJsonOnSerialized, bool implementsIJsonOnSerializing) { GenerationMode = generationMode; TypeRef = type.GetCompilableName(); TypeInfoPropertyName = type.GetTypeInfoPropertyName(); Type = type; ClassType = classType; IsValueType = type.IsValueType; CanBeNull = !IsValueType || nullableUnderlyingTypeMetadata != null; NumberHandling = numberHandling; PropertyGenSpecList = propertyGenSpecList; CtorParamGenSpecArray = ctorParamGenSpecArray; CollectionType = collectionType; CollectionKeyTypeMetadata = collectionKeyTypeMetadata; CollectionValueTypeMetadata = collectionValueTypeMetadata; ConstructionStrategy = constructionStrategy; NullableUnderlyingTypeMetadata = nullableUnderlyingTypeMetadata; ConverterInstantiationLogic = converterInstantiationLogic; ImplementsIJsonOnSerialized = implementsIJsonOnSerialized; ImplementsIJsonOnSerializing = implementsIJsonOnSerializing; }
private void DetermineNumberHandling(JsonNumberHandling?parentTypeNumberHandling) { bool numberHandlingIsApplicable = ConverterBase.IsInternalConverterForNumberType || TypeIsCollectionOfNumbersWithInternalConverter(); if (IsForClassInfo) { if (parentTypeNumberHandling != null && !ConverterBase.IsInternalConverter) { ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this); } if (numberHandlingIsApplicable) { // This logic is to honor JsonNumberHandlingAttribute placed on // custom collections e.g. public class MyNumberList : List<int>. // Priority 1: Get handling from the type (parent type in this case is the type itself). NumberHandling = parentTypeNumberHandling; // Priority 2: Get handling from JsonSerializerOptions instance. if (!NumberHandling.HasValue && Options.NumberHandling != JsonNumberHandling.Strict) { NumberHandling = Options.NumberHandling; } } } else { Debug.Assert(MemberInfo != null); JsonNumberHandlingAttribute?attribute = GetAttribute <JsonNumberHandlingAttribute>(MemberInfo); if (attribute != null && !numberHandlingIsApplicable) { ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this); } if (numberHandlingIsApplicable) { // Priority 1: Get handling from attribute on property or field. JsonNumberHandling?handling = attribute?.Handling; // Priority 2: Get handling from attribute on parent class type. handling ??= parentTypeNumberHandling; // Priority 3: Get handling from JsonSerializerOptions instance. if (!handling.HasValue && Options.NumberHandling != JsonNumberHandling.Strict) { handling = Options.NumberHandling; } NumberHandling = handling; } } }
public void Push() { if (_continuationCount == 0) { if (_count == 0) { // Performance optimization: reuse the first stackframe on the first push operation. // NB need to be careful when making writes to Current _before_ the first `Push` // operation is performed. _count = 1; } else { JsonTypeInfo jsonTypeInfo = Current.JsonPropertyInfo?.JsonTypeInfo ?? Current.CtorArgumentState !.JsonParameterInfo !.JsonTypeInfo; JsonNumberHandling?numberHandling = Current.NumberHandling; EnsurePushCapacity(); _stack[_count - 1] = Current; Current = default; _count++; Current.JsonTypeInfo = jsonTypeInfo; Current.JsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo; // Allow number handling on property to win over handling on type. Current.NumberHandling = numberHandling ?? Current.JsonPropertyInfo.EffectiveNumberHandling; Current.CanContainMetadata = PreserveReferences || jsonTypeInfo.PolymorphicTypeResolver?.UsesTypeDiscriminators == true; } } else { // We are re-entering a continuation, adjust indices accordingly. if (_count++ > 0) { _stack[_count - 2] = Current; Current = _stack[_count - 1]; } // check if we are done if (_continuationCount == _count) { _continuationCount = 0; } } SetConstructorArgumentState(); #if DEBUG // Ensure the method is always exercised in debug builds. _ = JsonPath(); #endif }
public void Push() { if (_continuationCount == 0) { Debug.Assert(Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntrySuspended); if (_count == 0 && Current.PolymorphicSerializationState == PolymorphicSerializationState.None) { // Perf enhancement: do not create a new stackframe on the first push operation // unless the converter has primed the current frame for polymorphic dispatch. _count = 1; _indexOffset = 1; // currentIndex := _count - 1; } else { JsonTypeInfo jsonTypeInfo = Current.GetNestedJsonTypeInfo(); JsonNumberHandling?numberHandling = Current.NumberHandling; EnsurePushCapacity(); _stack[_count - _indexOffset] = Current; Current = default; _count++; Current.JsonTypeInfo = jsonTypeInfo; Current.JsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo; // Allow number handling on property to win over handling on type. Current.NumberHandling = numberHandling ?? Current.JsonPropertyInfo.EffectiveNumberHandling; } } else { // We are re-entering a continuation, adjust indices accordingly if (_count++ > 0 || _indexOffset == 0) { Current = _stack[_count - _indexOffset]; } // check if we are done if (_continuationCount == _count) { _continuationCount = 0; } } #if DEBUG // Ensure the method is always exercised in debug builds. _ = PropertyPath(); #endif }
private void DetermineNumberHandling(JsonNumberHandling?parentTypeNumberHandling) { if (IsForClassInfo) { if (parentTypeNumberHandling != null && !ConverterBase.IsInternalConverter) { ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this); } // Priority 1: Get handling from the type (parent type in this case is the type itself). NumberHandling = parentTypeNumberHandling; // Priority 2: Get handling from JsonSerializerOptions instance. if (!NumberHandling.HasValue && Options.NumberHandling != JsonNumberHandling.Strict) { NumberHandling = Options.NumberHandling; } } else { JsonNumberHandling?handling = null; // Priority 1: Get handling from attribute on property or field. if (MemberInfo != null) { JsonNumberHandlingAttribute?attribute = GetAttribute <JsonNumberHandlingAttribute>(MemberInfo); if (attribute != null && !ConverterBase.IsInternalConverterForNumberType && ((ClassType.Enumerable | ClassType.Dictionary) & ClassType) == 0) { ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this); } handling = attribute?.Handling; } // Priority 2: Get handling from attribute on parent class type. handling ??= parentTypeNumberHandling; // Priority 3: Get handling from JsonSerializerOptions instance. if (!handling.HasValue && Options.NumberHandling != JsonNumberHandling.Strict) { handling = Options.NumberHandling; } NumberHandling = handling; } }
public JsonPropertyInfo <TProperty> CreateProperty <TProperty>( string clrPropertyName, System.Reflection.MemberTypes memberType, System.Type declaringType, JsonTypeInfo <TProperty> classInfo, JsonConverter converter, System.Func <object, TProperty> getter, System.Action <object, TProperty> setter, string jsonPropertyName, byte[] nameAsUtf8Bytes, byte[] escapedNameSection, JsonIgnoreCondition?ignoreCondition, JsonNumberHandling?numberHandling) { JsonSerializerOptions options = GetOptions(); JsonPropertyInfo <TProperty> jsonPropertyInfo = JsonPropertyInfo <TProperty> .Create(); jsonPropertyInfo.Options = options; // Property name settings. // TODO: consider whether we need to examine options.Encoder here as well. if (options.PropertyNamingPolicy == null && nameAsUtf8Bytes != null && escapedNameSection != null) { jsonPropertyInfo.NameAsString = jsonPropertyName ?? clrPropertyName; jsonPropertyInfo.NameAsUtf8Bytes = nameAsUtf8Bytes; jsonPropertyInfo.EscapedNameSection = escapedNameSection; } else { jsonPropertyInfo.NameAsString = jsonPropertyName ?? options.PropertyNamingPolicy?.ConvertName(clrPropertyName) ?? (options.PropertyNamingPolicy == null ? null : throw new System.InvalidOperationException("TODO: PropertyNamingPolicy cannot return null.")); // NameAsUtf8Bytes and EscapedNameSection will be set in CompleteInitialization() below. } if (ignoreCondition != JsonIgnoreCondition.Always) { jsonPropertyInfo.Get = getter; jsonPropertyInfo.Set = setter; jsonPropertyInfo.ConverterBase = converter ?? throw new System.NotSupportedException("TODO: need custom converter here?"); jsonPropertyInfo.RuntimeClassInfo = classInfo; jsonPropertyInfo.DeclaredPropertyType = typeof(TProperty); jsonPropertyInfo.DeclaringType = declaringType; jsonPropertyInfo.IgnoreCondition = ignoreCondition; jsonPropertyInfo.MemberType = memberType; } jsonPropertyInfo.CompleteInitialization(); return(jsonPropertyInfo); }
public void Initialize( JsonSourceGenerationMode generationMode, Type type, ClassType classType, JsonNumberHandling?numberHandling, List <PropertyGenerationSpec>?propertyGenSpecList, ParameterGenerationSpec[]?ctorParamGenSpecArray, CollectionType collectionType, TypeGenerationSpec?collectionKeyTypeMetadata, TypeGenerationSpec?collectionValueTypeMetadata, ObjectConstructionStrategy constructionStrategy, TypeGenerationSpec?nullableUnderlyingTypeMetadata, string?runtimeTypeRef, TypeGenerationSpec?extensionDataPropertyTypeSpec, string?converterInstantiationLogic, bool implementsIJsonOnSerialized, bool implementsIJsonOnSerializing, bool hasTypeFactoryConverter, bool canContainNullableReferenceAnnotations, bool hasPropertyFactoryConverters, bool isPolymorphic) { GenerationMode = generationMode; TypeRef = type.GetCompilableName(); TypeInfoPropertyName = type.GetTypeInfoPropertyName(); Type = type; ClassType = classType; IsValueType = type.IsValueType; CanBeNull = !IsValueType || nullableUnderlyingTypeMetadata != null; IsPolymorphic = isPolymorphic; NumberHandling = numberHandling; PropertyGenSpecList = propertyGenSpecList; CtorParamGenSpecArray = ctorParamGenSpecArray; CollectionType = collectionType; CollectionKeyTypeMetadata = collectionKeyTypeMetadata; CollectionValueTypeMetadata = collectionValueTypeMetadata; ConstructionStrategy = constructionStrategy; NullableUnderlyingTypeMetadata = nullableUnderlyingTypeMetadata; RuntimeTypeRef = runtimeTypeRef; ExtensionDataPropertyTypeSpec = extensionDataPropertyTypeSpec; ConverterInstantiationLogic = converterInstantiationLogic; ImplementsIJsonOnSerialized = implementsIJsonOnSerialized; ImplementsIJsonOnSerializing = implementsIJsonOnSerializing; CanContainNullableReferenceAnnotations = canContainNullableReferenceAnnotations; HasTypeFactoryConverter = hasTypeFactoryConverter; HasPropertyFactoryConverters = hasPropertyFactoryConverters; }
public void Push() { if (_continuationCount == 0) { if (_count == 0) { // Performance optimization: reuse the first stackframe on the first push operation. // NB need to be careful when making writes to Current _before_ the first `Push` // operation is performed. _count = 1; } else { JsonTypeInfo jsonTypeInfo = Current.GetNestedJsonTypeInfo(); JsonNumberHandling?numberHandling = Current.NumberHandling; EnsurePushCapacity(); _stack[_count - 1] = Current; Current = default; _count++; Current.JsonTypeInfo = jsonTypeInfo; Current.JsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo; // Allow number handling on property to win over handling on type. Current.NumberHandling = numberHandling ?? Current.JsonPropertyInfo.NumberHandling; } } else { // We are re-entering a continuation, adjust indices accordingly if (_count++ > 0) { Current = _stack[_count - 1]; } // check if we are done if (_continuationCount == _count) { _continuationCount = 0; } } #if DEBUG // Ensure the method is always exercised in debug builds. _ = PropertyPath(); #endif }
private void CacheMember( Type declaringType, Type memberType, MemberInfo memberInfo, JsonNumberHandling?typeNumberHandling, Dictionary <string, JsonPropertyInfo> cache, ref Dictionary <string, MemberInfo>?ignoredMembers) { JsonPropertyInfo jsonPropertyInfo = AddProperty(memberInfo, memberType, declaringType, typeNumberHandling, Options); Debug.Assert(jsonPropertyInfo.NameAsString != null); string memberName = memberInfo.Name; // The JsonPropertyNameAttribute or naming policy resulted in a collision. if (!JsonHelpers.TryAdd(cache, jsonPropertyInfo.NameAsString, jsonPropertyInfo)) { JsonPropertyInfo other = cache[jsonPropertyInfo.NameAsString]; if (other.IsIgnored) { // Overwrite previously cached property since it has [JsonIgnore]. cache[jsonPropertyInfo.NameAsString] = jsonPropertyInfo; } else if ( // Does the current property have `JsonIgnoreAttribute`? !jsonPropertyInfo.IsIgnored && // Is the current property hidden by the previously cached property // (with `new` keyword, or by overriding)? other.MemberInfo !.Name != memberName && // Was a property with the same CLR name was ignored? That property hid the current property, // thus, if it was ignored, the current property should be ignored too. ignoredMembers?.ContainsKey(memberName) != true) { // We throw if we have two public properties that have the same JSON property name, and neither have been ignored. ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo); } // Ignore the current property. } if (jsonPropertyInfo.IsIgnored) { (ignoredMembers ??= new Dictionary <string, MemberInfo>()).Add(memberName, memberInfo); } }
public void Push() { if (_continuationCount == 0) { if (_count == 0) { // The first stack frame is held in Current. _count = 1; } else { JsonTypeInfo jsonTypeInfo = Current.GetPolymorphicJsonPropertyInfo().RuntimeTypeInfo; JsonNumberHandling?numberHandling = Current.NumberHandling; EnsurePushCapacity(); _stack[_count - 1] = Current; Current = default; _count++; Current.JsonTypeInfo = jsonTypeInfo; Current.DeclaredJsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo; // Allow number handling on property to win over handling on type. Current.NumberHandling = numberHandling ?? Current.DeclaredJsonPropertyInfo.NumberHandling; } } else { // We are re-entering a continuation, adjust indices accordingly if (_count++ > 0) { Current = _stack[_count - 1]; } // check if we are done if (_continuationCount == _count) { _continuationCount = 0; } } #if DEBUG // Ensure the method is always exercised in debug builds. _ = PropertyPath(); #endif }
public void Push() { if (_continuationCount == 0) { if (_count == 0) { // The first stack frame is held in Current. _count = 1; } else { JsonTypeInfo jsonTypeInfo = Current.GetPolymorphicJsonPropertyInfo().RuntimeTypeInfo; JsonNumberHandling?numberHandling = Current.NumberHandling; AddCurrent(); Current.Reset(); Current.JsonTypeInfo = jsonTypeInfo; Current.DeclaredJsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo; // Allow number handling on property to win over handling on type. Current.NumberHandling = numberHandling ?? Current.DeclaredJsonPropertyInfo.NumberHandling; } } else if (_continuationCount == 1) { // No need for a push since there is only one stack frame. Debug.Assert(_count == 1); _continuationCount = 0; } else { // A continuation, adjust the index. Current = _previous[_count - 1]; // Check if we are done. if (_count == _continuationCount) { _continuationCount = 0; } else { _count++; } } }
internal virtual void GetPolicies(JsonIgnoreCondition?ignoreCondition, JsonNumberHandling?declaringTypeNumberHandling) { if (IsForTypeInfo) { Debug.Assert(MemberInfo == null); DetermineNumberHandlingForTypeInfo(declaringTypeNumberHandling); } else { Debug.Assert(MemberInfo != null); DetermineSerializationCapabilities(ignoreCondition); DeterminePropertyName(); DetermineIgnoreCondition(ignoreCondition); JsonNumberHandlingAttribute?attribute = GetAttribute <JsonNumberHandlingAttribute>(MemberInfo); DetermineNumberHandlingForProperty(attribute?.Handling, declaringTypeNumberHandling); } }
/// <summary> /// Create a <see cref="JsonPropertyInfo"/> for a given Type. /// See <seealso cref="PropertyInfoForTypeInfo"/>. /// </summary> internal static JsonPropertyInfo CreatePropertyInfoForTypeInfo( Type declaredPropertyType, JsonConverter converter, JsonNumberHandling?numberHandling, JsonSerializerOptions options) { JsonPropertyInfo jsonPropertyInfo = CreateProperty( declaredPropertyType: declaredPropertyType, memberInfo: null, // Not a real property so this is null. parentClassType: ObjectType, // a dummy value (not used) isVirtual: false, converter, options, parentTypeNumberHandling: numberHandling); Debug.Assert(jsonPropertyInfo.IsForTypeInfo); return(jsonPropertyInfo); }
/// <summary> /// Create a <see cref="JsonPropertyInfo"/> for a given Type. /// See <seealso cref="JsonClassInfo.PropertyInfoForClassInfo"/>. /// </summary> internal static JsonPropertyInfo CreatePropertyInfoForClassInfo( Type declaredPropertyType, Type runtimePropertyType, JsonConverter converter, JsonSerializerOptions options) { JsonNumberHandling?numberHandling = GetNumberHandlingForType(declaredPropertyType); JsonPropertyInfo jsonPropertyInfo = CreateProperty( declaredPropertyType: declaredPropertyType, runtimePropertyType: runtimePropertyType, memberInfo: null, // Not a real property so this is null. parentClassType: JsonClassInfo.ObjectType, // a dummy value (not used) converter: converter, options, parentTypeNumberHandling: numberHandling); Debug.Assert(jsonPropertyInfo.IsForClassInfo); return(jsonPropertyInfo); }
internal virtual void Initialize( Type parentClassType, Type declaredPropertyType, ConverterStrategy converterStrategy, MemberInfo?memberInfo, bool isVirtual, JsonConverter converter, JsonIgnoreCondition?ignoreCondition, JsonNumberHandling?parentTypeNumberHandling, JsonSerializerOptions options) { Debug.Assert(converter != null); DeclaringType = parentClassType; PropertyType = declaredPropertyType; ConverterStrategy = converterStrategy; MemberInfo = memberInfo; IsVirtual = isVirtual; ConverterBase = converter; Options = options; }
public virtual void Initialize( Type parentClassType, Type declaredPropertyType, Type?runtimePropertyType, ClassType runtimeClassType, MemberInfo?memberInfo, JsonConverter converter, JsonIgnoreCondition?ignoreCondition, JsonNumberHandling?parentTypeNumberHandling, JsonSerializerOptions options) { Debug.Assert(converter != null); ParentClassType = parentClassType; DeclaredPropertyType = declaredPropertyType; RuntimePropertyType = runtimePropertyType; ClassType = runtimeClassType; MemberInfo = memberInfo; ConverterBase = converter; Options = options; }
internal void DetermineNumberHandlingForTypeInfo(JsonNumberHandling?numberHandling) { if (numberHandling != null && numberHandling != JsonNumberHandling.Strict && !ConverterBase.IsInternalConverter) { ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this); } if (NumberHandingIsApplicable()) { // This logic is to honor JsonNumberHandlingAttribute placed on // custom collections e.g. public class MyNumberList : List<int>. // Priority 1: Get handling from the type (parent type in this case is the type itself). NumberHandling = numberHandling; // Priority 2: Get handling from JsonSerializerOptions instance. if (!NumberHandling.HasValue && Options.NumberHandling != JsonNumberHandling.Strict) { NumberHandling = Options.NumberHandling; } } }
internal void DetermineNumberHandlingForProperty() { bool numberHandlingIsApplicable = NumberHandingIsApplicable(); if (numberHandlingIsApplicable) { // Priority 1: Get handling from attribute on property/field, or its parent class type. JsonNumberHandling?handling = NumberHandling ?? DeclaringTypeNumberHandling; // Priority 2: Get handling from JsonSerializerOptions instance. if (!handling.HasValue && Options.NumberHandling != JsonNumberHandling.Strict) { handling = Options.NumberHandling; } EffectiveNumberHandling = handling; } else if (NumberHandling.HasValue && NumberHandling != JsonNumberHandling.Strict) { ThrowHelper.ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(this); } }
public void Initialize( string compilableName, string friendlyName, Type type, ClassType classType, bool isValueType, JsonNumberHandling?numberHandling, List <PropertyMetadata>?propertiesMetadata, CollectionType collectionType, TypeMetadata?collectionKeyTypeMetadata, TypeMetadata?collectionValueTypeMetadata, ObjectConstructionStrategy constructionStrategy, TypeMetadata?nullableUnderlyingTypeMetadata, string?converterInstantiationLogic, bool containsOnlyPrimitives) { if (_hasBeenInitialized) { throw new InvalidOperationException("Type metadata has already been initialized."); } _hasBeenInitialized = true; CompilableName = compilableName; FriendlyName = friendlyName; Type = type; ClassType = classType; IsValueType = isValueType; NumberHandling = numberHandling; PropertiesMetadata = propertiesMetadata; CollectionType = collectionType; CollectionKeyTypeMetadata = collectionKeyTypeMetadata; CollectionValueTypeMetadata = collectionValueTypeMetadata; ConstructionStrategy = constructionStrategy; NullableUnderlyingTypeMetadata = nullableUnderlyingTypeMetadata; ConverterInstantiationLogic = converterInstantiationLogic; ContainsOnlyPrimitives = containsOnlyPrimitives; }
internal override void Initialize( Type parentClassType, Type declaredPropertyType, Type?runtimePropertyType, ConverterStrategy runtimeClassType, MemberInfo?memberInfo, bool isVirtual, JsonConverter converter, JsonIgnoreCondition?ignoreCondition, JsonNumberHandling?parentTypeNumberHandling, JsonSerializerOptions options) { base.Initialize( parentClassType, declaredPropertyType, runtimePropertyType, runtimeClassType, memberInfo, isVirtual, converter, ignoreCondition, parentTypeNumberHandling, options); switch (memberInfo) { case PropertyInfo propertyInfo: { bool useNonPublicAccessors = GetAttribute <JsonIncludeAttribute>(propertyInfo) != null; MethodInfo?getMethod = propertyInfo.GetMethod; if (getMethod != null && (getMethod.IsPublic || useNonPublicAccessors)) { HasGetter = true; Get = options.MemberAccessorStrategy.CreatePropertyGetter <T>(propertyInfo); } MethodInfo?setMethod = propertyInfo.SetMethod; if (setMethod != null && (setMethod.IsPublic || useNonPublicAccessors)) { HasSetter = true; Set = options.MemberAccessorStrategy.CreatePropertySetter <T>(propertyInfo); } MemberType = MemberTypes.Property; break; } case FieldInfo fieldInfo: { Debug.Assert(fieldInfo.IsPublic); HasGetter = true; Get = options.MemberAccessorStrategy.CreateFieldGetter <T>(fieldInfo); if (!fieldInfo.IsInitOnly) { HasSetter = true; Set = options.MemberAccessorStrategy.CreateFieldSetter <T>(fieldInfo); } MemberType = MemberTypes.Field; break; } default: { IsForTypeInfo = true; HasGetter = true; HasSetter = true; break; } } _converterIsExternalAndPolymorphic = !converter.IsInternalConverter && DeclaredPropertyType != converter.TypeToConvert; PropertyTypeCanBeNull = DeclaredPropertyType.CanBeNull(); _propertyTypeEqualsTypeToConvert = typeof(T) == DeclaredPropertyType; GetPolicies(ignoreCondition, parentTypeNumberHandling); }
internal void InitializeForSourceGen( JsonSerializerOptions options, bool isProperty, bool isPublic, Type declaringType, JsonTypeInfo typeInfo, JsonConverter <T> converter, Func <object, T>?getter, Action <object, T>?setter, JsonIgnoreCondition?ignoreCondition, bool hasJsonInclude, JsonNumberHandling?numberHandling, string propertyName, string?jsonPropertyName) { Options = options; ClrName = propertyName; // Property name settings. if (jsonPropertyName != null) { NameAsString = jsonPropertyName; } else if (options.PropertyNamingPolicy == null) { NameAsString = ClrName; } else { NameAsString = options.PropertyNamingPolicy.ConvertName(ClrName); if (NameAsString == null) { ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(DeclaringType, this); } } NameAsUtf8Bytes ??= Encoding.UTF8.GetBytes(NameAsString !); EscapedNameSection ??= JsonHelpers.GetEscapedPropertyNameSection(NameAsUtf8Bytes, Options.Encoder); SrcGen_IsPublic = isPublic; SrcGen_HasJsonInclude = hasJsonInclude; if (ignoreCondition == JsonIgnoreCondition.Always) { IsIgnored = true; Debug.Assert(!ShouldSerialize); Debug.Assert(!ShouldDeserialize); } else { Get = getter; Set = setter; HasGetter = Get != null; HasSetter = Set != null; ConverterBase = converter; RuntimeTypeInfo = typeInfo; DeclaredPropertyType = typeof(T); DeclaringType = declaringType; IgnoreCondition = ignoreCondition; MemberType = isProperty ? MemberTypes.Property : MemberTypes.Field; _converterIsExternalAndPolymorphic = !converter.IsInternalConverter && DeclaredPropertyType != converter.TypeToConvert; PropertyTypeCanBeNull = typeof(T).CanBeNull(); _propertyTypeEqualsTypeToConvert = converter.TypeToConvert == typeof(T); ConverterStrategy = Converter !.ConverterStrategy; RuntimePropertyType = DeclaredPropertyType; DetermineIgnoreCondition(IgnoreCondition); // TODO: this method needs to also take the number handling option for the declaring type. DetermineNumberHandlingForProperty(numberHandling, declaringTypeNumberHandling: null); DetermineSerializationCapabilities(IgnoreCondition); } }
public JsonClassInfo(Type type, JsonSerializerOptions options) { Type = type; Options = options; JsonConverter converter = GetConverter( Type, parentClassType: null, // A ClassInfo never has a "parent" class. memberInfo: null, // A ClassInfo never has a "parent" property. out Type runtimeType, Options); ClassType = converter.ClassType; JsonNumberHandling?typeNumberHandling = GetNumberHandlingForType(Type); PropertyInfoForClassInfo = CreatePropertyInfoForClassInfo(Type, runtimeType, converter, Options); switch (ClassType) { case ClassType.Object: { CreateObject = Options.MemberAccessorStrategy.CreateConstructor(type); Dictionary <string, JsonPropertyInfo> cache = new Dictionary <string, JsonPropertyInfo>( Options.PropertyNameCaseInsensitive ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal); Dictionary <string, MemberInfo>?ignoredMembers = null; // We start from the most derived type. for (Type?currentType = type; currentType != null; currentType = currentType.BaseType) { const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; foreach (PropertyInfo propertyInfo in currentType.GetProperties(bindingFlags)) { // Ignore indexers and virtual properties that have overrides that were [JsonIgnore]d. if (propertyInfo.GetIndexParameters().Length > 0 || PropertyIsOverridenAndIgnored(propertyInfo, ignoredMembers)) { continue; } // For now we only support public properties (i.e. setter and/or getter is public). if (propertyInfo.GetMethod?.IsPublic == true || propertyInfo.SetMethod?.IsPublic == true) { CacheMember(currentType, propertyInfo.PropertyType, propertyInfo, typeNumberHandling, cache, ref ignoredMembers); } else { if (JsonPropertyInfo.GetAttribute <JsonIncludeAttribute>(propertyInfo) != null) { ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(propertyInfo, currentType); } // Non-public properties should not be included for (de)serialization. } } foreach (FieldInfo fieldInfo in currentType.GetFields(bindingFlags)) { if (PropertyIsOverridenAndIgnored(fieldInfo, ignoredMembers)) { continue; } bool hasJsonInclude = JsonPropertyInfo.GetAttribute <JsonIncludeAttribute>(fieldInfo) != null; if (fieldInfo.IsPublic) { if (hasJsonInclude || Options.IncludeFields) { CacheMember(currentType, fieldInfo.FieldType, fieldInfo, typeNumberHandling, cache, ref ignoredMembers); } } else { if (hasJsonInclude) { ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(fieldInfo, currentType); } // Non-public fields should not be included for (de)serialization. } } } JsonPropertyInfo[] cacheArray; if (DetermineExtensionDataProperty(cache)) { // Remove from cache since it is handled independently. cache.Remove(DataExtensionProperty !.NameAsString); cacheArray = new JsonPropertyInfo[cache.Count + 1]; // Set the last element to the extension property. cacheArray[cache.Count] = DataExtensionProperty; } else { cacheArray = new JsonPropertyInfo[cache.Count]; } // Copy the dictionary cache to the array cache. cache.Values.CopyTo(cacheArray, 0); // These are not accessed by other threads until the current JsonClassInfo instance // is finished initializing and added to the cache on JsonSerializerOptions. PropertyCache = cache; PropertyCacheArray = cacheArray; // Allow constructor parameter logic to remove items from the dictionary since the JSON // property values will be passed to the constructor and do not call a property setter. if (converter.ConstructorIsParameterized) { InitializeConstructorParameters(converter.ConstructorInfo !); } } break; case ClassType.Enumerable: case ClassType.Dictionary: { ElementType = converter.ElementType; CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType); } break; case ClassType.Value: case ClassType.NewValue: { CreateObject = Options.MemberAccessorStrategy.CreateConstructor(type); } break; case ClassType.None: { ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(type); } break; default: Debug.Fail($"Unexpected class type: {ClassType}"); throw new InvalidOperationException(); } }
public override void Initialize( Type parentClassType, Type declaredPropertyType, Type?runtimePropertyType, ClassType runtimeClassType, MemberInfo?memberInfo, JsonConverter converter, JsonIgnoreCondition?ignoreCondition, JsonNumberHandling?parentTypeNumberHandling, JsonSerializerOptions options) { base.Initialize( parentClassType, declaredPropertyType, runtimePropertyType, runtimeClassType, memberInfo, converter, ignoreCondition, parentTypeNumberHandling, options); switch (memberInfo) { case PropertyInfo propertyInfo: { bool useNonPublicAccessors = GetAttribute <JsonIncludeAttribute>(propertyInfo) != null; MethodInfo?getMethod = propertyInfo.GetMethod; if (getMethod != null && (getMethod.IsPublic || useNonPublicAccessors)) { HasGetter = true; Get = options.MemberAccessorStrategy.CreatePropertyGetter <T>(propertyInfo); } MethodInfo?setMethod = propertyInfo.SetMethod; if (setMethod != null && (setMethod.IsPublic || useNonPublicAccessors)) { HasSetter = true; Set = options.MemberAccessorStrategy.CreatePropertySetter <T>(propertyInfo); } break; } case FieldInfo fieldInfo: { Debug.Assert(fieldInfo.IsPublic); HasGetter = true; Get = options.MemberAccessorStrategy.CreateFieldGetter <T>(fieldInfo); if (!fieldInfo.IsInitOnly) { HasSetter = true; Set = options.MemberAccessorStrategy.CreateFieldSetter <T>(fieldInfo); } break; } default: { IsForClassInfo = true; HasGetter = true; HasSetter = true; break; } } GetPolicies(ignoreCondition, parentTypeNumberHandling, defaultValueIsNull: Converter.CanBeNull); }
public void Push() { if (_continuationCount == 0) { if (_count == 0) { // The first stack frame is held in Current. _count = 1; } else { JsonTypeInfo jsonTypeInfo; JsonNumberHandling?numberHandling = Current.NumberHandling; ConverterStrategy converterStrategy = Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy; if (converterStrategy == ConverterStrategy.Object) { if (Current.JsonPropertyInfo != null) { jsonTypeInfo = Current.JsonPropertyInfo.RuntimeTypeInfo; } else { jsonTypeInfo = Current.CtorArgumentState !.JsonParameterInfo !.RuntimeTypeInfo; } } else if (converterStrategy == ConverterStrategy.Value) { // Although ConverterStrategy.Value doesn't push, a custom custom converter may re-enter serialization. jsonTypeInfo = Current.JsonPropertyInfo !.RuntimeTypeInfo; } else { Debug.Assert(((ConverterStrategy.Enumerable | ConverterStrategy.Dictionary) & converterStrategy) != 0); jsonTypeInfo = Current.JsonTypeInfo.ElementTypeInfo !; } EnsurePushCapacity(); _stack[_count - 1] = Current; Current = default; _count++; Current.JsonTypeInfo = jsonTypeInfo; Current.JsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo; // Allow number handling on property to win over handling on type. Current.NumberHandling = numberHandling ?? Current.JsonPropertyInfo.NumberHandling; } } else { // We are re-entering a continuation, adjust indices accordingly if (_count++ > 0) { Current = _stack[_count - 1]; } // check if we are done if (_continuationCount == _count) { _continuationCount = 0; } } SetConstructorArgumentState(); #if DEBUG // Ensure the method is always exercised in debug builds. _ = JsonPath(); #endif }
public void Push() { if (_continuationCount == 0) { if (_count == 0) { // The first stack frame is held in Current. _count = 1; } else { JsonTypeInfo jsonTypeInfo; JsonNumberHandling?numberHandling = Current.NumberHandling; ConverterStrategy converterStrategy = Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterStrategy; if (converterStrategy == ConverterStrategy.Object) { if (Current.JsonPropertyInfo != null) { jsonTypeInfo = Current.JsonPropertyInfo.RuntimeTypeInfo; } else { jsonTypeInfo = Current.CtorArgumentState !.JsonParameterInfo !.RuntimeTypeInfo; } } else if (converterStrategy == ConverterStrategy.Value) { // Although ConverterStrategy.Value doesn't push, a custom custom converter may re-enter serialization. jsonTypeInfo = Current.JsonPropertyInfo !.RuntimeTypeInfo; } else { Debug.Assert(((ConverterStrategy.Enumerable | ConverterStrategy.Dictionary) & converterStrategy) != 0); jsonTypeInfo = Current.JsonTypeInfo.ElementTypeInfo !; } AddCurrent(); Current.Reset(); Current.JsonTypeInfo = jsonTypeInfo; Current.JsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo; // Allow number handling on property to win over handling on type. Current.NumberHandling = numberHandling ?? Current.JsonPropertyInfo.NumberHandling; } } else if (_continuationCount == 1) { // No need for a push since there is only one stack frame. Debug.Assert(_count == 1); _continuationCount = 0; } else { // A continuation; adjust the index. Current = _previous[_count - 1]; // Check if we are done. if (_count == _continuationCount) { _continuationCount = 0; } else { _count++; } } SetConstructorArgumentState(); }