예제 #1
0
        public static void ThrowInvalidOperationException_IgnoreConditionOnValueTypeInvalid(JsonPropertyInfo jsonPropertyInfo)
        {
            MemberInfo memberInfo = jsonPropertyInfo.MemberInfo !;

            throw new InvalidOperationException(SR.Format(SR.IgnoreConditionOnValueTypeInvalid, memberInfo.Name, memberInfo.DeclaringType));
        }
        public static void ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(JsonPropertyInfo jsonPropertyInfo)
        {
            MemberInfo?memberInfo = jsonPropertyInfo.MemberInfo;

            Debug.Assert(memberInfo != null);
            Debug.Assert(!jsonPropertyInfo.IsForTypeInfo);

            throw new InvalidOperationException(SR.Format(SR.NumberHandlingOnPropertyInvalid, memberInfo.Name, memberInfo.DeclaringType));
        }
예제 #3
0
 public static void ThrowInvalidOperationException_SerializerPropertyNameConflict(Type type, JsonPropertyInfo jsonPropertyInfo)
 {
     throw new InvalidOperationException(SR.Format(SR.SerializerPropertyNameConflict, type, jsonPropertyInfo.PropertyInfo?.Name));
 }
예제 #4
0
 // Copy any settings defined at run-time to the new property.
 public void CopyRuntimeSettingsTo(JsonPropertyInfo other)
 {
     other.EscapedName     = EscapedName;
     other.Name            = Name;
     other.PropertyNameKey = PropertyNameKey;
 }
        private static void GetRuntimePropertyInfo(object?value, JsonClassInfo jsonClassInfo, ref JsonPropertyInfo jsonPropertyInfo, JsonSerializerOptions options)
        {
            if (value != null)
            {
                Type runtimeType = value.GetType();

                // Nothing to do for typeof(object)
                if (runtimeType != typeof(object))
                {
                    jsonPropertyInfo = jsonClassInfo.GetOrAddPolymorphicProperty(jsonPropertyInfo, runtimeType, options);
                }
            }
        }
        internal static JsonPropertyInfo CreateProperty(
            Type declaredPropertyType,
            Type runtimePropertyType,
            PropertyInfo propertyInfo,
            Type parentClassType,
            Type collectionElementType,
            Type nullableUnderlyingType,
            JsonConverter converter,
            ClassType classType,
            JsonSerializerOptions options)
        {
            bool treatAsNullable = nullableUnderlyingType != null;

            // Obtain the type of the JsonPropertyInfo class to construct.
            Type propertyInfoClassType;

            if (treatAsNullable && converter != null)
            {
                propertyInfoClassType = typeof(JsonPropertyInfoNullable <,>).MakeGenericType(parentClassType, nullableUnderlyingType);
            }
            else
            {
                Type typeToConvert = converter?.TypeToConvert;
                if (typeToConvert == null)
                {
                    typeToConvert = declaredPropertyType;
                }

                // For the covariant case, create JsonPropertyInfoNotNullable. The generic constraints are "where TConverter : TDeclaredProperty".
                if (runtimePropertyType.IsAssignableFrom(typeToConvert))
                {
                    propertyInfoClassType = typeof(JsonPropertyInfoNotNullable <, , ,>).MakeGenericType(
                        parentClassType,
                        declaredPropertyType,
                        runtimePropertyType,
                        typeToConvert);
                }
                else
                {
                    Debug.Assert(typeToConvert.IsAssignableFrom(runtimePropertyType));

                    // For the contravariant case, create JsonPropertyInfoNotNullableContravariant. The generic constraints are "where TDeclaredProperty : TConverter".
                    propertyInfoClassType = typeof(JsonPropertyInfoNotNullableContravariant <, , ,>).MakeGenericType(
                        parentClassType,
                        declaredPropertyType,
                        runtimePropertyType,
                        typeToConvert);
                }
            }

            // Create the JsonPropertyInfo instance.
            JsonPropertyInfo jsonPropertyInfo = (JsonPropertyInfo)Activator.CreateInstance(
                propertyInfoClassType,
                BindingFlags.Instance | BindingFlags.Public,
                binder: null,
                args: null,
                culture: null);

            jsonPropertyInfo.Initialize(
                parentClassType,
                declaredPropertyType,
                runtimePropertyType,
                runtimeClassType: classType,
                propertyInfo,
                collectionElementType,
                converter,
                treatAsNullable,
                options);

            return(jsonPropertyInfo);
        }
예제 #7
0
        internal JsonClassInfo(Type type, JsonSerializerOptions options)
        {
            Type      = type;
            Options   = options;
            ClassType = GetClassType(type, options);

            CreateObject = options.MemberAccessorStrategy.CreateConstructor(type);

            // Ignore properties on enumerable.
            switch (ClassType)
            {
            case ClassType.Object:
            {
                PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

                Dictionary <string, JsonPropertyInfo> cache = CreatePropertyCache(properties.Length);

                foreach (PropertyInfo propertyInfo in properties)
                {
                    // Ignore indexers
                    if (propertyInfo.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }

                    // For now we only support public getters\setters
                    if (propertyInfo.GetMethod?.IsPublic == true ||
                        propertyInfo.SetMethod?.IsPublic == true)
                    {
                        JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo.PropertyType, propertyInfo, type, options);
                        Debug.Assert(jsonPropertyInfo != null);

                        // If the JsonPropertyNameAttribute or naming policy results in collisions, throw an exception.
                        if (!JsonHelpers.TryAdd(cache, jsonPropertyInfo.NameAsString, jsonPropertyInfo))
                        {
                            JsonPropertyInfo other = cache[jsonPropertyInfo.NameAsString];

                            if (other.ShouldDeserialize == false && other.ShouldSerialize == false)
                            {
                                // Overwrite the one just added since it has [JsonIgnore].
                                cache[jsonPropertyInfo.NameAsString] = jsonPropertyInfo;
                            }
                            else if (jsonPropertyInfo.ShouldDeserialize == true || jsonPropertyInfo.ShouldSerialize == true)
                            {
                                ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(this, jsonPropertyInfo);
                            }
                            // else ignore jsonPropertyInfo since it has [JsonIgnore].
                        }
                    }
                }

                // Set as a unit to avoid concurrency issues.
                PropertyCache = cache;

                DetermineExtensionDataProperty();
            }
            break;

            case ClassType.Enumerable:
            case ClassType.Dictionary:
            {
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);

                // Use the type from the property policy to get any late-bound concrete types (from an interface like IDictionary).
                CreateObject = options.MemberAccessorStrategy.CreateConstructor(PolicyProperty.RuntimePropertyType);

                // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies.
                Type elementType = GetElementType(type, parentType: null, memberInfo: null, options: options);
                ElementClassInfo = options.GetOrAddClass(elementType);
            }
            break;

            case ClassType.IDictionaryConstructible:
            {
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);

                Type elementType = GetElementType(type, parentType: null, memberInfo: null, options: options);

                CreateObject = options.MemberAccessorStrategy.CreateConstructor(
                    typeof(Dictionary <,>).MakeGenericType(typeof(string), elementType));

                // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies.
                ElementClassInfo = options.GetOrAddClass(elementType);
            }
            break;

            case ClassType.Value:
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);
                break;

            case ClassType.Unknown:
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);
                PropertyCache = new Dictionary <string, JsonPropertyInfo>();
                break;

            default:
                Debug.Fail($"Unexpected class type: {ClassType}");
                break;
            }
        }
        private static bool HandleNull(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state)
        {
            if (state.Current.SkipProperty)
            {
                // Clear the current property in case it is a dictionary, since dictionaries must have EndProperty() called when completed.
                // A non-dictionary property can also have EndProperty() called when completed, although it is redundant.
                state.Current.EndProperty();

                return(false);
            }

            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

            if (jsonPropertyInfo == null || (reader.CurrentDepth == 0 && jsonPropertyInfo.CanBeNull))
            {
                Debug.Assert(state.IsLastFrame);
                Debug.Assert(state.Current.ReturnValue == null);
                return(true);
            }

            Debug.Assert(jsonPropertyInfo != null);

            if (state.Current.IsProcessingCollectionObject())
            {
                AddNullToCollection(jsonPropertyInfo, ref reader, ref state);
                return(false);
            }

            if (state.Current.IsProcessingCollectionProperty())
            {
                if (state.Current.CollectionPropertyInitialized)
                {
                    // Add the element.
                    AddNullToCollection(jsonPropertyInfo, ref reader, ref state);
                }
                else
                {
                    // Set the property to null.
                    ApplyObjectToEnumerable(null, ref state, setPropertyDirectly: true);

                    // Reset so that `Is*Property` no longer returns true
                    state.Current.EndProperty();
                }

                return(false);
            }

            if (!jsonPropertyInfo.CanBeNull)
            {
                // Allow a value type converter to return a null value representation, such as JsonElement.
                // Most likely this will throw JsonException.
                jsonPropertyInfo.Read(JsonTokenType.Null, ref state, ref reader);
                return(false);
            }

            if (state.Current.ReturnValue == null)
            {
                Debug.Assert(state.IsLastFrame);
                return(true);
            }

            if (!jsonPropertyInfo.IgnoreNullValues)
            {
                state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value: null);
            }

            return(false);
        }
예제 #9
0
 public abstract IEnumerable CreateDerivedEnumerableInstance(JsonPropertyInfo collectionPropertyInfo, IList sourceList, string jsonPath, JsonSerializerOptions options);
        internal static JsonPropertyInfo CreateProperty(Type declaredPropertyType, Type runtimePropertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options)
        {
            bool hasIgnoreAttribute = (JsonPropertyInfo.GetAttribute <JsonIgnoreAttribute>(propertyInfo) != null);

            if (hasIgnoreAttribute)
            {
                return(JsonPropertyInfo.CreateIgnoredPropertyPlaceholder(propertyInfo, options));
            }

            Type collectionElementType = null;

            switch (GetClassType(runtimePropertyType, options))
            {
            case ClassType.Enumerable:
            case ClassType.Dictionary:
            case ClassType.IDictionaryConstructible:
            case ClassType.Unknown:
                collectionElementType = GetElementType(runtimePropertyType, parentClassType, propertyInfo, options);
                break;
            }

            JsonConverter converter;

            // Create the JsonPropertyInfo<TType, TProperty>
            Type propertyInfoClassType;

            if (runtimePropertyType.IsGenericType && runtimePropertyType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                // For Nullable, use the underlying type.
                Type underlyingPropertyType = Nullable.GetUnderlyingType(runtimePropertyType);
                propertyInfoClassType = typeof(JsonPropertyInfoNullable <,>).MakeGenericType(parentClassType, underlyingPropertyType);
                converter             = options.DetermineConverterForProperty(parentClassType, underlyingPropertyType, propertyInfo);
            }
            else
            {
                converter = options.DetermineConverterForProperty(parentClassType, runtimePropertyType, propertyInfo);
                Type typeToConvert = converter?.TypeToConvert;
                if (typeToConvert == null)
                {
                    typeToConvert = runtimePropertyType;
                }

                // For the covariant case, create JsonPropertyInfoNotNullable. The generic constraints are "where TConverter : TDeclaredProperty".
                if (runtimePropertyType.IsAssignableFrom(typeToConvert))
                {
                    propertyInfoClassType = typeof(JsonPropertyInfoNotNullable <, , ,>).MakeGenericType(
                        parentClassType,
                        declaredPropertyType,
                        runtimePropertyType,
                        typeToConvert);
                }
                else
                {
                    Debug.Assert(typeToConvert.IsAssignableFrom(runtimePropertyType));

                    // For the contravariant case, create JsonPropertyInfoNotNullableContravariant. The generic constraints are "where TDeclaredProperty : TConverter".
                    propertyInfoClassType = typeof(JsonPropertyInfoNotNullableContravariant <, , ,>).MakeGenericType(
                        parentClassType,
                        declaredPropertyType,
                        runtimePropertyType,
                        typeToConvert);
                }
            }

            JsonPropertyInfo jsonInfo = (JsonPropertyInfo)Activator.CreateInstance(
                propertyInfoClassType,
                BindingFlags.Instance | BindingFlags.Public,
                binder: null,
                args: null,
                culture: null);

            jsonInfo.Initialize(parentClassType, declaredPropertyType, runtimePropertyType, propertyInfo, collectionElementType, converter, options);

            return(jsonInfo);
        }
        private static bool HandleObject(
            JsonPropertyInfo jsonPropertyInfo,
            JsonSerializerOptions options,
            Utf8JsonWriter writer,
            ref WriteStack state)
        {
            Debug.Assert(
                state.Current.JsonClassInfo.ClassType == ClassType.Object ||
                state.Current.JsonClassInfo.ClassType == ClassType.Unknown);

            if (!jsonPropertyInfo.ShouldSerialize)
            {
                state.Current.MoveToNextProperty = true;
                return(true);
            }

            bool   obtainedValue = false;
            object currentValue  = null;

            // Check for polymorphism.
            if (jsonPropertyInfo.ClassType == ClassType.Unknown)
            {
                currentValue  = jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue);
                obtainedValue = true;
                GetRuntimePropertyInfo(currentValue, state.Current.JsonClassInfo, ref jsonPropertyInfo, options);
            }

            state.Current.JsonPropertyInfo = jsonPropertyInfo;

            if (jsonPropertyInfo.ClassType == ClassType.Value)
            {
                jsonPropertyInfo.Write(ref state, writer);
                state.Current.MoveToNextProperty = true;
                return(true);
            }

            // A property that returns an enumerator keeps the same stack frame.
            if (jsonPropertyInfo.ClassType == ClassType.Enumerable)
            {
                bool endOfEnumerable = HandleEnumerable(jsonPropertyInfo.ElementClassInfo, options, writer, ref state);
                if (endOfEnumerable)
                {
                    state.Current.MoveToNextProperty = true;
                }

                return(endOfEnumerable);
            }

            // A property that returns a dictionary keeps the same stack frame.
            if (jsonPropertyInfo.ClassType == ClassType.Dictionary)
            {
                bool endOfEnumerable = HandleDictionary(jsonPropertyInfo.ElementClassInfo, options, writer, ref state);
                if (endOfEnumerable)
                {
                    state.Current.MoveToNextProperty = true;
                }

                return(endOfEnumerable);
            }

            // A property that returns a type that is deserialized by passing an
            // IDictionary to its constructor keeps the same stack frame.
            if (jsonPropertyInfo.ClassType == ClassType.IDictionaryConstructible)
            {
                state.Current.IsIDictionaryConstructibleProperty = true;

                bool endOfEnumerable = HandleDictionary(jsonPropertyInfo.ElementClassInfo, options, writer, ref state);
                if (endOfEnumerable)
                {
                    state.Current.MoveToNextProperty = true;
                }

                return(endOfEnumerable);
            }

            // A property that returns an object.
            if (!obtainedValue)
            {
                currentValue = jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue);
            }

            if (currentValue != null)
            {
                // A new stack frame is required.
                JsonPropertyInfo previousPropertyInfo = state.Current.JsonPropertyInfo;
                state.Current.MoveToNextProperty = true;

                JsonClassInfo nextClassInfo = jsonPropertyInfo.RuntimeClassInfo;
                state.Push(nextClassInfo, currentValue);

                // Set the PropertyInfo so we can obtain the property name in order to write it.
                state.Current.JsonPropertyInfo = previousPropertyInfo;
            }
            else
            {
                if (!jsonPropertyInfo.IgnoreNullValues)
                {
                    writer.WriteNull(jsonPropertyInfo.EscapedName.Value);
                }

                state.Current.MoveToNextProperty = true;
            }

            return(true);
        }
예제 #12
0
        internal JsonClassInfo(Type type, JsonSerializerOptions options)
        {
            Type      = type;
            ClassType = GetClassType(type, options);

            CreateObject = options.ClassMaterializerStrategy.CreateConstructor(type);

            // Ignore properties on enumerable.
            switch (ClassType)
            {
            case ClassType.Object:
            {
                var propertyNames = new HashSet <string>(StringComparer.Ordinal);

                foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
                {
                    // Ignore indexers
                    if (propertyInfo.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }

                    // For now we only support public getters\setters
                    if (propertyInfo.GetMethod?.IsPublic == true ||
                        propertyInfo.SetMethod?.IsPublic == true)
                    {
                        JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo.PropertyType, propertyInfo, type, options);

                        Debug.Assert(jsonPropertyInfo.NameUsedToCompareAsString != null);

                        // If the JsonPropertyNameAttribute or naming policy results in collisions, throw an exception.
                        if (!propertyNames.Add(jsonPropertyInfo.NameUsedToCompareAsString))
                        {
                            ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(this, jsonPropertyInfo);
                        }

                        jsonPropertyInfo.ClearUnusedValuesAfterAdd();
                    }
                }

                DetermineExtensionDataProperty();
            }
            break;

            case ClassType.Enumerable:
            case ClassType.Dictionary:
            {
                // Add a single property that maps to the class type so we can have policies applied.
                JsonPropertyInfo policyProperty = AddPolicyProperty(type, options);

                // Use the type from the property policy to get any late-bound concrete types (from an interface like IDictionary).
                CreateObject = options.ClassMaterializerStrategy.CreateConstructor(policyProperty.RuntimePropertyType);

                // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies.
                Type elementType = GetElementType(type, parentType: null, memberInfo: null, options: options);
                ElementClassInfo = options.GetOrAddClass(elementType);
            }
            break;

            case ClassType.IDictionaryConstructible:
            {
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);

                Type elementType = GetElementType(type, parentType: null, memberInfo: null, options: options);

                CreateObject = options.ClassMaterializerStrategy.CreateConstructor(
                    typeof(Dictionary <,>).MakeGenericType(typeof(string), elementType));

                // Create a ClassInfo that maps to the element type which is used for (de)serialization and policies.
                ElementClassInfo = options.GetOrAddClass(elementType);
            }
            break;

            case ClassType.Value:
            case ClassType.Unknown:
                // Add a single property that maps to the class type so we can have policies applied.
                AddPolicyProperty(type, options);
                break;

            default:
                Debug.Fail($"Unexpected class type: {ClassType}");
                break;
            }
        }
예제 #13
0
        private static bool TryIsPropertyRefEqual(ref PropertyRef propertyRef, ReadOnlySpan <byte> propertyName, ulong key, ref JsonPropertyInfo info)
        {
            if (key == propertyRef.Key)
            {
                if (propertyName.Length <= PropertyNameKeyLength ||
                    // We compare the whole name, although we could skip the first 6 bytes (but it's likely not any faster)
                    propertyName.SequenceEqual(propertyRef.Info.NameUsedToCompare))
                {
                    info = propertyRef.Info;
                    return(true);
                }
            }

            return(false);
        }
예제 #14
0
        internal JsonPropertyInfo GetProperty(JsonSerializerOptions options, ReadOnlySpan <byte> propertyName, ref ReadStackFrame frame)
        {
            // If we should compare with case-insensitive, normalize to an uppercase format since that is what is cached on the propertyInfo.
            if (options.PropertyNameCaseInsensitive)
            {
                string utf16PropertyName = JsonHelpers.Utf8GetString(propertyName);
                string upper             = utf16PropertyName.ToUpperInvariant();
                propertyName = Encoding.UTF8.GetBytes(upper);
            }

            ulong            key  = GetKey(propertyName);
            JsonPropertyInfo info = null;

            // First try sorted lookup.
            int propertyIndex = frame.PropertyIndex;

            // If we're not trying to build the cache locally, and there is an existing cache, then use it.
            bool hasPropertyCache = frame.PropertyRefCache == null && _propertyRefsSorted != null;

            if (hasPropertyCache)
            {
                // This .Length is consistent no matter what json data intialized _propertyRefsSorted.
                int count = _propertyRefsSorted.Length;
                if (count != 0)
                {
                    int iForward  = propertyIndex;
                    int iBackward = propertyIndex - 1;
                    while (iForward < count || iBackward >= 0)
                    {
                        if (iForward < count)
                        {
                            if (TryIsPropertyRefEqual(ref _propertyRefsSorted[iForward], propertyName, key, ref info))
                            {
                                return(info);
                            }
                            ++iForward;
                        }

                        if (iBackward >= 0)
                        {
                            if (TryIsPropertyRefEqual(ref _propertyRefsSorted[iBackward], propertyName, key, ref info))
                            {
                                return(info);
                            }
                            --iBackward;
                        }
                    }
                }
            }

            // Try the main list which has all of the properties in a consistent order.
            // We could get here even when hasPropertyCache==true if there is a race condition with different json
            // property ordering and _propertyRefsSorted is re-assigned while in the loop above.
            for (int i = 0; i < _propertyRefs.Count; i++)
            {
                PropertyRef propertyRef = _propertyRefs[i];
                if (TryIsPropertyRefEqual(ref propertyRef, propertyName, key, ref info))
                {
                    break;
                }
            }

            if (!hasPropertyCache)
            {
                if (propertyIndex == 0 && frame.PropertyRefCache == null)
                {
                    // Create the temporary list on first property access to prevent a partially filled List.
                    frame.PropertyRefCache = new HashSet <PropertyRef>();
                }

                if (info != null)
                {
                    Debug.Assert(frame.PropertyRefCache != null);
                    frame.PropertyRefCache.Add(new PropertyRef(key, info));
                }
            }

            return(info);
        }
예제 #15
0
        // If this method is changed, also change ApplyValueToEnumerable.
        internal static void ApplyObjectToEnumerable(
            object value,
            ref ReadStack state,
            bool setPropertyDirectly = false)
        {
            Debug.Assert(!state.Current.SkipProperty);

            if (state.Current.IsProcessingObject(ClassType.Enumerable))
            {
                if (state.Current.TempEnumerableValues != null)
                {
                    state.Current.TempEnumerableValues.Add(value);
                }
                else
                {
                    if (state.Current.AddObjectToEnumerable == null)
                    {
                        if (state.Current.ReturnValue is IList list)
                        {
                            list.Add(value);
                        }
                        else
                        {
                            ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(value.GetType());
                            return;
                        }
                    }
                    else
                    {
                        state.Current.JsonPropertyInfo.AddObjectToEnumerableWithReflection(state.Current.AddObjectToEnumerable, value);
                    }
                }
            }
            else if (!setPropertyDirectly && state.Current.IsProcessingProperty(ClassType.Enumerable))
            {
                Debug.Assert(state.Current.JsonPropertyInfo != null);
                Debug.Assert(state.Current.ReturnValue != null);

                if (state.Current.TempEnumerableValues != null)
                {
                    state.Current.TempEnumerableValues.Add(value);
                }
                else
                {
                    JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

                    object currentEnumerable = jsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue);
                    if (currentEnumerable == null ||
                        // ImmutableArray<T> is a struct, so default value won't be null.
                        jsonPropertyInfo.IsImmutableArray)
                    {
                        jsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
                    }
                    else if (state.Current.AddObjectToEnumerable == null)
                    {
                        ((IList)currentEnumerable).Add(value);
                    }
                    else
                    {
                        jsonPropertyInfo.AddObjectToEnumerableWithReflection(state.Current.AddObjectToEnumerable, value);
                    }
                }
            }
            else if (state.Current.IsProcessingObject(ClassType.Dictionary) || (state.Current.IsProcessingProperty(ClassType.Dictionary) && !setPropertyDirectly))
            {
                string key = state.Current.KeyName;
                Debug.Assert(!string.IsNullOrEmpty(key));

                if (state.Current.TempDictionaryValues != null)
                {
                    (state.Current.TempDictionaryValues)[key] = value;
                }
                else
                {
                    Debug.Assert(state.Current.ReturnValue != null);

                    object currentDictionary = state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue);

                    if (currentDictionary is IDictionary dict)
                    {
                        Debug.Assert(!dict.IsReadOnly);
                        dict[key] = value;
                    }
                    else
                    {
                        state.Current.JsonPropertyInfo.AddObjectToDictionary(currentDictionary, key, value);
                    }
                }
            }
            else
            {
                Debug.Assert(state.Current.JsonPropertyInfo != null);
                state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
            }
        }
예제 #16
0
 public abstract object CreateDerivedDictionaryInstance(JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options);
예제 #17
0
        // If this method is changed, also change ApplyObjectToEnumerable.
        internal static void ApplyValueToEnumerable <TProperty>(
            ref TProperty value,
            ref ReadStack state)
        {
            Debug.Assert(!state.Current.SkipProperty);

            if (state.Current.IsProcessingObject(ClassType.Enumerable))
            {
                if (state.Current.TempEnumerableValues != null)
                {
                    ((IList <TProperty>)state.Current.TempEnumerableValues).Add(value);
                }
                else
                {
                    AddValueToEnumerable(ref state, state.Current.ReturnValue, value);
                }
            }
            else if (state.Current.IsProcessingProperty(ClassType.Enumerable))
            {
                if (state.Current.TempEnumerableValues != null)
                {
                    ((IList <TProperty>)state.Current.TempEnumerableValues).Add(value);
                }
                else
                {
                    Debug.Assert(state.Current.JsonPropertyInfo != null);
                    Debug.Assert(state.Current.ReturnValue != null);

                    JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

                    object currentEnumerable = jsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue);
                    if (currentEnumerable == null ||
                        // ImmutableArray<T> is a struct, so default value won't be null.
                        jsonPropertyInfo.IsImmutableArray)
                    {
                        jsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
                    }
                    else
                    {
                        AddValueToEnumerable(ref state, currentEnumerable, value);
                    }
                }
            }
            else if (state.Current.IsProcessingDictionary())
            {
                string key = state.Current.KeyName;
                Debug.Assert(!string.IsNullOrEmpty(key));

                if (state.Current.TempDictionaryValues != null)
                {
                    ((IDictionary <string, TProperty>)state.Current.TempDictionaryValues)[key] = value;
                }
                else
                {
                    Debug.Assert(state.Current.ReturnValue != null);

                    object currentDictionary = state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue);

                    if (currentDictionary is IDictionary <string, TProperty> genericDict)
                    {
                        Debug.Assert(!genericDict.IsReadOnly);
                        genericDict[key] = value;
                    }
                    else if (currentDictionary is IDictionary dict)
                    {
                        Debug.Assert(!dict.IsReadOnly);
                        dict[key] = value;
                    }
                    else
                    {
                        throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(currentDictionary.GetType(), parentType: null, memberInfo: null);
                    }
                }
            }
            else
            {
                Debug.Assert(state.Current.JsonPropertyInfo != null);
                state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
            }
        }
예제 #18
0
 internal JsonPropertyInfo GetOrAddPolymorphicProperty(JsonPropertyInfo property, Type runtimePropertyType, JsonSerializerOptions options)
 {
예제 #19
0
        internal JsonPropertyInfo GetProperty(ReadOnlySpan <byte> propertyName, ref ReadStackFrame frame)
        {
            JsonPropertyInfo info = null;

            // If we're not trying to build the cache locally, and there is an existing cache, then use it.
            if (_propertyRefsSorted != null)
            {
                ulong key = GetKey(propertyName);

                // First try sorted lookup.
                int propertyIndex = frame.PropertyIndex;

                // This .Length is consistent no matter what json data intialized _propertyRefsSorted.
                int count = _propertyRefsSorted.Length;
                if (count != 0)
                {
                    int iForward  = Math.Min(propertyIndex, count);
                    int iBackward = iForward - 1;
                    while (iForward < count || iBackward >= 0)
                    {
                        if (iForward < count)
                        {
                            if (TryIsPropertyRefEqual(_propertyRefsSorted[iForward], propertyName, key, ref info))
                            {
                                return(info);
                            }
                            ++iForward;
                        }

                        if (iBackward >= 0)
                        {
                            if (TryIsPropertyRefEqual(_propertyRefsSorted[iBackward], propertyName, key, ref info))
                            {
                                return(info);
                            }
                            --iBackward;
                        }
                    }
                }
            }

            // Try the main list which has all of the properties in a consistent order.
            // We could get here even when hasPropertyCache==true if there is a race condition with different json
            // property ordering and _propertyRefsSorted is re-assigned while in the loop above.

            string stringPropertyName = JsonHelpers.Utf8GetString(propertyName);

            if (PropertyCache.TryGetValue(stringPropertyName, out info))
            {
                // For performance, only add to cache up to a threshold and then just use the dictionary.
                int count;
                if (_propertyRefsSorted != null)
                {
                    count = _propertyRefsSorted.Length;
                }
                else
                {
                    count = 0;
                }

                // Do a quick check for the stable (after warm-up) case.
                if (count < PropertyNameCountCacheThreshold)
                {
                    if (frame.PropertyRefCache != null)
                    {
                        count += frame.PropertyRefCache.Count;
                    }

                    // Check again to fill up to the limit.
                    if (count < PropertyNameCountCacheThreshold)
                    {
                        if (frame.PropertyRefCache == null)
                        {
                            frame.PropertyRefCache = new List <PropertyRef>();
                        }

                        ulong       key         = info.PropertyNameKey;
                        PropertyRef propertyRef = new PropertyRef(key, info);
                        frame.PropertyRefCache.Add(propertyRef);
                    }
                }
            }

            return(info);
        }
예제 #20
0
        public static object CreateEnumerableValue(ref Utf8JsonReader reader, ref ReadStack state)
        {
            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

            // If the property has an EnumerableConverter, then we use tempEnumerableValues.
            if (jsonPropertyInfo.EnumerableConverter != null)
            {
                IList converterList;
                if (jsonPropertyInfo.ElementClassInfo.ClassType == ClassType.Value)
                {
                    converterList = jsonPropertyInfo.ElementClassInfo.PolicyProperty.CreateConverterList();
                }
                else
                {
                    converterList = new List <object>();
                }

                state.Current.TempEnumerableValues = converterList;

                // Clear the value if present to ensure we don't confuse tempEnumerableValues with the collection.
                if (!jsonPropertyInfo.IsPropertyPolicy &&
                    !state.Current.JsonPropertyInfo.RuntimePropertyType.FullName.StartsWith(DefaultImmutableEnumerableConverter.ImmutableArrayGenericTypeName))
                {
                    jsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, null);
                }

                return(null);
            }

            Type propertyType = jsonPropertyInfo.RuntimePropertyType;

            if (typeof(IList).IsAssignableFrom(propertyType))
            {
                // If IList, add the members as we create them.
                JsonClassInfo collectionClassInfo;

                if (jsonPropertyInfo.DeclaredPropertyType == jsonPropertyInfo.ImplementedPropertyType)
                {
                    collectionClassInfo = jsonPropertyInfo.RuntimeClassInfo;
                }
                else
                {
                    collectionClassInfo = jsonPropertyInfo.DeclaredTypeClassInfo;
                }

                if (collectionClassInfo.CreateObject() is IList collection)
                {
                    return(collection);
                }
                else
                {
                    ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(jsonPropertyInfo.DeclaredPropertyType, reader, state.JsonPath);
                    return(null);
                }
            }
            else
            {
                ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(propertyType, reader, state.JsonPath);
                return(null);
            }
        }
        private static bool HandleDictionary(
            JsonClassInfo elementClassInfo,
            JsonSerializerOptions options,
            Utf8JsonWriter writer,
            ref WriteStack state)
        {
            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

            if (state.Current.CollectionEnumerator == null)
            {
                IEnumerable enumerable;

                enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue);
                if (enumerable == null)
                {
                    if (!state.Current.JsonPropertyInfo.IgnoreNullValues)
                    {
                        // Write a null object or enumerable.
                        state.Current.WriteObjectOrArrayStart(ClassType.Enumerable, writer, writeNull: true);
                    }

                    return(true);
                }

                if (enumerable is IDictionary dictionary)
                {
                    state.Current.CollectionEnumerator = dictionary.GetEnumerator();
                }
                else
                {
                    state.Current.CollectionEnumerator = enumerable.GetEnumerator();
                }

                if (state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing)
                {
                    state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer);
                }
            }

            if (state.Current.CollectionEnumerator.MoveNext())
            {
                // Check for polymorphism.
                if (elementClassInfo.ClassType == ClassType.Unknown)
                {
                    object currentValue = ((IDictionaryEnumerator)state.Current.CollectionEnumerator).Entry.Value;
                    GetRuntimeClassInfo(currentValue, ref elementClassInfo, options);
                }

                if (elementClassInfo.ClassType == ClassType.Value)
                {
                    elementClassInfo.PolicyProperty.WriteDictionary(ref state, writer);
                }
                else if (state.Current.CollectionEnumerator.Current == null)
                {
                    writer.WriteNull(jsonPropertyInfo.Name);
                }
                else
                {
                    // An object or another enumerator requires a new stack frame.
                    var    enumerator = (IDictionaryEnumerator)state.Current.CollectionEnumerator;
                    object value      = enumerator.Value;
                    state.Push(elementClassInfo, value);
                    state.Current.KeyName = (string)enumerator.Key;
                }

                return(false);
            }

            // We are done enumerating.
            if (state.Current.ExtensionDataStatus == ExtensionDataWriteStatus.Writing)
            {
                state.Current.ExtensionDataStatus = ExtensionDataWriteStatus.Finished;
            }
            else
            {
                writer.WriteEndObject();
            }

            if (state.Current.PopStackOnEndCollection)
            {
                state.Pop();
            }
            else
            {
                state.Current.EndDictionary();
            }

            return(true);
        }
예제 #22
0
        private static void HandleStartDictionary(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state)
        {
            Debug.Assert(!state.Current.IsProcessingEnumerable);

            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

            if (jsonPropertyInfo == null)
            {
                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options);
            }

            Debug.Assert(jsonPropertyInfo != null);

            // A nested object or dictionary so push new frame.
            if (state.Current.PropertyInitialized)
            {
                state.Push();
                state.Current.JsonClassInfo = jsonPropertyInfo.ElementClassInfo;
                state.Current.InitializeJsonPropertyInfo();
                state.Current.PropertyInitialized = true;

                ClassType classType = state.Current.JsonClassInfo.ClassType;
                if (classType == ClassType.Value &&
                    jsonPropertyInfo.ElementClassInfo.Type != typeof(object) &&
                    jsonPropertyInfo.ElementClassInfo.Type != typeof(JsonElement))
                {
                    ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, reader, state.JsonPath);
                }

                JsonClassInfo classInfo = state.Current.JsonClassInfo;

                if (state.Current.IsProcessingIDictionaryConstructible)
                {
                    state.Current.TempDictionaryValues = (IDictionary)classInfo.CreateObject();
                }
                else
                {
                    if (classInfo.CreateObject == null)
                    {
                        ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(classInfo.Type, reader, state.JsonPath);
                        return;
                    }
                    state.Current.ReturnValue = classInfo.CreateObject();
                }
                return;
            }

            state.Current.PropertyInitialized = true;

            if (state.Current.IsProcessingIDictionaryConstructible)
            {
                JsonClassInfo dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.RuntimePropertyType);
                state.Current.TempDictionaryValues = (IDictionary)dictionaryClassInfo.CreateObject();
            }
            // Else if current property is already set (from a constructor, for example), leave as-is.
            else if (jsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue) == null)
            {
                // Create the dictionary.
                JsonClassInfo dictionaryClassInfo = jsonPropertyInfo.RuntimeClassInfo;
                IDictionary   value = (IDictionary)dictionaryClassInfo.CreateObject();

                if (value != null)
                {
                    if (state.Current.ReturnValue != null)
                    {
                        state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
                    }
                    else
                    {
                        // A dictionary is being returned directly, or a nested dictionary.
                        state.Current.SetReturnValue(value);
                    }
                }
            }
        }
예제 #23
0
        private static void HandlePropertyName(
            JsonSerializerOptions options,
            ref Utf8JsonReader reader,
            ref ReadStack state)
        {
            if (state.Current.Drain)
            {
                return;
            }

            Debug.Assert(state.Current.ReturnValue != default || state.Current.TempDictionaryValues != default);
            Debug.Assert(state.Current.JsonClassInfo != default);

            if ((state.Current.IsProcessingDictionary || state.Current.IsProcessingIDictionaryConstructible) &&
                state.Current.JsonClassInfo.DataExtensionProperty != state.Current.JsonPropertyInfo)
            {
                if (state.Current.IsDictionary || state.Current.IsIDictionaryConstructible)
                {
                    state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.PolicyProperty;
                }

                Debug.Assert(
                    state.Current.IsDictionary ||
                    (state.Current.IsDictionaryProperty && state.Current.JsonPropertyInfo != null) ||
                    state.Current.IsIDictionaryConstructible ||
                    (state.Current.IsIDictionaryConstructibleProperty && state.Current.JsonPropertyInfo != null));

                state.Current.KeyName = reader.GetString();
            }
            else
            {
                state.Current.EndProperty();

                ReadOnlySpan <byte> propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
                if (reader._stringHasEscaping)
                {
                    int idx = propertyName.IndexOf(JsonConstants.BackSlash);
                    Debug.Assert(idx != -1);
                    propertyName = GetUnescapedString(propertyName, idx);
                }

                JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(propertyName, ref state.Current);
                if (jsonPropertyInfo == JsonPropertyInfo.s_missingProperty)
                {
                    JsonPropertyInfo dataExtProperty = state.Current.JsonClassInfo.DataExtensionProperty;
                    if (dataExtProperty == null)
                    {
                        state.Current.JsonPropertyInfo = JsonPropertyInfo.s_missingProperty;
                    }
                    else
                    {
                        state.Current.JsonPropertyInfo = dataExtProperty;
                        state.Current.JsonPropertyName = propertyName.ToArray();
                        state.Current.KeyName          = JsonHelpers.Utf8GetString(propertyName);
                        state.Current.CollectionPropertyInitialized = true;

                        CreateDataExtensionProperty(dataExtProperty, ref state);
                    }
                }
                else
                {
                    // Support JsonException.Path.
                    Debug.Assert(
                        jsonPropertyInfo.JsonPropertyName == null ||
                        options.PropertyNameCaseInsensitive ||
                        propertyName.SequenceEqual(jsonPropertyInfo.JsonPropertyName));

                    state.Current.JsonPropertyInfo = jsonPropertyInfo;

                    if (jsonPropertyInfo.JsonPropertyName == null)
                    {
                        byte[] propertyNameArray = propertyName.ToArray();
                        if (options.PropertyNameCaseInsensitive)
                        {
                            // Each payload can have a different name here; remember the value on the temporary stack.
                            state.Current.JsonPropertyName = propertyNameArray;
                        }
                        else
                        {
                            // Prevent future allocs by caching globally on the JsonPropertyInfo which is specific to a Type+PropertyName
                            // so it will match the incoming payload except when case insensitivity is enabled (which is handled above).
                            state.Current.JsonPropertyInfo.JsonPropertyName = propertyNameArray;
                        }
                    }
                }

                // Increment the PropertyIndex so JsonClassInfo.GetProperty() starts with the next property.
                state.Current.PropertyIndex++;
            }
        }
예제 #24
0
        public JsonClassInfo(Type type, JsonSerializerOptions options)
        {
            Type    = type;
            Options = options;

            JsonConverter converter = GetConverter(
                Type,
                parentClassType: null, // A ClassInfo never has a "parent" class.
                propertyInfo: null,    // A ClassInfo never has a "parent" property.
                out Type runtimeType,
                Options);

            ClassType = converter.ClassType;
            PropertyInfoForClassInfo = CreatePropertyInfoForClassInfo(Type, runtimeType, converter, Options);

            switch (ClassType)
            {
            case ClassType.Object:
            {
                CreateObject = options.MemberAccessorStrategy.CreateConstructor(type);

                PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

                Dictionary <string, JsonPropertyInfo> cache = CreatePropertyCache(properties.Length);

                foreach (PropertyInfo propertyInfo in properties)
                {
                    // Ignore indexers
                    if (propertyInfo.GetIndexParameters().Length > 0)
                    {
                        continue;
                    }

                    if (IsNonPublicProperty(propertyInfo))
                    {
                        if (JsonPropertyInfo.GetAttribute <JsonIncludeAttribute>(propertyInfo) != null)
                        {
                            ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(propertyInfo, Type);
                        }

                        // Non-public properties should not be included for (de)serialization.
                        continue;
                    }

                    // For now we only support public getters\setters
                    if (propertyInfo.GetMethod?.IsPublic == true ||
                        propertyInfo.SetMethod?.IsPublic == true)
                    {
                        JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo, type, options);
                        Debug.Assert(jsonPropertyInfo != null && jsonPropertyInfo.NameAsString != null);

                        // If the JsonPropertyNameAttribute or naming policy results in collisions, throw an exception.
                        if (!JsonHelpers.TryAdd(cache, jsonPropertyInfo.NameAsString, jsonPropertyInfo))
                        {
                            JsonPropertyInfo other = cache[jsonPropertyInfo.NameAsString];

                            if (other.ShouldDeserialize == false && other.ShouldSerialize == false)
                            {
                                // Overwrite the one just added since it has [JsonIgnore].
                                cache[jsonPropertyInfo.NameAsString] = jsonPropertyInfo;
                            }
                            else if (jsonPropertyInfo.ShouldDeserialize == true || jsonPropertyInfo.ShouldSerialize == true)
                            {
                                ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo);
                            }
                            // else ignore jsonPropertyInfo since it has [JsonIgnore].
                        }
                    }
                }

                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];
                }

                // Set fields when finished to avoid concurrency issues.
                PropertyCache = cache;
                cache.Values.CopyTo(cacheArray, 0);
                PropertyCacheArray = cacheArray;

                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 static void ThrowInvalidOperationException_ExtensionDataCannotBindToCtorParam(JsonPropertyInfo jsonPropertyInfo)
 {
     throw new InvalidOperationException(SR.Format(SR.ExtensionDataCannotBindToCtorParam, jsonPropertyInfo.ClrName, jsonPropertyInfo.DeclaringType));
 }
예제 #26
0
        public static void ThrowInvalidOperationException_NumberHandlingOnPropertyInvalid(JsonPropertyInfo jsonPropertyInfo)
        {
            MemberInfo?memberInfo = jsonPropertyInfo.MemberInfo;

            if (!jsonPropertyInfo.ConverterBase.IsInternalConverter)
            {
                throw new InvalidOperationException(SR.Format(
                                                        SR.NumberHandlingConverterMustBeBuiltIn,
                                                        jsonPropertyInfo.ConverterBase.GetType(),
                                                        jsonPropertyInfo.IsForTypeInfo ? jsonPropertyInfo.DeclaredPropertyType : memberInfo !.DeclaringType));
            }

            // This exception is only thrown for object properties.
            Debug.Assert(!jsonPropertyInfo.IsForTypeInfo && memberInfo != null);
            throw new InvalidOperationException(SR.Format(
                                                    SR.NumberHandlingOnPropertyTypeMustBeNumberOrCollection,
                                                    memberInfo.Name,
                                                    memberInfo.DeclaringType));
        }
예제 #27
0
 public void EndProperty()
 {
     JsonPropertyInfo   = null;
     KeyName            = null;
     MoveToNextProperty = false;
 }
예제 #28
0
        private static void HandleStartArray(JsonSerializerOptions options, ref ReadStack state)
        {
            if (state.Current.SkipProperty)
            {
                // The array is not being applied to the object.
                state.Push();
                state.Current.Drain = true;
                return;
            }

            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

            if (jsonPropertyInfo == null)
            {
                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootProperty(options);
            }
            else if (state.Current.JsonClassInfo.ClassType == ClassType.Unknown)
            {
                jsonPropertyInfo = state.Current.JsonClassInfo.GetOrAddPolymorphicProperty(jsonPropertyInfo, typeof(object), options);
            }

            // Verify that we have a valid enumerable.
            Type arrayType = jsonPropertyInfo.RuntimePropertyType;

            if (!typeof(IEnumerable).IsAssignableFrom(arrayType))
            {
                ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(arrayType);
            }

            Debug.Assert(state.Current.IsProcessingCollection());

            if (state.Current.CollectionPropertyInitialized)
            {
                // A nested json array so push a new stack frame.
                Type elementType = jsonPropertyInfo.ElementClassInfo.Type;

                state.Push();
                state.Current.Initialize(elementType, options);
            }

            state.Current.CollectionPropertyInitialized = true;

            // We should not be processing custom converters here (converters are of ClassType.Value).
            Debug.Assert(state.Current.JsonClassInfo.ClassType != ClassType.Value);

            // Set or replace the existing enumerable value.
            object value = ReadStackFrame.CreateEnumerableValue(ref state);

            // If value is not null, then we don't have a converter so apply the value.
            if (value != null)
            {
                state.Current.DetermineEnumerablePopulationStrategy(value);

                if (state.Current.ReturnValue != null)
                {
                    state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
                }
                else
                {
                    state.Current.ReturnValue = value;
                }
            }
        }
예제 #29
0
 public static void ThrowInvalidOperationException_SerializerPropertyNameNull(Type parentType, JsonPropertyInfo jsonPropertyInfo)
 {
     throw new InvalidOperationException(SR.Format(SR.SerializerPropertyNameNull, parentType, jsonPropertyInfo.PropertyInfo?.Name));
 }
예제 #30
0
        private static void HandleStartArray(
            JsonSerializerOptions options,
            ref Utf8JsonReader reader,
            ref ReadStack state)
        {
            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

            if (state.Current.SkipProperty)
            {
                // The array is not being applied to the object.
                state.Push();
                state.Current.Drain = true;
                return;
            }

            if (jsonPropertyInfo == null)
            {
                jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options);
            }
            else if (state.Current.JsonClassInfo.ClassType == ClassType.Unknown)
            {
                jsonPropertyInfo = state.Current.JsonClassInfo.CreatePolymorphicProperty(jsonPropertyInfo, typeof(object), options);
            }

            // Verify that we don't have a multidimensional array.
            Type arrayType = jsonPropertyInfo.RuntimePropertyType;

            if (!state.Current.IsProcessingKeyValuePair && !typeof(IEnumerable).IsAssignableFrom(arrayType) || (arrayType.IsArray && arrayType.GetArrayRank() > 1))
            {
                ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(arrayType, reader, state.JsonPath);
            }

            Debug.Assert(state.Current.IsProcessingEnumerableOrDictionary);

            if (state.Current.PropertyInitialized)
            {
                // A nested json array so push a new stack frame.
                Type elementType = jsonPropertyInfo.ElementClassInfo.Type;

                state.Push();
                state.Current.Initialize(elementType, options);
                state.Current.PropertyInitialized = true;
            }
            else
            {
                state.Current.PropertyInitialized = true;
            }

            jsonPropertyInfo = state.Current.JsonPropertyInfo;

            // If current property is already set (from a constructor, for example) leave as-is.
            if (jsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue) == null)
            {
                // Create the enumerable.
                object value = ReadStackFrame.CreateEnumerableValue(ref reader, ref state, options);

                // If value is not null, then we don't have a converter so apply the value.
                if (value != null)
                {
                    if (state.Current.ReturnValue != null)
                    {
                        state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
                    }
                    else
                    {
                        // Primitive arrays being returned without object
                        state.Current.SetReturnValue(value);
                    }
                }
            }
        }