internal static MetadataPropertyName WriteMetadataForObject( JsonConverter jsonConverter, ref WriteStack state, Utf8JsonWriter writer) { Debug.Assert(jsonConverter.CanHaveMetadata); Debug.Assert(!state.IsContinuation); Debug.Assert(state.CurrentContainsMetadata); MetadataPropertyName writtenMetadata = MetadataPropertyName.None; if (state.NewReferenceId != null) { writer.WriteString(s_metadataId, state.NewReferenceId); writtenMetadata |= MetadataPropertyName.Id; state.NewReferenceId = null; } if (state.PolymorphicTypeDiscriminator is string typeDiscriminatorId) { Debug.Assert(state.Parent.JsonPropertyInfo !.JsonTypeInfo.PolymorphicTypeResolver != null); JsonEncodedText propertyName = state.Parent.JsonPropertyInfo.JsonTypeInfo.PolymorphicTypeResolver.CustomTypeDiscriminatorPropertyNameJsonEncoded is JsonEncodedText customPropertyName ? customPropertyName : s_metadataType; writer.WriteString(propertyName, typeDiscriminatorId); writtenMetadata |= MetadataPropertyName.Type; state.PolymorphicTypeDiscriminator = null; } Debug.Assert(writtenMetadata != MetadataPropertyName.None); return(writtenMetadata); }
internal static MetadataPropertyName WriteReferenceForCollection( JsonConverter jsonConverter, object currentValue, ref WriteStack state, Utf8JsonWriter writer) { MetadataPropertyName metadataToWrite = GetResolvedReferenceHandling(jsonConverter, currentValue, ref state, out string?referenceId); if (metadataToWrite == MetadataPropertyName.NoMetadata) { writer.WriteStartArray(); } else if (metadataToWrite == MetadataPropertyName.Id) { writer.WriteStartObject(); writer.WriteString(s_metadataId, referenceId !); writer.WriteStartArray(s_metadataValues); } else { Debug.Assert(metadataToWrite == MetadataPropertyName.Ref); writer.WriteStartObject(); writer.WriteString(s_metadataRef, referenceId !); writer.WriteEndObject(); } return(metadataToWrite); }
private static void HandleMetadataPropertyValue(ref Utf8JsonReader reader, ref ReadStack state) { Debug.Assert(state.Current.JsonClassInfo !.Options.ReferenceHandling.ShouldReadPreservedReferences()); if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } MetadataPropertyName metadata = state.Current.LastSeenMetadataProperty; string key = reader.GetString() !; Debug.Assert(metadata == MetadataPropertyName.Id || metadata == MetadataPropertyName.Ref); if (metadata == MetadataPropertyName.Id) { // Special case for dictionary properties since those do not push into the ReadStack. // There is no need to check for enumerables since those will always be wrapped into JsonPreservableArrayReference<T> which turns enumerables into objects. object value = state.Current.IsProcessingProperty(ClassType.Dictionary) ? state.Current.JsonPropertyInfo !.GetValueAsObject(state.Current.ReturnValue) ! : state.Current.ReturnValue !; state.ReferenceResolver.AddReferenceOnDeserialize(key, value); } else if (metadata == MetadataPropertyName.Ref) { state.Current.ReferenceId = key; } }
internal sealed override bool OnTryWrite(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state) { bool success; if (value == null) { writer.WriteNullValue(); success = true; } else { bool shouldWritePreservedReferences = options.ReferenceHandling.ShouldWritePreservedReferences(); if (!state.Current.ProcessedStartToken) { state.Current.ProcessedStartToken = true; if (!shouldWritePreservedReferences) { writer.WriteStartArray(); } else { MetadataPropertyName metadata = JsonSerializer.WriteReferenceForCollection(this, value, ref state, writer); if (metadata == MetadataPropertyName.Ref) { return(true); } state.Current.MetadataPropertyName = metadata; } state.Current.DeclaredJsonPropertyInfo = state.Current.JsonClassInfo.ElementClassInfo !.PropertyInfoForClassInfo; } success = OnWriteResume(writer, value, options, ref state); if (success) { if (!state.Current.ProcessedEndToken) { state.Current.ProcessedEndToken = true; writer.WriteEndArray(); if (state.Current.MetadataPropertyName == MetadataPropertyName.Id) { // Write the EndObject for $values. writer.WriteEndObject(); } } } } return(success); }
internal static MetadataPropertyName WriteMetadataForCollection( JsonConverter jsonConverter, ref WriteStack state, Utf8JsonWriter writer) { // For collections with metadata, we nest the array payload within a JSON object. writer.WriteStartObject(); MetadataPropertyName writtenMetadata = WriteMetadataForObject(jsonConverter, ref state, writer); writer.WritePropertyName(s_metadataValues); // property name containing nested array values. return(writtenMetadata); }
private static void ResolveMetadataOnObject(MetadataPropertyName metadata, ref ReadStack state) { if (metadata == MetadataPropertyName.Id) { if (state.Current.PropertyIndex > 0 || state.Current.LastSeenMetadataProperty != MetadataPropertyName.NoMetadata) { ThrowHelper.ThrowJsonException_MetadataIdIsNotFirstProperty(); } state.Current.JsonPropertyName = ReadStack.s_idMetadataPropertyName; } else if (metadata == MetadataPropertyName.Values) { JsonPropertyInfo info = GetValuesPropertyInfoFromJsonPreservableArrayRef(ref state.Current); state.Current.JsonPropertyName = ReadStack.s_valuesMetadataPropertyName; state.Current.JsonPropertyInfo = info; // Throw after setting JsonPropertyName to show the correct JSON Path. if (state.Current.LastSeenMetadataProperty != MetadataPropertyName.Id) { ThrowHelper.ThrowJsonException_MetadataMissingIdBeforeValues(); } } else { Debug.Assert(metadata == MetadataPropertyName.Ref); if (state.Current.JsonClassInfo !.Type.IsValueType) { ThrowHelper.ThrowJsonException_MetadataInvalidReferenceToValueType(state.Current.JsonClassInfo.Type); } if (state.Current.PropertyIndex > 0 || state.Current.LastSeenMetadataProperty != MetadataPropertyName.NoMetadata) { ThrowHelper.ThrowJsonException_MetadataReferenceObjectCannotContainOtherProperties(); } state.Current.JsonPropertyName = ReadStack.s_refMetadataPropertyName; } }
private static void ResolveMetadataOnDictionary(MetadataPropertyName metadata, ref ReadStack state) { if (metadata == MetadataPropertyName.Id) { // Check we are not parsing into an immutable dictionary. if (state.Current.JsonPropertyInfo !.DictionaryConverter != null) { ThrowHelper.ThrowJsonException_MetadataCannotParsePreservedObjectIntoImmutable(state.Current.JsonPropertyInfo.DeclaredPropertyType); } if (state.Current.KeyName != null) { ThrowHelper.ThrowJsonException_MetadataIdIsNotFirstProperty_Dictionary(ref state.Current); } } else if (metadata == MetadataPropertyName.Ref) { if (state.Current.KeyName != null) { ThrowHelper.ThrowJsonException_MetadataReferenceObjectCannotContainOtherProperties_Dictionary(ref state.Current); } } }
/// <summary> /// Returns true if successful, false is the reader ran out of buffer. /// Sets state.Current.ReturnValue to the $ref target for MetadataRefProperty cases. /// </summary> internal static bool ResolveMetadata( JsonConverter converter, ref Utf8JsonReader reader, ref ReadStack state) { if (state.Current.ObjectState < StackFrameObjectState.ReadAheadNameOrEndObject) { // Read the first metadata property name. if (!ReadAheadMetataDataAndSetState(ref reader, ref state, StackFrameObjectState.ReadNameOrEndObject)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadNameOrEndObject) { if (reader.TokenType != JsonTokenType.PropertyName) { // An enumerable needs metadata since it starts with StartObject. if (converter.ClassType == ClassType.Enumerable) { ThrowHelper.ThrowJsonException_MetadataPreservedArrayValuesNotFound(converter.TypeToConvert); } // The reader should have detected other invalid cases. Debug.Assert(reader.TokenType == JsonTokenType.EndObject); // Skip the read of the first property name, since we already read it above. state.Current.PropertyState = StackFramePropertyState.ReadName; return(true); } ReadOnlySpan <byte> propertyName = reader.GetSpan(); MetadataPropertyName metadata = GetMetadataPropertyName(propertyName); if (metadata == MetadataPropertyName.Id) { state.Current.JsonPropertyName = propertyName.ToArray(); if (!converter.CanHaveIdMetadata) { ThrowHelper.ThrowJsonException_MetadataCannotParsePreservedObjectIntoImmutable(converter.TypeToConvert); } state.Current.ObjectState = StackFrameObjectState.ReadAheadIdValue; } else if (metadata == MetadataPropertyName.Ref) { state.Current.JsonPropertyName = propertyName.ToArray(); if (converter.IsValueType) { ThrowHelper.ThrowJsonException_MetadataInvalidReferenceToValueType(converter.TypeToConvert); } state.Current.ObjectState = StackFrameObjectState.ReadAheadRefValue; } else if (metadata == MetadataPropertyName.Values) { state.Current.JsonPropertyName = propertyName.ToArray(); if (converter.ClassType == ClassType.Enumerable) { ThrowHelper.ThrowJsonException_MetadataMissingIdBeforeValues(); } else { ThrowHelper.ThrowJsonException_MetadataInvalidPropertyWithLeadingDollarSign(propertyName, ref state, reader); } } else { Debug.Assert(metadata == MetadataPropertyName.NoMetadata); // Having a StartObject without metadata properties is not allowed. if (converter.ClassType == ClassType.Enumerable) { state.Current.JsonPropertyName = propertyName.ToArray(); ThrowHelper.ThrowJsonException_MetadataPreservedArrayInvalidProperty(converter.TypeToConvert, reader); } // Skip the read of the first property name, since we already read it above. state.Current.PropertyState = StackFramePropertyState.ReadName; return(true); } } if (state.Current.ObjectState == StackFrameObjectState.ReadAheadRefValue) { if (!ReadAheadMetataDataAndSetState(ref reader, ref state, StackFrameObjectState.ReadRefValue)) { return(false); } } else if (state.Current.ObjectState == StackFrameObjectState.ReadAheadIdValue) { if (!ReadAheadMetataDataAndSetState(ref reader, ref state, StackFrameObjectState.ReadIdValue)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadRefValue) { if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } string key = reader.GetString() !; // todo: https://github.com/dotnet/runtime/issues/32354 state.Current.ReturnValue = state.ReferenceResolver.ResolveReferenceOnDeserialize(key); state.Current.ObjectState = StackFrameObjectState.ReadAheadRefEndObject; } else if (state.Current.ObjectState == StackFrameObjectState.ReadIdValue) { if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } state.Current.MetadataId = reader.GetString(); // Clear the MetadataPropertyName since we are done processing Id. state.Current.JsonPropertyName = default; if (converter.ClassType == ClassType.Enumerable) { // Need to Read $values property name. state.Current.ObjectState = StackFrameObjectState.ReadAheadValuesName; } else { // We are done reading metadata. state.Current.ObjectState = StackFrameObjectState.PropertyValue; return(true); } } if (state.Current.ObjectState == StackFrameObjectState.ReadAheadRefEndObject) { if (!ReadAheadMetataDataAndSetState(ref reader, ref state, StackFrameObjectState.ReadRefEndObject)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadRefEndObject) { if (reader.TokenType != JsonTokenType.EndObject) { // We just read a property. The only valid next tokens are EndObject and PropertyName. Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); ThrowHelper.ThrowJsonException_MetadataReferenceObjectCannotContainOtherProperties(reader.GetSpan(), ref state); } return(true); } if (state.Current.ObjectState == StackFrameObjectState.ReadAheadValuesName) { if (!ReadAheadMetataDataAndSetState(ref reader, ref state, StackFrameObjectState.ReadValuesName)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadValuesName) { if (reader.TokenType != JsonTokenType.PropertyName) { ThrowHelper.ThrowJsonException_MetadataPreservedArrayValuesNotFound(converter.TypeToConvert); } ReadOnlySpan <byte> propertyName = reader.GetSpan(); // Remember the property in case we get an exception. state.Current.JsonPropertyName = propertyName.ToArray(); if (GetMetadataPropertyName(propertyName) != MetadataPropertyName.Values) { ThrowHelper.ThrowJsonException_MetadataPreservedArrayInvalidProperty(converter.TypeToConvert, reader); } state.Current.ObjectState = StackFrameObjectState.ReadAheadValuesStartArray; } if (state.Current.ObjectState == StackFrameObjectState.ReadAheadValuesStartArray) { if (!ReadAheadMetataDataAndSetState(ref reader, ref state, StackFrameObjectState.ReadValuesStartArray)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadValuesStartArray) { if (reader.TokenType != JsonTokenType.StartArray) { ThrowHelper.ThrowJsonException_MetadataValuesInvalidToken(reader.TokenType); } state.Current.ObjectState = StackFrameObjectState.PropertyValue; } return(true); }
private static void HandlePropertyName( JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { if (state.Current.Drain) { return; } Debug.Assert(state.Current.ReturnValue != null || state.Current.TempDictionaryValues != null); Debug.Assert(state.Current.JsonClassInfo != null); bool isProcessingDictObject = state.Current.IsProcessingObject(ClassType.Dictionary); if ((isProcessingDictObject || state.Current.IsProcessingProperty(ClassType.Dictionary)) && state.Current.JsonClassInfo.DataExtensionProperty != state.Current.JsonPropertyInfo) { if (isProcessingDictObject) { state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.PolicyProperty; } if (options.ReferenceHandling.ShouldReadPreservedReferences()) { ReadOnlySpan <byte> propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; MetadataPropertyName metadata = GetMetadataPropertyName(propertyName, ref state, ref reader); ResolveMetadataOnDictionary(metadata, ref state); state.Current.LastSeenMetadataProperty = metadata; } state.Current.KeyName = reader.GetString(); } else { Debug.Assert(state.Current.JsonClassInfo.ClassType == ClassType.Object); state.Current.EndProperty(); ReadOnlySpan <byte> propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; if (options.ReferenceHandling.ShouldReadPreservedReferences()) { MetadataPropertyName metadata = GetMetadataPropertyName(propertyName, ref state, ref reader); if (metadata == MetadataPropertyName.NoMetadata) { if (state.Current.IsPreservedArray) { ThrowHelper.ThrowJsonException_MetadataPreservedArrayInvalidProperty(in reader, ref state); } HandlePropertyNameDefault(propertyName, ref state, ref reader, options); } else { ResolveMetadataOnObject(metadata, ref state); } state.Current.LastSeenMetadataProperty = metadata; } else { HandlePropertyNameDefault(propertyName, ref state, ref reader, options); } } }
/// <summary> /// Returns true if successful, false is the reader ran out of buffer. /// Sets state.Current.ReturnValue to the reference target for $ref cases; /// Sets state.Current.ReturnValue to a new instance for $id cases. /// </summary> internal static bool ResolveMetadataForJsonObject <T>( ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { JsonConverter converter = state.Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase; if (state.Current.ObjectState < StackFrameObjectState.ReadAheadNameOrEndObject) { // Read the first metadata property name. if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadNameOrEndObject)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadNameOrEndObject) { if (reader.TokenType != JsonTokenType.PropertyName) { // Since this was an empty object, we are done reading metadata. state.Current.ObjectState = StackFrameObjectState.PropertyValue; // Skip the read of the first property name, since we already read it above. state.Current.PropertyState = StackFramePropertyState.ReadName; return(true); } ReadOnlySpan <byte> propertyName = reader.GetSpan(); MetadataPropertyName metadata = GetMetadataPropertyName(propertyName); if (metadata == MetadataPropertyName.Id) { state.Current.JsonPropertyName = s_idPropertyName; if (!converter.CanHaveIdMetadata) { ThrowHelper.ThrowJsonException_MetadataCannotParsePreservedObjectIntoImmutable(converter.TypeToConvert); } state.Current.ObjectState = StackFrameObjectState.ReadAheadIdValue; } else if (metadata == MetadataPropertyName.Ref) { state.Current.JsonPropertyName = s_refPropertyName; if (converter.IsValueType) { ThrowHelper.ThrowJsonException_MetadataInvalidReferenceToValueType(converter.TypeToConvert); } state.Current.ObjectState = StackFrameObjectState.ReadAheadRefValue; } else if (metadata == MetadataPropertyName.Values) { ThrowHelper.ThrowJsonException_MetadataInvalidPropertyWithLeadingDollarSign(propertyName, ref state, reader); } else { Debug.Assert(metadata == MetadataPropertyName.NoMetadata); // We are done reading metadata, the object didn't contain any. state.Current.ObjectState = StackFrameObjectState.PropertyValue; // Skip the read of the first property name, since we already read it above. state.Current.PropertyState = StackFramePropertyState.ReadName; return(true); } } if (state.Current.ObjectState == StackFrameObjectState.ReadAheadRefValue) { if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadRefValue)) { return(false); } } else if (state.Current.ObjectState == StackFrameObjectState.ReadAheadIdValue) { if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadIdValue)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadRefValue) { if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } string referenceId = reader.GetString() !; object value = state.ReferenceResolver.ResolveReference(referenceId); ValidateValueIsCorrectType <T>(value, referenceId); state.Current.ReturnValue = value; state.Current.ObjectState = StackFrameObjectState.ReadAheadRefEndObject; } else if (state.Current.ObjectState == StackFrameObjectState.ReadIdValue) { if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } converter.CreateInstanceForReferenceResolver(ref reader, ref state, options); string referenceId = reader.GetString() !; state.ReferenceResolver.AddReference(referenceId, state.Current.ReturnValue !); // We are done reading metadata plus we instantiated the object. state.Current.ObjectState = StackFrameObjectState.CreatedObject; } // Clear the metadata property name that was set in case of failure on ResolveReference/AddReference. state.Current.JsonPropertyName = null; if (state.Current.ObjectState == StackFrameObjectState.ReadAheadRefEndObject) { if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadRefEndObject)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadRefEndObject) { if (reader.TokenType != JsonTokenType.EndObject) { // We just read a property. The only valid next tokens are EndObject and PropertyName. Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); ThrowHelper.ThrowJsonException_MetadataReferenceObjectCannotContainOtherProperties(reader.GetSpan(), ref state); } } return(true); }
/// <summary> /// Returns true if successful, false is the reader ran out of buffer. /// Sets state.Current.ReturnValue to the reference target for $ref cases; /// Sets state.Current.ReturnValue to a new instance for $id cases. /// </summary> internal static bool ResolveMetadataForJsonArray <T>( ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { JsonConverter converter = state.Current.JsonTypeInfo.PropertyInfoForTypeInfo.ConverterBase; if (state.Current.ObjectState < StackFrameObjectState.ReadAheadNameOrEndObject) { // Read the first metadata property name. if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadNameOrEndObject)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadNameOrEndObject) { if (reader.TokenType != JsonTokenType.PropertyName) { // The reader should have detected other invalid cases. Debug.Assert(reader.TokenType == JsonTokenType.EndObject); // An enumerable needs metadata since it starts with StartObject. ThrowHelper.ThrowJsonException_MetadataPreservedArrayValuesNotFound(ref state, converter.TypeToConvert); } ReadOnlySpan <byte> propertyName = reader.GetSpan(); MetadataPropertyName metadata = GetMetadataPropertyName(propertyName); if (metadata == MetadataPropertyName.Id) { state.Current.JsonPropertyName = s_idPropertyName; if (!converter.CanHaveIdMetadata) { ThrowHelper.ThrowJsonException_MetadataCannotParsePreservedObjectIntoImmutable(converter.TypeToConvert); } state.Current.ObjectState = StackFrameObjectState.ReadAheadIdValue; } else if (metadata == MetadataPropertyName.Ref) { state.Current.JsonPropertyName = s_refPropertyName; if (converter.IsValueType) { ThrowHelper.ThrowJsonException_MetadataInvalidReferenceToValueType(converter.TypeToConvert); } state.Current.ObjectState = StackFrameObjectState.ReadAheadRefValue; } else if (metadata == MetadataPropertyName.Values) { ThrowHelper.ThrowJsonException_MetadataMissingIdBeforeValues(ref state, propertyName); } else { Debug.Assert(metadata == MetadataPropertyName.NoMetadata); // Having a StartObject without metadata properties is not allowed. ThrowHelper.ThrowJsonException_MetadataPreservedArrayInvalidProperty(ref state, converter.TypeToConvert, reader); } } if (state.Current.ObjectState == StackFrameObjectState.ReadAheadRefValue) { if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadRefValue)) { return(false); } } else if (state.Current.ObjectState == StackFrameObjectState.ReadAheadIdValue) { if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadIdValue)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadRefValue) { if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } string referenceId = reader.GetString() !; object value = state.ReferenceResolver.ResolveReference(referenceId); ValidateValueIsCorrectType <T>(value, referenceId); state.Current.ReturnValue = value; state.Current.ObjectState = StackFrameObjectState.ReadAheadRefEndObject; } else if (state.Current.ObjectState == StackFrameObjectState.ReadIdValue) { if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } converter.CreateInstanceForReferenceResolver(ref reader, ref state, options); string referenceId = reader.GetString() !; state.ReferenceResolver.AddReference(referenceId, state.Current.ReturnValue !); // Need to Read $values property name. state.Current.ObjectState = StackFrameObjectState.ReadAheadValuesName; } // Clear the metadata property name that was set in case of failure on ResolverReference/AddReference. state.Current.JsonPropertyName = null; if (state.Current.ObjectState == StackFrameObjectState.ReadAheadRefEndObject) { if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadRefEndObject)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadRefEndObject) { if (reader.TokenType != JsonTokenType.EndObject) { // We just read a property. The only valid next tokens are EndObject and PropertyName. Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); ThrowHelper.ThrowJsonException_MetadataReferenceObjectCannotContainOtherProperties(reader.GetSpan(), ref state); } return(true); } if (state.Current.ObjectState == StackFrameObjectState.ReadAheadValuesName) { if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadValuesName)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadValuesName) { if (reader.TokenType != JsonTokenType.PropertyName) { ThrowHelper.ThrowJsonException_MetadataPreservedArrayValuesNotFound(ref state, converter.TypeToConvert); } ReadOnlySpan <byte> propertyName = reader.GetSpan(); if (GetMetadataPropertyName(propertyName) != MetadataPropertyName.Values) { ThrowHelper.ThrowJsonException_MetadataPreservedArrayInvalidProperty(ref state, converter.TypeToConvert, reader); } // Remember the property in case we get an exception in one of the array elements. state.Current.JsonPropertyName = s_valuesPropertyName; state.Current.ObjectState = StackFrameObjectState.ReadAheadValuesStartArray; } if (state.Current.ObjectState == StackFrameObjectState.ReadAheadValuesStartArray) { if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadValuesStartArray)) { return(false); } } if (state.Current.ObjectState == StackFrameObjectState.ReadValuesStartArray) { if (reader.TokenType != JsonTokenType.StartArray) { ThrowHelper.ThrowJsonException_MetadataValuesInvalidToken(reader.TokenType); } state.Current.ValidateEndTokenOnArray = true; state.Current.ObjectState = StackFrameObjectState.CreatedObject; } return(true); }
internal sealed override bool OnTryWrite( Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) { JsonTypeInfo jsonTypeInfo = state.Current.JsonTypeInfo; object obj = value; // box once if (!state.SupportContinuation) { writer.WriteStartObject(); if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve) { MetadataPropertyName propertyName = JsonSerializer.WriteReferenceForObject(this, ref state, writer); Debug.Assert(propertyName != MetadataPropertyName.Ref); } if (obj is IJsonOnSerializing onSerializing) { onSerializing.OnSerializing(); } List <KeyValuePair <string, JsonPropertyInfo?> > properties = jsonTypeInfo.PropertyCache !.List; for (int i = 0; i < properties.Count; i++) { JsonPropertyInfo jsonPropertyInfo = properties[i].Value !; if (jsonPropertyInfo.ShouldSerialize) { // Remember the current property for JsonPath support if an exception is thrown. state.Current.JsonPropertyInfo = jsonPropertyInfo; state.Current.NumberHandling = jsonPropertyInfo.NumberHandling; bool success = jsonPropertyInfo.GetMemberAndWriteJson(obj, ref state, writer); // Converters only return 'false' when out of data which is not possible in fast path. Debug.Assert(success); state.Current.EndProperty(); } } // Write extension data after the normal properties. JsonPropertyInfo?dataExtensionProperty = jsonTypeInfo.DataExtensionProperty; if (dataExtensionProperty?.ShouldSerialize == true) { // Remember the current property for JsonPath support if an exception is thrown. state.Current.JsonPropertyInfo = dataExtensionProperty; state.Current.NumberHandling = dataExtensionProperty.NumberHandling; bool success = dataExtensionProperty.GetMemberAndWriteJsonExtensionData(obj, ref state, writer); Debug.Assert(success); state.Current.EndProperty(); } writer.WriteEndObject(); } else { if (!state.Current.ProcessedStartToken) { writer.WriteStartObject(); if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve) { MetadataPropertyName propertyName = JsonSerializer.WriteReferenceForObject(this, ref state, writer); Debug.Assert(propertyName != MetadataPropertyName.Ref); } if (obj is IJsonOnSerializing onSerializing) { onSerializing.OnSerializing(); } state.Current.ProcessedStartToken = true; } List <KeyValuePair <string, JsonPropertyInfo?> >?propertyList = jsonTypeInfo.PropertyCache !.List !; while (state.Current.EnumeratorIndex < propertyList.Count) { JsonPropertyInfo?jsonPropertyInfo = propertyList ![state.Current.EnumeratorIndex].Value;