private static bool HandleDictionary( JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (state.Current.Enumerator == null) { IEnumerable enumerable; enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue); if (enumerable == null) { // Write a null object or enumerable. state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, writeNull: true); return(true); } state.Current.Enumerator = ((IDictionary)enumerable).GetEnumerator(); state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer); } if (state.Current.Enumerator.MoveNext()) { // Handle DataExtension. if (ReferenceEquals(jsonPropertyInfo, state.Current.JsonClassInfo.DataExtensionProperty)) { WriteExtensionData(writer, ref state.Current); } else { // Check for polymorphism. if (elementClassInfo.ClassType == ClassType.Unknown) { object currentValue = ((IDictionaryEnumerator)state.Current.Enumerator).Entry.Value; GetRuntimeClassInfo(currentValue, ref elementClassInfo, options); } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.GetPolicyProperty().WriteDictionary(ref state.Current, writer); } else if (state.Current.Enumerator.Current == null) { writer.WriteNull(jsonPropertyInfo.Name); } else { // An object or another enumerator requires a new stack frame. var enumerator = (IDictionaryEnumerator)state.Current.Enumerator; object value = enumerator.Value; state.Push(elementClassInfo, value); state.Current.KeyName = (string)enumerator.Key; } } return(false); } // We are done enumerating. writer.WriteEndObject(); if (state.Current.PopStackOnEnd) { state.Pop(); } else { state.Current.EndDictionary(); } return(true); }
// Copy any settings defined at run-time to the new property. internal void CopyRuntimeSettingsTo(JsonPropertyInfo other) { other._name = _name; other._compareName = _compareName; other._escapedName = _escapedName; }
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 (!typeof(IEnumerable).IsAssignableFrom(arrayType) || (arrayType.IsArray && arrayType.GetArrayRank() > 1)) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(arrayType, reader, state.PropertyPath); } Debug.Assert(state.Current.IsProcessingEnumerableOrDictionary); if (state.Current.PropertyInitialized) { // A nested json array so push a new stack frame. Type elementType = state.Current.JsonClassInfo.ElementClassInfo.GetPolicyProperty().RuntimePropertyType; state.Push(); state.Current.Initialize(elementType, options); } 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 != 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); } } } }
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); }
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 = Encoding.UTF8.GetString(propertyName.ToArray()); 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) { // Create the temporary list on first property access to prevent a partially filled List. Debug.Assert(frame.PropertyRefCache == null); frame.PropertyRefCache = new List <PropertyRef>(); } if (info != null) { Debug.Assert(frame.PropertyRefCache != null); frame.PropertyRefCache.Add(new PropertyRef(key, info)); } } return(info); }
// Copy any settings defined at run-time to the new property. public void CopyRuntimeSettingsTo(JsonPropertyInfo other) { other._name = _name; other._nameUsedToCompare = _nameUsedToCompare; other._escapedName = _escapedName; }
private static bool HandleDictionary( JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (!jsonPropertyInfo.ShouldSerialize) { // Ignore writing this property. return(true); } if (state.Current.Enumerator == null) { // Verify that the Dictionary can be serialized by having <string> as first generic argument. Type[] args = jsonPropertyInfo.RuntimePropertyType.GetGenericArguments(); if (args.Length == 0 || args[0].UnderlyingSystemType != typeof(string)) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, state.PropertyPath); } IEnumerable enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue); if (enumerable == null) { // Write a null object or enumerable. state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, writeNull: true); return(true); } state.Current.Enumerator = enumerable.GetEnumerator(); state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer); } if (state.Current.Enumerator.MoveNext()) { // Check for polymorphism. if (elementClassInfo.ClassType == ClassType.Unknown) { object currentValue = ((IDictionaryEnumerator)state.Current.Enumerator).Entry; GetRuntimeClassInfo(currentValue, ref elementClassInfo, options); } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.GetPolicyProperty().WriteDictionary(options, ref state.Current, writer); } else if (state.Current.Enumerator.Current == null) { writer.WriteNull(jsonPropertyInfo.Name); } else { // An object or another enumerator requires a new stack frame. var enumerator = (IDictionaryEnumerator)state.Current.Enumerator; object value = enumerator.Value; state.Push(elementClassInfo, value); state.Current.KeyName = (string)enumerator.Key; } return(false); } // We are done enumerating. writer.WriteEndObject(); if (state.Current.PopStackOnEnd) { state.Pop(); } else { state.Current.EndDictionary(); } return(true); }