public override IEnumerable CreateDerivedEnumerableInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IList sourceList)
        {
            // Implementing types that don't have default constructors are not supported for deserialization.
            if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
            {
                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                          collectionPropertyInfo.DeclaredPropertyType,
                          collectionPropertyInfo.ParentClassType,
                          collectionPropertyInfo.PropertyInfo);
            }

            object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();

            if (instance is IList instanceOfIList)
            {
                if (!instanceOfIList.IsReadOnly)
                {
                    foreach (object item in sourceList)
                    {
                        instanceOfIList.Add(item);
                    }
                    return(instanceOfIList);
                }
            }
            else if (instance is ICollection <TRuntimeProperty> instanceOfICollection)
            {
                if (!instanceOfICollection.IsReadOnly)
                {
                    foreach (TRuntimeProperty item in sourceList)
                    {
                        instanceOfICollection.Add(item);
                    }
                    return(instanceOfICollection);
                }
            }
            else if (instance is Stack <TRuntimeProperty> instanceOfStack)
            {
                foreach (TRuntimeProperty item in sourceList)
                {
                    instanceOfStack.Push(item);
                }
                return(instanceOfStack);
            }
            else if (instance is Queue <TRuntimeProperty> instanceOfQueue)
            {
                foreach (TRuntimeProperty item in sourceList)
                {
                    instanceOfQueue.Enqueue(item);
                }
                return(instanceOfQueue);
            }

            // TODO (https://github.com/dotnet/corefx/issues/40479):
            // Use reflection to support types implementing Stack or Queue.

            throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                      collectionPropertyInfo.DeclaredPropertyType,
                      collectionPropertyInfo.ParentClassType,
                      collectionPropertyInfo.PropertyInfo);
        }
        public override object CreateDerivedDictionaryInstance(JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options)
        {
            object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();

            if (instance is IDictionary instanceOfIDictionary)
            {
                if (!instanceOfIDictionary.IsReadOnly)
                {
                    foreach (DictionaryEntry entry in sourceDictionary)
                    {
                        instanceOfIDictionary.Add((string)entry.Key, entry.Value);
                    }
                    return(instanceOfIDictionary);
                }
            }
            else if (instance is IDictionary <string, TRuntimeProperty> instanceOfGenericIDictionary)
            {
                if (!instanceOfGenericIDictionary.IsReadOnly)
                {
                    foreach (DictionaryEntry entry in sourceDictionary)
                    {
                        instanceOfGenericIDictionary.Add((string)entry.Key, (TRuntimeProperty)entry.Value);
                    }
                    return(instanceOfGenericIDictionary);
                }
            }

            // TODO: Use reflection to support types implementing SortedList and maybe immutable dictionaries.

            // Types implementing SortedList and immutable dictionaries will fail here.
            throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                      collectionPropertyInfo.DeclaredPropertyType,
                      collectionPropertyInfo.ParentClassType,
                      collectionPropertyInfo.PropertyInfo);
        }
Exemple #3
0
        public void GetDictionaryKeyAndValue(ref WriteStackFrame writeStackFrame, out string key, out object value)
        {
            Debug.Assert(ClassType == ClassType.Dictionary);

            if (writeStackFrame.CollectionEnumerator is IDictionaryEnumerator iDictionaryEnumerator)
            {
                if (iDictionaryEnumerator.Key is string keyAsString)
                {
                    // Since IDictionaryEnumerator is not based on generics we can obtain the value directly.
                    key   = keyAsString;
                    value = iDictionaryEnumerator.Value;
                }
                else
                {
                    throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                              writeStackFrame.JsonPropertyInfo.DeclaredPropertyType,
                              writeStackFrame.JsonPropertyInfo.ParentClassType,
                              writeStackFrame.JsonPropertyInfo.PropertyInfo);
                }
            }
            else
            {
                // Forward to the generic dictionary.
                DictionaryValuePropertyPolicy.GetDictionaryKeyAndValueFromGenericDictionary(ref writeStackFrame, out key, out value);
            }
        }
Exemple #4
0
        public void DetermineEnumerablePopulationStrategy(object targetEnumerable)
        {
            if (JsonPropertyInfo.RuntimeClassInfo.AddItemToObject != null)
            {
                if (!JsonPropertyInfo.TryCreateEnumerableAddMethod(targetEnumerable, out object addMethodDelegate))
                {
                    // No "add" method for this collection, hence, not supported for deserialization.
                    throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                              JsonPropertyInfo.DeclaredPropertyType,
                              JsonPropertyInfo.ParentClassType,
                              JsonPropertyInfo.PropertyInfo);
                }

                AddObjectToEnumerable = addMethodDelegate;
            }
            else if (targetEnumerable is IList targetList)
            {
                if (targetList.IsReadOnly)
                {
                    throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                              JsonPropertyInfo.DeclaredPropertyType,
                              JsonPropertyInfo.ParentClassType,
                              JsonPropertyInfo.PropertyInfo);
                }
            }
            // If there's no add method, and we can't cast to IList, this collection is not supported for deserialization.
            else
            {
                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                          JsonPropertyInfo.DeclaredPropertyType,
                          JsonPropertyInfo.ParentClassType,
                          JsonPropertyInfo.PropertyInfo);
            }
        }
        public override ImmutableCollectionCreator ImmutableDictionaryCreateRange(Type constructingType, Type collectionType, Type elementType)
        {
            Debug.Assert(collectionType.IsGenericType);

            // Only string keys are allowed.
            if (collectionType.GetGenericArguments()[0] != typeof(string))
            {
                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(collectionType, parentType: null, memberInfo: null);
            }

            MethodInfo createRange = ImmutableDictionaryCreateRangeMethod(constructingType, elementType);

            if (createRange == null)
            {
                return(null);
            }

            Type            creatorType = typeof(ImmutableDictionaryCreator <,>).MakeGenericType(elementType, collectionType);
            ConstructorInfo constructor = creatorType.GetConstructor(
                BindingFlags.Public |
                BindingFlags.NonPublic |
                BindingFlags.Instance, binder: null,
                Type.EmptyTypes,
                modifiers: null);

            ImmutableCollectionCreator creator = (ImmutableCollectionCreator)constructor.Invoke(Array.Empty <object>());

            creator.RegisterCreatorDelegateFromMethod(createRange);
            return(creator);
        }
Exemple #6
0
        internal static void WriteDictionary <TProperty>(
            JsonConverter <TProperty> converter,
            JsonSerializerOptions options,
            ref WriteStackFrame current,
            Utf8JsonWriter writer)
        {
            Debug.Assert(converter != null && current.CollectionEnumerator != null);

            string    key;
            TProperty value;

            if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, TProperty> > enumerator)
            {
                key   = enumerator.Current.Key;
                value = enumerator.Current.Value;
            }
            else if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, object> > polymorphicEnumerator)
            {
                key   = polymorphicEnumerator.Current.Key;
                value = (TProperty)polymorphicEnumerator.Current.Value;
            }
            else
            {
                if (((DictionaryEntry)current.CollectionEnumerator.Current).Key is string keyAsString)
                {
                    key   = keyAsString;
                    value = (TProperty)((DictionaryEntry)current.CollectionEnumerator.Current).Value;
                }
                else
                {
                    throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                              current.JsonPropertyInfo.DeclaredPropertyType,
                              current.JsonPropertyInfo.ParentClassType,
                              current.JsonPropertyInfo.PropertyInfo);
                }
            }

            if (value == null)
            {
                writer.WriteNull(key);
            }
            else
            {
                if (options.DictionaryKeyPolicy != null &&
                    current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing) // We do not convert extension data.
                {
                    key = options.DictionaryKeyPolicy.ConvertName(key);

                    if (key == null)
                    {
                        ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(options.DictionaryKeyPolicy.GetType());
                    }
                }

                writer.WritePropertyName(key);
                converter.Write(writer, value, options);
            }
        }
Exemple #7
0
 public void DetermineIfDictionaryCanBePopulated(object targetDictionary)
 {
     if (!JsonPropertyInfo.CanPopulateDictionary(targetDictionary))
     {
         throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                   JsonPropertyInfo.DeclaredPropertyType,
                   JsonPropertyInfo.ParentClassType,
                   JsonPropertyInfo.PropertyInfo);
     }
 }
Exemple #8
0
        protected override void OnWriteDictionary(ref WriteStackFrame current, Utf8JsonWriter writer)
        {
            Debug.Assert(Converter != null && current.CollectionEnumerator != null);

            string    key   = null;
            TProperty?value = null;

            if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, TProperty?> > enumerator)
            {
                key   = enumerator.Current.Key;
                value = enumerator.Current.Value;
            }
            else
            {
                if (((DictionaryEntry)current.CollectionEnumerator.Current).Key is string keyAsString)
                {
                    key   = keyAsString;
                    value = (TProperty?)((DictionaryEntry)current.CollectionEnumerator.Current).Value;
                }
                else
                {
                    throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                              current.JsonPropertyInfo.DeclaredPropertyType,
                              current.JsonPropertyInfo.ParentClassType,
                              current.JsonPropertyInfo.PropertyInfo);
                }
            }

            Debug.Assert(key != null);

            if (Options.DictionaryKeyPolicy != null)
            {
                // We should not be in the Nullable-value implementation branch for extension data.
                // (TValue should be typeof(object) or typeof(JsonElement)).
                Debug.Assert(current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing);

                key = Options.DictionaryKeyPolicy.ConvertName(key);

                if (key == null)
                {
                    ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(Options.DictionaryKeyPolicy.GetType());
                }
            }

            if (value == null)
            {
                writer.WriteNull(key);
            }
            else
            {
                writer.WritePropertyName(key);
                Converter.Write(writer, value.GetValueOrDefault(), Options);
            }
        }
 public override void AddObjectToParentDictionary(object target, string key, object value)
 {
     if (target is IDictionary <string, TDeclaredProperty> genericDict)
     {
         Debug.Assert(!genericDict.IsReadOnly);
         genericDict[key] = (TDeclaredProperty)value;
     }
     else
     {
         throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(target.GetType(), parentType: null, memberInfo: null);
     }
 }
        public override IEnumerable CreateDerivedEnumerableInstance(JsonPropertyInfo collectionPropertyInfo, IList sourceList, string jsonPath, JsonSerializerOptions options)
        {
            object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();

            if (instance is IList instanceOfIList)
            {
                if (!instanceOfIList.IsReadOnly)
                {
                    foreach (object item in sourceList)
                    {
                        instanceOfIList.Add(item);
                    }
                    return(instanceOfIList);
                }
            }
            else if (instance is ICollection <TRuntimeProperty> instanceOfICollection)
            {
                if (!instanceOfICollection.IsReadOnly)
                {
                    foreach (TRuntimeProperty item in sourceList)
                    {
                        instanceOfICollection.Add(item);
                    }
                    return(instanceOfICollection);
                }
            }
            else if (instance is Stack <TRuntimeProperty> instanceOfStack)
            {
                foreach (TRuntimeProperty item in sourceList)
                {
                    instanceOfStack.Push(item);
                }
                return(instanceOfStack);
            }
            else if (instance is Queue <TRuntimeProperty> instanceOfQueue)
            {
                foreach (TRuntimeProperty item in sourceList)
                {
                    instanceOfQueue.Enqueue(item);
                }
                return(instanceOfQueue);
            }

            // TODO: Use reflection to support types implementing Stack or Queue.

            throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                      collectionPropertyInfo.DeclaredPropertyType,
                      collectionPropertyInfo.ParentClassType,
                      collectionPropertyInfo.PropertyInfo);
        }
        protected override void OnWriteDictionary(ref WriteStackFrame current, Utf8JsonWriter writer)
        {
            Debug.Assert(Converter != null && current.CollectionEnumerator != null);

            string    key   = null;
            TProperty?value = null;

            if (current.CollectionEnumerator is IEnumerator <KeyValuePair <string, TProperty?> > enumerator)
            {
                key   = enumerator.Current.Key;
                value = enumerator.Current.Value;
            }
            else
            {
                if (((DictionaryEntry)current.CollectionEnumerator.Current).Key is string keyAsString)
                {
                    key   = keyAsString;
                    value = (TProperty?)((DictionaryEntry)current.CollectionEnumerator.Current).Value;
                }
                else
                {
                    throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                              current.JsonPropertyInfo.DeclaredPropertyType,
                              current.JsonPropertyInfo.ParentClassType,
                              current.JsonPropertyInfo.PropertyInfo);
                }
            }

            Debug.Assert(key != null);

            if (value == null)
            {
                writer.WriteNull(key);
            }
            else
            {
                if (Options.DictionaryKeyPolicy != null)
                {
                    key = Options.DictionaryKeyPolicy.ConvertName(key);

                    if (key == null)
                    {
                        ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(Options.DictionaryKeyPolicy.GetType());
                    }
                }

                writer.WritePropertyName(key);
                Converter.Write(writer, value.GetValueOrDefault(), Options);
            }
        }
 public override void GetDictionaryKeyAndValueFromGenericDictionary(ref WriteStackFrame writeStackFrame, out string key, out object value)
 {
     if (writeStackFrame.CollectionEnumerator is IEnumerator <KeyValuePair <string, TDeclaredProperty> > genericEnumerator)
     {
         key   = genericEnumerator.Current.Key;
         value = genericEnumerator.Current.Value;
     }
     else
     {
         throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                   writeStackFrame.JsonPropertyInfo.DeclaredPropertyType,
                   writeStackFrame.JsonPropertyInfo.ParentClassType,
                   writeStackFrame.JsonPropertyInfo.PropertyInfo);
     }
 }
        public override ImmutableCollectionCreator ImmutableDictionaryCreateRange(Type constructingType, Type collectionType, Type elementType)
        {
            Debug.Assert(collectionType.IsGenericType);

            // Only string keys are allowed.
            if (collectionType.GetGenericArguments()[0] != typeof(string))
            {
                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(collectionType, parentType: null, memberInfo: null);
            }

            MethodInfo createRange = ImmutableDictionaryCreateRangeMethod(constructingType, elementType);

            if (createRange == null)
            {
                return(null);
            }

            Type creatorType = typeof(ImmutableDictionaryCreator <,>).MakeGenericType(elementType, collectionType);

            ConstructorInfo realMethod = creatorType.GetConstructor(
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                binder: null,
                Type.EmptyTypes,
                modifiers: null);

            Debug.Assert(realMethod != null);

            var dynamicMethod = new DynamicMethod(
                ConstructorInfo.ConstructorName,
                typeof(object),
                Type.EmptyTypes,
                typeof(ReflectionEmitMemberAccessor).Module,
                skipVisibility: true);

            ILGenerator generator = dynamicMethod.GetILGenerator();

            generator.Emit(OpCodes.Newobj, realMethod);
            generator.Emit(OpCodes.Ret);

            JsonClassInfo.ConstructorDelegate constructor = (JsonClassInfo.ConstructorDelegate)dynamicMethod.CreateDelegate(
                typeof(JsonClassInfo.ConstructorDelegate));

            ImmutableCollectionCreator creator = (ImmutableCollectionCreator)constructor();

            creator.RegisterCreatorDelegateFromMethod(createRange);
            return(creator);
        }
Exemple #14
0
        private void DetermineSerializationCapabilities()
        {
            if ((ClassType & (ClassType.Enumerable | ClassType.Dictionary)) == 0)
            {
                // We serialize if there is a getter + not ignoring readonly properties.
                ShouldSerialize = HasGetter && (HasSetter || !Options.IgnoreReadOnlyProperties);

                // We deserialize if there is a setter.
                ShouldDeserialize = HasSetter;
            }
            else
            {
                if (HasGetter)
                {
                    ShouldSerialize = true;

                    if (HasSetter)
                    {
                        ShouldDeserialize = true;

                        if (RuntimePropertyType.IsArray)
                        {
                            // Verify that we don't have a multidimensional array.
                            if (RuntimePropertyType.GetArrayRank() > 1)
                            {
                                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(RuntimePropertyType, ParentClassType, PropertyInfo);
                            }

                            EnumerableConverter = s_jsonArrayConverter;
                        }
                        else if (ClassType == ClassType.Dictionary && DefaultImmutableDictionaryConverter.IsImmutableDictionary(RuntimePropertyType))
                        {
                            DefaultImmutableDictionaryConverter.RegisterImmutableDictionary(RuntimePropertyType, ElementType, Options);
                            DictionaryConverter = s_jsonImmutableDictionaryConverter;
                        }
                        else if (ClassType == ClassType.Enumerable && DefaultImmutableEnumerableConverter.IsImmutableEnumerable(RuntimePropertyType, out bool isImmutableArray))
                        {
                            DefaultImmutableEnumerableConverter.RegisterImmutableCollection(RuntimePropertyType, ElementType, Options);
                            EnumerableConverter = s_jsonImmutableEnumerableConverter;

                            IsImmutableArray = isImmutableArray;
                        }
                    }
                }
            }
        }
        public override object CreateDerivedDictionaryInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary)
        {
            // Implementing types that don't have default constructors are not supported for deserialization.
            if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
            {
                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                          collectionPropertyInfo.DeclaredPropertyType,
                          collectionPropertyInfo.ParentClassType,
                          collectionPropertyInfo.PropertyInfo);
            }

            object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();

            if (instance is IDictionary instanceOfIDictionary)
            {
                if (!instanceOfIDictionary.IsReadOnly)
                {
                    foreach (DictionaryEntry entry in sourceDictionary)
                    {
                        instanceOfIDictionary.Add((string)entry.Key, entry.Value);
                    }
                    return(instanceOfIDictionary);
                }
            }
            else if (instance is IDictionary <string, TRuntimeProperty> instanceOfGenericIDictionary)
            {
                if (!instanceOfGenericIDictionary.IsReadOnly)
                {
                    foreach (DictionaryEntry entry in sourceDictionary)
                    {
                        instanceOfGenericIDictionary.Add((string)entry.Key, (TRuntimeProperty)entry.Value);
                    }
                    return(instanceOfGenericIDictionary);
                }
            }

            // TODO (https://github.com/dotnet/corefx/issues/40479):
            // Use reflection to support types implementing SortedList and maybe immutable dictionaries.

            // Types implementing SortedList and immutable dictionaries will fail here.
            throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                      collectionPropertyInfo.DeclaredPropertyType,
                      collectionPropertyInfo.ParentClassType,
                      collectionPropertyInfo.PropertyInfo);
        }
Exemple #16
0
        public static object CreateEnumerableValue(ref ReadStack state)
        {
            JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;

            // If the property has an EnumerableConverter, then we use tempEnumerableValues.
            if (jsonPropertyInfo.EnumerableConverter != null)
            {
                IList         converterList;
                JsonClassInfo elementClassInfo = jsonPropertyInfo.ElementClassInfo;
                if (elementClassInfo.ClassType == ClassType.Value)
                {
                    converterList = 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.IsImmutableArray)
                {
                    jsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, null);
                }

                return(null);
            }

            JsonClassInfo runtimeClassInfo = jsonPropertyInfo.RuntimeClassInfo;

            if (runtimeClassInfo.CreateObject != null)
            {
                return(runtimeClassInfo.CreateObject());
            }
            else
            {
                // Could not create an instance to be returned. For derived types, this means there is no parameterless ctor.
                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                          jsonPropertyInfo.DeclaredPropertyType,
                          jsonPropertyInfo.ParentClassType,
                          jsonPropertyInfo.PropertyInfo);
            }
        }
Exemple #17
0
        // Return the element type of the IEnumerable or return null if not an IEnumerable.
        public static Type GetElementType(Type propertyType, Type parentType, MemberInfo memberInfo, JsonSerializerOptions options)
        {
            if (!typeof(IEnumerable).IsAssignableFrom(propertyType))
            {
                return(null);
            }

            // Check for Array.
            Type elementType = propertyType.GetElementType();

            if (elementType != null)
            {
                return(elementType);
            }

            // Check for Dictionary<TKey, TValue> or IEnumerable<T>
            if (propertyType.IsGenericType)
            {
                Type[]    args      = propertyType.GetGenericArguments();
                ClassType classType = GetClassType(propertyType, options);

                if ((classType == ClassType.Dictionary || classType == ClassType.IDictionaryConstructible) &&
                    args.Length >= 2 && // It is >= 2 in case there is a IDictionary<TKey, TValue, TSomeExtension>.
                    args[0].UnderlyingSystemType == typeof(string))
                {
                    return(args[1]);
                }

                if (classType == ClassType.Enumerable && args.Length >= 1) // It is >= 1 in case there is an IEnumerable<T, TSomeExtension>.
                {
                    return(args[0]);
                }
            }

            if (propertyType.IsAssignableFrom(typeof(IList)) ||
                propertyType.IsAssignableFrom(typeof(IDictionary)) ||
                IsDeserializedByConstructingWithIList(propertyType) ||
                IsDeserializedByConstructingWithIDictionary(propertyType))
            {
                return(typeof(object));
            }

            throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(propertyType, parentType, memberInfo);
        }
Exemple #18
0
        public override IEnumerable CreateDerivedEnumerableInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IList sourceList)
        {
            // Implementing types that don't have default constructors are not supported for deserialization.
            if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
            {
                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(
                          collectionPropertyInfo.DeclaredPropertyType,
                          collectionPropertyInfo.ParentClassType,
                          collectionPropertyInfo.PropertyInfo);
            }

            object instance = collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject();

            if (instance is IList instanceOfIList && !instanceOfIList.IsReadOnly)
            {
                foreach (object item in sourceList)
                {
                    instanceOfIList.Add(item);
                }

                return(instanceOfIList);
            }
Exemple #19
0
        private void DetermineSerializationCapabilities()
        {
            if (ClassType != ClassType.Enumerable &&
                ClassType != ClassType.Dictionary &&
                ClassType != ClassType.IDictionaryConstructible)
            {
                // We serialize if there is a getter + not ignoring readonly properties.
                ShouldSerialize = HasGetter && (HasSetter || !Options.IgnoreReadOnlyProperties);

                // We deserialize if there is a setter.
                ShouldDeserialize = HasSetter;
            }
            else
            {
                if (HasGetter)
                {
                    ShouldSerialize = true;

                    if (HasSetter)
                    {
                        ShouldDeserialize = true;

                        if (RuntimePropertyType.IsArray)
                        {
                            // Verify that we don't have a multidimensional array.
                            if (RuntimePropertyType.GetArrayRank() > 1)
                            {
                                throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(RuntimePropertyType, ParentClassType, PropertyInfo);
                            }

                            EnumerableConverter = s_jsonArrayConverter;
                        }
                        else if (ClassType == ClassType.IDictionaryConstructible)
                        {
                            // Natively supported type.
                            if (DeclaredPropertyType == ImplementedPropertyType)
                            {
                                if (RuntimePropertyType.FullName.StartsWith(JsonClassInfo.ImmutableNamespaceName))
                                {
                                    DefaultImmutableDictionaryConverter.RegisterImmutableDictionary(
                                        RuntimePropertyType, JsonClassInfo.GetElementType(RuntimePropertyType, ParentClassType, PropertyInfo, Options), Options);

                                    DictionaryConverter = s_jsonImmutableDictionaryConverter;
                                }
                                else if (JsonClassInfo.IsDeserializedByConstructingWithIDictionary(RuntimePropertyType))
                                {
                                    DictionaryConverter = s_jsonIDictionaryConverter;
                                }
                            }
                            // Type that implements a type with ClassType IDictionaryConstructible.
                            else
                            {
                                DictionaryConverter = s_jsonDerivedDictionaryConverter;
                            }
                        }
                        else if (ClassType == ClassType.Enumerable)
                        {
                            // Else if it's an implementing type whose runtime type is not assignable to IList.
                            if (DeclaredPropertyType != ImplementedPropertyType &&
                                (!typeof(IList).IsAssignableFrom(RuntimePropertyType) ||
                                 ImplementedPropertyType == typeof(ArrayList) ||
                                 ImplementedPropertyType == typeof(IList)))
                            {
                                EnumerableConverter = s_jsonDerivedEnumerableConverter;
                            }
                            else if (JsonClassInfo.IsDeserializedByConstructingWithIList(RuntimePropertyType) ||
                                     (!typeof(IList).IsAssignableFrom(RuntimePropertyType) &&
                                      JsonClassInfo.HasConstructorThatTakesGenericIEnumerable(RuntimePropertyType, Options)))
                            {
                                EnumerableConverter = s_jsonICollectionConverter;
                            }
                            else if (RuntimePropertyType.IsGenericType &&
                                     RuntimePropertyType.FullName.StartsWith(JsonClassInfo.ImmutableNamespaceName) &&
                                     RuntimePropertyType.GetGenericArguments().Length == 1)
                            {
                                DefaultImmutableEnumerableConverter.RegisterImmutableCollection(RuntimePropertyType,
                                                                                                JsonClassInfo.GetElementType(RuntimePropertyType, ParentClassType, PropertyInfo, Options), Options);
                                EnumerableConverter = s_jsonImmutableEnumerableConverter;
                            }
                        }
                    }
                }
            }
        }
        // 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)
                    {
                        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 && state.Current.JsonPropertyInfo != 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
                    {
                        Debug.Assert(currentDictionary != null);
                        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);
            }
        }
        private static void HandleStartDictionary(JsonSerializerOptions options, 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.CollectionPropertyInitialized)
            {
                state.Push();
                state.Current.JsonClassInfo = jsonPropertyInfo.ElementClassInfo;
                state.Current.InitializeJsonPropertyInfo();

                JsonClassInfo classInfo = state.Current.JsonClassInfo;

                if (state.Current.IsProcessingIDictionaryConstructible())
                {
                    state.Current.TempDictionaryValues          = (IDictionary)classInfo.CreateConcreteDictionary();
                    state.Current.CollectionPropertyInitialized = true;
                }
                else if (state.Current.IsProcessingDictionary())
                {
                    if (classInfo.CreateObject == null)
                    {
                        throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(classInfo.Type, parentType: null, memberInfo: null);
                    }

                    state.Current.ReturnValue = classInfo.CreateObject();
                    state.Current.CollectionPropertyInitialized = true;
                }
                else if (state.Current.IsProcessingObject(ClassType.Object))
                {
                    if (classInfo.CreateObject == null)
                    {
                        ThrowHelper.ThrowNotSupportedException_DeserializeCreateObjectDelegateIsNull(classInfo.Type);
                    }

                    state.Current.ReturnValue = classInfo.CreateObject();
                }
                else
                {
                    ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(classInfo.Type);
                }

                return;
            }

            state.Current.CollectionPropertyInitialized = true;

            if (state.Current.IsProcessingIDictionaryConstructible())
            {
                JsonClassInfo dictionaryClassInfo;
                if (jsonPropertyInfo.DeclaredPropertyType == jsonPropertyInfo.ImplementedPropertyType)
                {
                    dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.RuntimePropertyType);
                }
                else
                {
                    dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.DeclaredPropertyType);
                }

                state.Current.TempDictionaryValues = (IDictionary)dictionaryClassInfo.CreateConcreteDictionary();
            }
            else
            {
                // 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);
                    }
                }
            }
        }
Exemple #22
0
        private static void HandleStartObject(JsonSerializerOptions options, ref ReadStack state)
        {
            Debug.Assert(!state.Current.IsProcessingDictionaryOrIDictionaryConstructible());

            // Note: unless we are a root object, we are going to push a property onto the ReadStack
            // in the if/else if check below.

            if (state.Current.IsProcessingEnumerable())
            {
                // A nested object within an enumerable (non-dictionary).

                if (!state.Current.CollectionPropertyInitialized)
                {
                    // We have bad JSON: enumerable element appeared without preceding StartArray token.
                    ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonPropertyInfo.DeclaredPropertyType);
                }

                Type objType = state.Current.GetElementType();
                state.Push();
                state.Current.Initialize(objType, options);
            }
            else if (state.Current.JsonPropertyInfo != null)
            {
                // Nested object within an object.
                Debug.Assert(state.Current.IsProcessingObject(ClassType.Object));

                Type objType = state.Current.JsonPropertyInfo.RuntimePropertyType;
                state.Push();
                state.Current.Initialize(objType, options);
            }

            JsonClassInfo classInfo = state.Current.JsonClassInfo;

            if (state.Current.IsProcessingObject(ClassType.IDictionaryConstructible))
            {
                state.Current.TempDictionaryValues          = (IDictionary)classInfo.CreateConcreteDictionary();
                state.Current.CollectionPropertyInitialized = true;
            }
            else if (state.Current.IsProcessingObject(ClassType.Dictionary))
            {
                if (classInfo.CreateObject == null)
                {
                    throw ThrowHelper.GetNotSupportedException_SerializationNotSupportedCollection(classInfo.Type, parentType: null, memberInfo: null);
                }

                state.Current.ReturnValue = classInfo.CreateObject();
                state.Current.CollectionPropertyInitialized = true;
            }
            else if (state.Current.IsProcessingObject(ClassType.Object))
            {
                if (classInfo.CreateObject == null)
                {
                    ThrowHelper.ThrowNotSupportedException_DeserializeCreateObjectDelegateIsNull(classInfo.Type);
                }

                state.Current.ReturnValue = classInfo.CreateObject();

                if (state.Current.IsProcessingDictionary())
                {
                    state.Current.CollectionPropertyInitialized = true;
                }
            }
            else
            {
                // Only dictionaries or objects are valid given the `StartObject` token.
                ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(classInfo.Type);
            }
        }