public void InitializeRoot(Type type, JsonSerializerOptions options) { JsonClassInfo jsonClassInfo = options.GetOrAddClass(type); Debug.Assert(jsonClassInfo.ClassType != ClassType.Invalid); Current.JsonClassInfo = jsonClassInfo; // The initial JsonPropertyInfo will be used to obtain the converter. Current.JsonPropertyInfo = jsonClassInfo.PolicyProperty !; if (options.ReferenceHandling.ShouldReadPreservedReferences()) { ReferenceResolver = new DefaultReferenceResolver(writing: false); } }
public void Initialize(Type type, JsonSerializerOptions options, bool supportContinuation) { JsonClassInfo jsonClassInfo = options.GetOrAddClass(type); Current.JsonClassInfo = jsonClassInfo; // The initial JsonPropertyInfo will be used to obtain the converter. Current.JsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo; if (options.ReferenceHandling.ShouldReadPreservedReferences()) { ReferenceResolver = new DefaultReferenceResolver(writing: false); } SupportContinuation = supportContinuation; }
internal JsonPropertyInfo GetJsonPropertyInfoFromClassInfo(JsonClassInfo classInfo, JsonSerializerOptions options) { if (classInfo.ClassType != ClassType.Object) { return(classInfo.GetPolicyProperty()); } Type objectType = classInfo.Type; if (!_objectJsonProperties.TryGetValue(objectType, out JsonPropertyInfo propertyInfo)) { propertyInfo = JsonClassInfo.CreateProperty(objectType, objectType, null, typeof(object), options); _objectJsonProperties[objectType] = propertyInfo; } return(propertyInfo); }
public virtual void Initialize( Type parentClassType, Type declaredPropertyType, Type runtimePropertyType, Type implementedPropertyType, PropertyInfo propertyInfo, Type elementType, JsonConverter converter, JsonSerializerOptions options) { ParentClassType = parentClassType; DeclaredPropertyType = declaredPropertyType; RuntimePropertyType = runtimePropertyType; ImplementedPropertyType = implementedPropertyType; PropertyInfo = propertyInfo; ElementType = elementType; Options = options; IsNullableType = runtimePropertyType.IsGenericType && runtimePropertyType.GetGenericTypeDefinition() == typeof(Nullable <>); CanBeNull = IsNullableType || !runtimePropertyType.IsValueType; if (converter != null) { ConverterBase = converter; HasInternalConverter = (converter.GetType().Assembly == GetType().Assembly); // Avoid calling GetClassType since it will re-ask if there is a converter which is slow. if (runtimePropertyType == typeof(object)) { ClassType = ClassType.Unknown; } else { ClassType = ClassType.Value; } } // Special case for immutable collections. else if (declaredPropertyType != implementedPropertyType && !JsonClassInfo.IsNativelySupportedCollection(declaredPropertyType)) { ClassType = JsonClassInfo.GetClassType(declaredPropertyType, options); } else { ClassType = JsonClassInfo.GetClassType(runtimePropertyType, options); } }
/// <summary> /// Initialize the state without delayed initialization of the JsonClassInfo. /// </summary> public JsonConverter Initialize(Type type, JsonSerializerOptions options, bool supportContinuation) { JsonClassInfo jsonClassInfo = options.GetOrAddClassForRootType(type); Current.JsonClassInfo = jsonClassInfo; Current.DeclaredJsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo; Current.NumberHandling = Current.DeclaredJsonPropertyInfo.NumberHandling; if (options.ReferenceHandler != null) { ReferenceResolver = options.ReferenceHandler !.CreateResolver(writing: true); } SupportContinuation = supportContinuation; return(jsonClassInfo.PropertyInfoForClassInfo.ConverterBase); }
private void DeterminePropertyName() { if (PropertyInfo == null) { return; } JsonPropertyNameAttribute nameAttribute = GetAttribute <JsonPropertyNameAttribute>(PropertyInfo); if (nameAttribute != null) { string name = nameAttribute.Name; if (name == null) { ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(ParentClassType, this); } NameAsString = name; } else if (Options.PropertyNamingPolicy != null) { string name = Options.PropertyNamingPolicy.ConvertName(PropertyInfo.Name); if (name == null) { ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(ParentClassType, this); } NameAsString = name; } else { NameAsString = PropertyInfo.Name; } Debug.Assert(NameAsString != null); // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder. Name = Encoding.UTF8.GetBytes(NameAsString); // Cache the escaped property name. EscapedName = JsonEncodedText.Encode(Name, Options.Encoder); ulong key = JsonClassInfo.GetKey(Name); PropertyNameKey = key; }
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); } }
public void Push() { if (_continuationCount == 0) { if (_count == 0) { // The first stack frame is held in Current. _count = 1; } else { JsonClassInfo jsonClassInfo = Current.GetPolymorphicJsonPropertyInfo().RuntimeClassInfo; JsonNumberHandling?numberHandling = Current.NumberHandling; AddCurrent(); Current.Reset(); Current.JsonClassInfo = jsonClassInfo; Current.DeclaredJsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo; // Allow number handling on property to win over handling on type. Current.NumberHandling = numberHandling ?? Current.DeclaredJsonPropertyInfo.NumberHandling; } } else if (_continuationCount == 1) { // No need for a push since there is only one stack frame. Debug.Assert(_count == 1); _continuationCount = 0; } else { // A continuation, adjust the index. Current = _previous[_count - 1]; // Check if we are done. if (_count == _continuationCount) { _continuationCount = 0; } else { _count++; } } }
/// <summary> /// Initialize the state without delayed initialization of the JsonClassInfo. /// </summary> public void Initialize(Type type, JsonSerializerOptions options, bool supportContinuation) { JsonClassInfo jsonClassInfo = options.GetOrAddClass(type); Current.JsonClassInfo = jsonClassInfo; if ((jsonClassInfo.ClassType & (ClassType.Enumerable | ClassType.Dictionary)) == 0) { Current.DeclaredJsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo; } if (options.ReferenceHandling.ShouldWritePreservedReferences()) { ReferenceResolver = new DefaultReferenceResolver(writing: true); } SupportContinuation = supportContinuation; }
public virtual void Initialize( Type parentClassType, Type declaredPropertyType, Type runtimePropertyType, PropertyInfo propertyInfo, Type elementType, JsonSerializerOptions options) { ParentClassType = parentClassType; DeclaredPropertyType = declaredPropertyType; RuntimePropertyType = runtimePropertyType; PropertyInfo = propertyInfo; ClassType = JsonClassInfo.GetClassType(runtimePropertyType); _elementType = elementType; Options = options; IsNullableType = runtimePropertyType.IsGenericType && runtimePropertyType.GetGenericTypeDefinition() == typeof(Nullable <>); CanBeNull = IsNullableType || !runtimePropertyType.IsValueType; }
private JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options) { JsonPropertyInfo jsonInfo = CreateProperty(propertyType, propertyType, propertyInfo, classType, options); // Convert non-immutable dictionary interfaces to concrete types. if (propertyType.IsInterface && jsonInfo.ClassType == ClassType.Dictionary) { JsonClassInfo elementClassInfo = jsonInfo.ElementClassInfo; JsonPropertyInfo elementPropertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementClassInfo, options); Type newPropertyType = elementPropertyInfo.GetDictionaryConcreteType(); if (propertyType != newPropertyType) { jsonInfo = CreateProperty(propertyType, newPropertyType, propertyInfo, classType, options); } } else if (jsonInfo.ClassType == ClassType.Enumerable && !propertyType.IsArray && (IsDeserializedByAssigningFromList(propertyType) || IsSetInterface(propertyType))) { JsonClassInfo elementClassInfo = jsonInfo.ElementClassInfo; JsonPropertyInfo elementPropertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementClassInfo, options); // Get a runtime type for the property. e.g. ISet<T> -> HashSet<T>, ICollection -> List<object> // We use the element's JsonPropertyInfo so we can utilize the generic support. Type newPropertyType = elementPropertyInfo.GetConcreteType(propertyType); if ((propertyType != newPropertyType) && propertyType.IsAssignableFrom(newPropertyType)) { jsonInfo = CreateProperty(propertyType, newPropertyType, propertyInfo, classType, options); } } if (propertyInfo != null) { _propertyRefs.Add(new PropertyRef(GetKey(jsonInfo.NameUsedToCompare), jsonInfo)); } else { // A single property or an IEnumerable _propertyRefs.Add(new PropertyRef(0, jsonInfo)); } return(jsonInfo); }
public void Push(JsonClassInfo nextClassInfo, object nextValue) { Push(); Current.JsonClassInfo = nextClassInfo; Current.CurrentValue = nextValue; ClassType classType = nextClassInfo.ClassType; if (classType == ClassType.Enumerable || nextClassInfo.ClassType == ClassType.Dictionary) { Current.PopStackOnEndCollection = true; Current.JsonPropertyInfo = Current.JsonClassInfo.PolicyProperty; } else { Debug.Assert(nextClassInfo.ClassType == ClassType.Object || nextClassInfo.ClassType == ClassType.Unknown); Current.PopStackOnEndObject = true; } }
public void Initialize(Type type, JsonSerializerOptions options, bool supportContinuation) { JsonClassInfo jsonClassInfo = options.GetOrAddClassForRootType(type); Current.JsonClassInfo = jsonClassInfo; // The initial JsonPropertyInfo will be used to obtain the converter. Current.JsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo; bool preserveReferences = options.ReferenceHandler != null; if (preserveReferences) { ReferenceResolver = options.ReferenceHandler !.CreateResolver(writing: false); } SupportContinuation = supportContinuation; UseFastPath = !supportContinuation && !preserveReferences; }
public void Read(JsonTokenType tokenType, ref ReadStack state, ref Utf8JsonReader reader) { Debug.Assert(ShouldDeserialize); JsonPropertyInfo propertyInfo; JsonClassInfo elementClassInfo = ElementClassInfo; if (elementClassInfo != null && (propertyInfo = elementClassInfo.PolicyProperty) != null) { if (!state.Current.CollectionPropertyInitialized) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(propertyInfo.RuntimePropertyType); } // Forward the setter to the value-based JsonPropertyInfo. propertyInfo.ReadEnumerable(tokenType, ref state, ref reader); } // For performance on release build, don't verify converter correctness for internal converters. else if (HasInternalConverter) { #if DEBUG JsonTokenType originalTokenType = reader.TokenType; int originalDepth = reader.CurrentDepth; long originalBytesConsumed = reader.BytesConsumed; #endif OnRead(ref state, ref reader); #if DEBUG VerifyRead(originalTokenType, originalDepth, originalBytesConsumed, ref reader); #endif } else { JsonTokenType originalTokenType = reader.TokenType; int originalDepth = reader.CurrentDepth; long originalBytesConsumed = reader.BytesConsumed; OnRead(ref state, ref reader); VerifyRead(originalTokenType, originalDepth, originalBytesConsumed, ref reader); } }
public void Push() { if (_continuationCount == 0) { if (_count == 0) { // The first stack frame is held in Current. _count = 1; } else { JsonClassInfo jsonClassInfo = Current.GetPolymorphicJsonPropertyInfo().RuntimeClassInfo; AddCurrent(); Current.Reset(); Current.JsonClassInfo = jsonClassInfo; Current.DeclaredJsonPropertyInfo = jsonClassInfo.PolicyProperty !; } } else if (_continuationCount == 1) { // No need for a push since there is only one stack frame. Debug.Assert(_count == 1); _continuationCount = 0; } else { // A continuation, adjust the index. Current = _previous[_count - 1]; // Check if we are done. if (_count == _continuationCount) { _continuationCount = 0; } else { _count++; } } }
private static void HandleStartObject(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { Debug.Assert(!state.Current.IsProcessingDictionary && !state.Current.IsProcessingIDictionaryConstructible); if (state.Current.IsProcessingEnumerable) { // A nested object within an enumerable. Type objType = state.Current.GetElementType(); state.Push(); state.Current.Initialize(objType, options); } else if (state.Current.JsonPropertyInfo != null) { // Nested object. Type objType = state.Current.JsonPropertyInfo.RuntimePropertyType; state.Push(); state.Current.Initialize(objType, options); } JsonClassInfo classInfo = state.Current.JsonClassInfo; if (classInfo.CreateObject is null && classInfo.ClassType == ClassType.Object) { if (classInfo.Type.IsInterface) { ThrowHelper.ThrowInvalidOperationException_DeserializePolymorphicInterface(classInfo.Type); } else { ThrowHelper.ThrowInvalidOperationException_DeserializeMissingParameterlessConstructor(classInfo.Type); } } if (state.Current.IsProcessingIDictionaryConstructible) { state.Current.TempDictionaryValues = (IDictionary)classInfo.CreateConcreteDictionary(); } else { state.Current.ReturnValue = classInfo.CreateObject(); } }
public void Initialize(Type type, JsonSerializerOptions options) { JsonClassInfo = options.GetOrAddClass(type); if (JsonClassInfo.ClassType == ClassType.Value || JsonClassInfo.ClassType == ClassType.Enumerable || JsonClassInfo.ClassType == ClassType.Dictionary) { JsonPropertyInfo = JsonClassInfo.GetPolicyProperty(); } else if (JsonClassInfo.ClassType == ClassType.IDictionaryConstructible) { JsonPropertyInfo = JsonClassInfo.GetPolicyProperty(); IsIDictionaryConstructible = true; } else if (JsonClassInfo.ClassType == ClassType.KeyValuePair) { JsonPropertyInfo = JsonClassInfo.GetPolicyPropertyOfKeyValuePair(); // Advance to the next property, since the first one is the KeyValuePair type itself, // not its first property (Key or Value). PropertyIndex++; } }
/// <summary> /// Initialize the state without delayed initialization of the JsonClassInfo. /// </summary> public void Initialize(Type type, JsonSerializerOptions options, bool supportContinuation) { JsonClassInfo jsonClassInfo = options.GetOrAddClass(type); Current.JsonClassInfo = jsonClassInfo; if ((jsonClassInfo.ClassType & (ClassType.Enumerable | ClassType.Dictionary)) == 0) { Current.DeclaredJsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo; } bool preserveReferences = options.ReferenceHandler != null; if (preserveReferences) { ReferenceResolver = options.ReferenceHandler !.CreateResolver(writing: true); } SupportContinuation = supportContinuation; }
/// <summary> /// Initialize the state without delayed initialization of the JsonClassInfo. /// </summary> public JsonConverter Initialize(Type type, JsonSerializerOptions options, bool supportContinuation) { JsonClassInfo jsonClassInfo = options.GetOrAddClassForRootType(type); Current.JsonClassInfo = jsonClassInfo; if ((jsonClassInfo.ClassType & (ClassType.Enumerable | ClassType.Dictionary)) == 0) { Current.DeclaredJsonPropertyInfo = jsonClassInfo.PropertyInfoForClassInfo; } if (options.ReferenceHandler != null) { ReferenceResolver = options.ReferenceHandler !.CreateResolver(writing: true); } SupportContinuation = supportContinuation; return(jsonClassInfo.PropertyInfoForClassInfo.ConverterBase); }
private static bool WriteObject( JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { // Write the start. if (!state.Current.StartObjectWritten) { state.Current.WriteObjectOrArrayStart(ClassType.Object, writer); } if (state.Current.MoveToNextProperty) { state.Current.NextProperty(); } // Determine if we are done enumerating properties. // If the ClassType is unknown, there will be a policy property applied. There is probably // a better way to identify policy properties- maybe not put them in the normal property bag? JsonClassInfo classInfo = state.Current.JsonClassInfo; if (classInfo.ClassType != ClassType.Unknown && state.Current.PropertyIndex != classInfo.PropertyCount) { HandleObject(options, writer, ref state); return(false); } writer.WriteEndObject(); if (state.Current.PopStackOnEndObject) { state.Pop(); } else { state.Current.EndObject(); } return(true); }
private static bool WriteObject( JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { // Write the start. if (!state.Current.StartObjectWritten) { state.Current.WriteObjectOrArrayStart(ClassType.Object, writer); state.Current.PropertyEnumerator = state.Current.JsonClassInfo.PropertyCache.GetEnumerator(); state.Current.NextProperty(); } else if (state.Current.MoveToNextProperty) { state.Current.NextProperty(); } // Determine if we are done enumerating properties. // If the ClassType is unknown, there will be a policy property applied JsonClassInfo classInfo = state.Current.JsonClassInfo; if (classInfo.ClassType != ClassType.Unknown && state.Current.PropertyEnumeratorActive) { HandleObject(options, writer, ref state); return(false); } writer.WriteEndObject(); if (state.Current.PopStackOnEndObject) { state.Pop(); } else { state.Current.EndObject(); } return(true); }
public static object?CreateDictionaryValue(ref ReadStack state) { Debug.Assert(state.Current.JsonPropertyInfo != null); JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; // If the property has a DictionaryConverter, then we use tempDictionaryValues. if (jsonPropertyInfo.DictionaryConverter != null) { IDictionary converterDictionary; JsonClassInfo elementClassInfo = jsonPropertyInfo.ElementClassInfo !; if (elementClassInfo.ClassType == ClassType.Value) { converterDictionary = elementClassInfo.PolicyProperty !.CreateConverterDictionary(); } else { converterDictionary = new Dictionary <string, object>(); } state.Current.TempDictionaryValues = converterDictionary; // Clear the value if present to ensure we don't confuse TempDictionaryValues with the collection. if (!jsonPropertyInfo.IsPropertyPolicy && jsonPropertyInfo.CanBeNull) { jsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, null); } return(null); } JsonClassInfo runtimeClassInfo = jsonPropertyInfo.RuntimeClassInfo; if (runtimeClassInfo.CreateObject == null) { ThrowHelper.ThrowNotSupportedException_DeserializeCreateObjectDelegateIsNull(jsonPropertyInfo.DeclaredPropertyType); } return(runtimeClassInfo.CreateObject()); }
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 && jsonPropertyInfo.CanBeNull) { jsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, null); } return(null); } JsonClassInfo runtimeClassInfo = jsonPropertyInfo.RuntimeClassInfo; if (runtimeClassInfo.CreateObject == null) { ThrowHelper.ThrowNotSupportedException_DeserializeCreateObjectDelegateIsNull(jsonPropertyInfo.DeclaredPropertyType); } return(runtimeClassInfo.CreateObject()); }
public virtual void Initialize( Type parentClassType, Type declaredPropertyType, Type runtimePropertyType, PropertyInfo propertyInfo, Type elementType, JsonConverter converter, JsonSerializerOptions options) { ParentClassType = parentClassType; DeclaredPropertyType = declaredPropertyType; RuntimePropertyType = runtimePropertyType; PropertyInfo = propertyInfo; _elementType = elementType; Options = options; IsNullableType = runtimePropertyType.IsGenericType && runtimePropertyType.GetGenericTypeDefinition() == typeof(Nullable <>); CanBeNull = IsNullableType || !runtimePropertyType.IsValueType; if (converter != null) { ConverterBase = converter; // Avoid calling GetClassType since it will re-ask if there is a converter which is slow. if (runtimePropertyType == typeof(object)) { ClassType = ClassType.Unknown; } else { ClassType = ClassType.Value; } } else { ClassType = JsonClassInfo.GetClassType(runtimePropertyType, options); } }
public static object CreateEnumerableValue(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { 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; return(null); } Type propertyType = state.Current.JsonPropertyInfo.RuntimePropertyType; if (typeof(IList).IsAssignableFrom(propertyType)) { // If IList, add the members as we create them. JsonClassInfo collectionClassInfo = state.Current.JsonPropertyInfo.RuntimeClassInfo; IList collection = (IList)collectionClassInfo.CreateObject(); return(collection); } else { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(propertyType, reader, state.JsonPath); return(null); } }
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; } } } } } }
private static bool HandleObject( JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { Debug.Assert( state.Current.JsonClassInfo.ClassType == ClassType.Object || state.Current.JsonClassInfo.ClassType == ClassType.Unknown); JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(state.Current.PropertyIndex); 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 an immutable dictionary 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); }
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 = (IEnumerable?)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue); if (enumerable == null) { if ((state.Current.JsonClassInfo !.ClassType != ClassType.Object || // Write null dictionary values !jsonPropertyInfo.IgnoreNullValues) && // Ignore ClassType.Object properties if IgnoreNullValues is true state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing) // Ignore null extension property (which is a dictionary) { // Write a null object or enumerable. state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, options, writeNull: true); } if (state.Current.PopStackOnEndCollection) { state.Pop(); } return(true); } if (state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing) { if (options.ReferenceHandling.ShouldWritePreservedReferences()) { if (WriteReference(ref state, writer, options, ClassType.Dictionary, enumerable)) { return(WriteEndDictionary(ref state)); } } else { state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, options); } } // Let the dictionary return the default IEnumerator from its IEnumerable.GetEnumerator(). // For IDictionary-derived classes this is normally be IDictionaryEnumerator. // For IDictionary<TKey, TVale>-derived classes this is normally IDictionaryEnumerator as well // but may be IEnumerable<KeyValuePair<TKey, TValue>> if the dictionary only supports generics. state.Current.CollectionEnumerator = enumerable.GetEnumerator(); } if (state.Current.CollectionEnumerator.MoveNext()) { // A dictionary should not have a null KeyValuePair. Debug.Assert(state.Current.CollectionEnumerator.Current != null); bool obtainedValues = false; string?key = default; object?value = default; // Check for polymorphism. if (elementClassInfo.ClassType == ClassType.Unknown) { jsonPropertyInfo.GetDictionaryKeyAndValue(ref state.Current, out key, out value); GetRuntimeClassInfo(value, ref elementClassInfo, options); obtainedValues = true; } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.PolicyProperty !.WriteDictionary(ref state, writer); } else { if (!obtainedValues) { jsonPropertyInfo.GetDictionaryKeyAndValue(ref state.Current, out key, out value); } if (options.DictionaryKeyPolicy != null && state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Writing) { Debug.Assert(key != null); key = options.DictionaryKeyPolicy.ConvertName(key); if (key == null) { ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(options.DictionaryKeyPolicy.GetType()); } } // An object or another enumerator requires a new stack frame. state.Push(elementClassInfo, value); state.Current.KeyName = key; } return(false); } // We are done enumerating. if (state.Current.ExtensionDataStatus == ExtensionDataWriteStatus.Writing) { state.Current.ExtensionDataStatus = ExtensionDataWriteStatus.Finished; } else { writer.WriteEndObject(); } return(WriteEndDictionary(ref state)); }
private static void HandleStartObject(JsonSerializerOptions options, ref ReadStack state) { Debug.Assert(!state.Current.IsProcessingDictionary()); // 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.Dictionary)) { object value = ReadStackFrame.CreateDictionaryValue(ref state); // If value is not null, then we don't have a converter so apply the value. if (value != null) { state.Current.ReturnValue = value; state.Current.DetermineIfDictionaryCanBePopulated(state.Current.ReturnValue); } 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 { // Only dictionaries or objects are valid given the `StartObject` token. ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(classInfo.Type); } }
private static void HandleEndDictionary(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { if (state.Current.IsDictionaryProperty) { // We added the items to the dictionary already. state.Current.ResetProperty(); } else if (state.Current.IsIDictionaryConstructibleProperty) { Debug.Assert(state.Current.TempDictionaryValues != null); JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter; state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options)); state.Current.ResetProperty(); } else if (state.Current.IsKeyValuePairProperty) { JsonClassInfo elementClassInfo = state.Current.JsonPropertyInfo.ElementClassInfo; JsonPropertyInfo propertyInfo; if (elementClassInfo.ClassType == ClassType.KeyValuePair) { propertyInfo = elementClassInfo.GetPolicyPropertyOfKeyValuePair(); } else { propertyInfo = elementClassInfo.GetPolicyProperty(); } Debug.Assert(state.Current.TempDictionaryValues != null); state.Current.JsonPropertyInfo.SetValueAsObject( state.Current.ReturnValue, propertyInfo.CreateKeyValuePairInstance(ref state, state.Current.TempDictionaryValues, options)); state.Current.ResetProperty(); } else { object value; if (state.Current.TempDictionaryValues != null) { if (state.Current.IsKeyValuePair) { JsonClassInfo elementClassInfo = state.Current.JsonClassInfo.ElementClassInfo; JsonPropertyInfo propertyInfo; if (elementClassInfo.ClassType == ClassType.KeyValuePair) { propertyInfo = elementClassInfo.GetPolicyPropertyOfKeyValuePair(); } else { propertyInfo = elementClassInfo.GetPolicyProperty(); } value = propertyInfo.CreateKeyValuePairInstance(ref state, state.Current.TempDictionaryValues, options); } else { JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter; value = converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options); } } else { value = state.Current.ReturnValue; } if (state.IsLastFrame) { // Set the return value directly since this will be returned to the user. state.Current.Reset(); state.Current.ReturnValue = value; } else { state.Pop(); ApplyObjectToEnumerable(value, ref state, ref reader); } } }