예제 #1
0
        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;
            }
        }
예제 #2
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));
        }
예제 #3
0
        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);
        }
예제 #4
0
 public virtual void GetPolicies(JsonIgnoreCondition?ignoreCondition, JsonNumberHandling?parentTypeNumberHandling, bool defaultValueIsNull)
 {
     DetermineSerializationCapabilities(ignoreCondition);
     DeterminePropertyName();
     DetermineIgnoreCondition(ignoreCondition, defaultValueIsNull);
     DetermineNumberHandling(parentTypeNumberHandling);
 }
예제 #5
0
 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;
 }
예제 #6
0
 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;
 }
예제 #7
0
        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;
                }
            }
        }
예제 #8
0
        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
        }
예제 #9
0
        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
        }
예제 #10
0
        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;
            }
        }
예제 #11
0
        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);
        }
예제 #12
0
 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;
 }
예제 #13
0
        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
        }
예제 #14
0
        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);
            }
        }
예제 #15
0
파일: WriteStack.cs 프로젝트: z77ma/runtime
        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
        }
예제 #16
0
        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++;
                }
            }
        }
예제 #17
0
        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);
            }
        }
예제 #18
0
        /// <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);
        }
예제 #19
0
        /// <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);
        }
예제 #20
0
        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;
        }
예제 #21
0
        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;
        }
예제 #22
0
        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;
                }
            }
        }
예제 #23
0
        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);
            }
        }
예제 #24
0
        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;
        }
예제 #25
0
        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);
        }
예제 #26
0
        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);
            }
        }
예제 #27
0
        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);
        }
예제 #29
0
        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
        }
예제 #30
0
        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();
        }