private static bool HandleEndArray( JsonSerializerOptions options, ref ReadStack state) { bool lastFrame = state.IsLastFrame; if (state.Current.Drain) { // The array is not being applied to the object. state.Pop(); return(lastFrame); } IEnumerable value = ReadStackFrame.GetEnumerableValue(ref state.Current); if (state.Current.TempEnumerableValues != null) { // We have a converter; possibilities: // - Add value to current frame's current property or TempEnumerableValues. // - Add value to previous frame's current property or TempEnumerableValues. // - Set current property on current frame to value. // - Set current property on previous frame to value. // - Set ReturnValue if root frame and value is the actual return value. JsonEnumerableConverter converter = state.Current.JsonPropertyInfo.EnumerableConverter; Debug.Assert(converter != null); value = converter.CreateFromList(ref state, (IList)value, options); state.Current.TempEnumerableValues = null; } else if (state.Current.IsProcessingProperty(ClassType.Enumerable)) { // We added the items to the list already. state.Current.EndProperty(); return(false); } if (lastFrame) { if (state.Current.ReturnValue == null) { // Returning a converted list or object. state.Current.Reset(); state.Current.ReturnValue = value; return(true); } else if (state.Current.IsProcessingCollectionObject()) { // Returning a non-converted list. return(true); } // else there must be an outer object, so we'll return false here. } else if (state.Current.IsProcessingObject(ClassType.Enumerable)) { state.Pop(); } ApplyObjectToEnumerable(value, ref state); return(false); }
private static void HandleEndObject(ref ReadStack state) { // Only allow dictionaries to be processed here if this is the DataExtensionProperty. Debug.Assert(!state.Current.IsProcessingDictionary() || state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo); // Check if we are trying to build the sorted cache. if (state.Current.PropertyRefCache != null) { state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current); } object value = state.Current.ReturnValue; if (state.IsLastFrame) { state.Current.Reset(); state.Current.ReturnValue = value; } else { state.Pop(); ApplyObjectToEnumerable(value, ref state); } }
private static void HandleEndObject(ref ReadStack state) { // Only allow dictionaries to be processed here if this is the DataExtensionProperty. Debug.Assert( (!state.Current.IsProcessingDictionary() || state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo) && !state.Current.IsProcessingIDictionaryConstructible()); if (state.Current.JsonClassInfo.ClassType == ClassType.Value) { // We should be in a converter, thus we must have bad JSON. ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonPropertyInfo.RuntimePropertyType); } // Check if we are trying to build the sorted cache. if (state.Current.PropertyRefCache != null) { state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current); } object value = state.Current.ReturnValue; if (state.IsLastFrame) { state.Current.Reset(); state.Current.ReturnValue = value; } else { state.Pop(); ApplyObjectToEnumerable(value, ref state); } }
private static void HandleEndDictionary(JsonSerializerOptions options, ref ReadStack state) { Debug.Assert(!state.Current.SkipProperty && state.Current.JsonPropertyInfo != null); if (state.Current.IsProcessingProperty(ClassType.Dictionary)) { if (state.Current.TempDictionaryValues != null) { JsonDictionaryConverter?converter = state.Current.JsonPropertyInfo.DictionaryConverter; Debug.Assert(converter != null); state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options)); state.Current.EndProperty(); } else { Debug.Assert(state.Current.JsonClassInfo != null); // Handle special case of DataExtensionProperty where we just added a dictionary element to the extension property. // Since the JSON value is not a dictionary element (it's a normal property in JSON) a JsonTokenType.EndObject // encountered here is from the outer object so forward to HandleEndObject(). if (state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo) { HandleEndObject(ref state); } else { // We added the items to the dictionary already. state.Current.EndProperty(); } } } else { object?value; if (state.Current.TempDictionaryValues != null) { JsonDictionaryConverter?converter = state.Current.JsonPropertyInfo.DictionaryConverter; Debug.Assert(converter != null); 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); } } }
private static void HandleEndDictionary(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { if (state.Current.SkipProperty) { return; } if (state.Current.IsDictionaryProperty) { // We added the items to the dictionary already. state.Current.EndProperty(); } 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.EndProperty(); } else { object value; if (state.Current.TempDictionaryValues != null) { 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); } } }
private static void HandleEndObject(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { Debug.Assert(!state.Current.IsProcessingDictionary && !state.Current.IsProcessingIDictionaryConstructible); state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current); object value = state.Current.ReturnValue; if (state.IsLastFrame) { state.Current.Reset(); state.Current.ReturnValue = value; } else { state.Pop(); ApplyObjectToEnumerable(value, ref state, ref reader); } }
private static void HandleEndObject(ref ReadStack state) { Debug.Assert(state.Current.JsonClassInfo != null); // Only allow dictionaries to be processed here if this is the DataExtensionProperty or if the dictionary is a preserved reference. Debug.Assert(!state.Current.IsProcessingDictionary() || state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo || (state.Current.IsProcessingObject(ClassType.Dictionary) && state.Current.ReferenceId != null)); // Check if we are trying to build the sorted cache. if (state.Current.PropertyRefCache != null) { state.Current.JsonClassInfo.UpdateSortedPropertyCache(ref state.Current); } object?value; // Used for ReferenceHandling.Preserve if (state.Current.IsPreservedArray) { value = GetPreservedArrayValue(ref state); } else { value = state.Current.ReturnValue; } if (state.IsLastFrame) { state.Current.Reset(); state.Current.ReturnValue = value; } else { // Set directly when handling non-nested preserved array bool setPropertyDirectly = state.Current.IsPreservedArray && !state.Current.IsNestedPreservedArray; state.Pop(); ApplyObjectToEnumerable(value, ref state, setPropertyDirectly); } }
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.IsImmutableDictionaryProperty) { Debug.Assert(state.Current.TempDictionaryValues != null); state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, CreateImmutableDictionaryFromTempValues(ref state, options)); state.Current.ResetProperty(); } else { object value; if (state.Current.TempDictionaryValues != null) { value = CreateImmutableDictionaryFromTempValues(ref state, 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); } } }
private static bool HandleEndArray( JsonSerializerOptions options, ref ReadStack state) { bool lastFrame = state.IsLastFrame; if (state.Current.Drain) { // The array is not being applied to the object. state.Pop(); return(lastFrame); } IEnumerable?value = ReadStackFrame.GetEnumerableValue(ref state.Current); bool setPropertyDirectly = false; if (state.Current.TempEnumerableValues != null) { Debug.Assert(state.Current.JsonPropertyInfo != null); // We have a converter; possibilities: // - Add value to current frame's current property or TempEnumerableValues. // - Add value to previous frame's current property or TempEnumerableValues. // - Set current property on current frame to value. // - Set current property on previous frame to value. // - Set ReturnValue if root frame and value is the actual return value. JsonEnumerableConverter?converter = state.Current.JsonPropertyInfo.EnumerableConverter; Debug.Assert(converter != null); value = converter.CreateFromList(ref state, (IList)value !, options); state.Current.TempEnumerableValues = null; // Since we used a converter, we just processed an array or an immutable collection. This means we created a new enumerable object. // If we are processing an enumerable property, replace the current value of the property with the new instance. if (state.Current.IsProcessingProperty(ClassType.Enumerable)) { setPropertyDirectly = true; } } else if (state.Current.IsProcessingProperty(ClassType.Enumerable)) { // We added the items to the list already. state.Current.EndProperty(); return(false); } if (lastFrame) { if (state.Current.ReturnValue == null) { // Returning a converted list or object. state.Current.Reset(); state.Current.ReturnValue = value; return(true); } else if (state.Current.IsProcessingCollectionObject()) { // Returning a non-converted list. return(true); } // else there must be an outer object, so we'll return false here. } else if (state.Current.IsProcessingObject(ClassType.Enumerable)) { state.Pop(); } ApplyObjectToEnumerable(value, ref state, setPropertyDirectly); return(false); }
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); } } }
private static void ReadCore( JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack readStack) { try { JsonReaderState initialState = default; long initialBytesConsumed = default; while (true) { if (readStack.ReadAhead) { // When we're reading ahead we always have to save the state // as we don't know if the next token is an opening object or // array brace. initialState = reader.CurrentState; initialBytesConsumed = reader.BytesConsumed; } if (!reader.Read()) { // Need more data break; } JsonTokenType tokenType = reader.TokenType; if (options.ReferenceHandling.ShouldReadPreservedReferences()) { CheckValidTokenAfterMetadataValues(ref readStack, tokenType); } if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False)) { Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False); HandleValue(tokenType, options, ref reader, ref readStack); } else if (tokenType == JsonTokenType.PropertyName) { HandlePropertyName(options, ref reader, ref readStack); } else if (tokenType == JsonTokenType.StartObject) { if (readStack.Current.SkipProperty) { readStack.Push(); readStack.Current.Drain = true; } else if (readStack.Current.IsProcessingValue()) { if (!HandleObjectAsValue(tokenType, options, ref reader, ref readStack, ref initialState, initialBytesConsumed)) { // Need more data break; } } else if (readStack.Current.IsProcessingDictionary()) { HandleStartDictionary(options, ref readStack); } else { HandleStartObject(options, ref readStack); } } else if (tokenType == JsonTokenType.EndObject) { if (readStack.Current.Drain) { readStack.Pop(); // 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. readStack.Current.EndProperty(); } else if (readStack.Current.ReferenceId != null) { Debug.Assert(options.ReferenceHandling.ShouldReadPreservedReferences()); HandleReference(ref readStack); } else if (readStack.Current.IsProcessingDictionary()) { HandleEndDictionary(options, ref readStack); } else { HandleEndObject(ref readStack); } } else if (tokenType == JsonTokenType.StartArray) { if (!readStack.Current.IsProcessingValue()) { HandleStartArray(options, ref readStack); } else if (!HandleObjectAsValue(tokenType, options, ref reader, ref readStack, ref initialState, initialBytesConsumed)) { // Need more data break; } } else if (tokenType == JsonTokenType.EndArray) { HandleEndArray(options, ref readStack); } else if (tokenType == JsonTokenType.Null) { HandleNull(options, ref reader, ref readStack); } } } catch (JsonReaderException ex) { // Re-throw with Path information. ThrowHelper.ReThrowWithPath(readStack, ex); } catch (FormatException ex) when(ex.Source == ThrowHelper.ExceptionSourceValueToRethrowAsJsonException) { ThrowHelper.ReThrowWithPath(readStack, reader, ex); } catch (InvalidOperationException ex) when(ex.Source == ThrowHelper.ExceptionSourceValueToRethrowAsJsonException) { ThrowHelper.ReThrowWithPath(readStack, reader, ex); } catch (JsonException ex) { ThrowHelper.AddExceptionInformation(readStack, reader, ex); throw; } readStack.BytesConsumed += reader.BytesConsumed; }
private static void ReadCore( JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack readStack) { try { JsonReaderState initialState = default; long initialBytesConsumed = default; while (true) { if (readStack.ReadAhead) { // When we're reading ahead we always have to save the state // as we don't know if the next token is an opening object or // array brace. initialState = reader.CurrentState; initialBytesConsumed = reader.BytesConsumed; } if (!reader.Read()) { // Need more data break; } JsonTokenType tokenType = reader.TokenType; if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False)) { Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False); HandleValue(tokenType, options, ref reader, ref readStack); } else if (tokenType == JsonTokenType.PropertyName) { HandlePropertyName(options, ref reader, ref readStack); } else if (tokenType == JsonTokenType.StartObject) { if (readStack.Current.SkipProperty) { readStack.Push(); readStack.Current.Drain = true; } else if (readStack.Current.IsProcessingValue(tokenType)) { if (!HandleObjectAsValue(tokenType, options, ref reader, ref readStack, ref initialState, initialBytesConsumed)) { // Need more data break; } } else if (readStack.Current.IsProcessingDictionary || readStack.Current.IsProcessingIDictionaryConstructible) { HandleStartDictionary(options, ref reader, ref readStack); } else { HandleStartObject(options, ref reader, ref readStack); } } else if (tokenType == JsonTokenType.EndObject) { if (readStack.Current.Drain) { readStack.Pop(); } else if (readStack.Current.IsProcessingDictionary || readStack.Current.IsProcessingIDictionaryConstructible) { HandleEndDictionary(options, ref reader, ref readStack); } else { HandleEndObject(options, ref reader, ref readStack); } } else if (tokenType == JsonTokenType.StartArray) { if (!readStack.Current.IsProcessingValue(tokenType)) { HandleStartArray(options, ref reader, ref readStack); } else if (!HandleObjectAsValue(tokenType, options, ref reader, ref readStack, ref initialState, initialBytesConsumed)) { // Need more data break; } } else if (tokenType == JsonTokenType.EndArray) { HandleEndArray(options, ref reader, ref readStack); } else if (tokenType == JsonTokenType.Null) { HandleNull(ref reader, ref readStack, options); } } } catch (JsonReaderException ex) { // Re-throw with Path information. ThrowHelper.ReThrowWithPath(readStack, ex); } catch (FormatException ex) when(ex.Source == ThrowHelper.ExceptionSourceValueToRethrowAsJsonException) { ThrowHelper.ReThrowWithPath(readStack, reader, ex); } catch (InvalidOperationException ex) when(ex.Source == ThrowHelper.ExceptionSourceValueToRethrowAsJsonException) { ThrowHelper.ReThrowWithPath(readStack, reader, ex); } catch (JsonException ex) { ThrowHelper.AddExceptionInformation(readStack, reader, ex); throw; } readStack.BytesConsumed += reader.BytesConsumed; return; }