public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { if (!int.TryParse(reader.GetString(), out var res)) { throw new JsonException("Failed to parse json number"); } return(res); } return(reader.GetInt32()); }
public override int Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { ReadOnlySpan <byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; if (Utf8Parser.TryParse(span, out int number, out int bytesConsumed) && span.Length == bytesConsumed) { return(number); } if (int.TryParse(reader.GetString(), out number)) { return(number); } } return(reader.GetInt32()); }
internal static bool TryReadMetadata(JsonConverter converter, JsonTypeInfo jsonTypeInfo, ref Utf8JsonReader reader, ref ReadStack state) { Debug.Assert(state.Current.ObjectState == StackFrameObjectState.StartToken); Debug.Assert(state.Current.CanContainMetadata); while (true) { if (state.Current.PropertyState == StackFramePropertyState.None) { state.Current.PropertyState = StackFramePropertyState.ReadName; // Read the property name. if (!reader.Read()) { return(false); } } if (state.Current.PropertyState < StackFramePropertyState.Name) { if (reader.TokenType == JsonTokenType.EndObject) { // Read the entire object while parsing for metadata. return(true); } // We just read a property. The only valid next tokens are EndObject and PropertyName. Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Ref)) { // No properties whatsoever should follow a $ref property. ThrowHelper.ThrowJsonException_MetadataReferenceObjectCannotContainOtherProperties(reader.GetSpan(), ref state); } ReadOnlySpan <byte> propertyName = reader.GetSpan(); switch (state.Current.LatestMetadataPropertyName = GetMetadataPropertyName(propertyName, jsonTypeInfo.PolymorphicTypeResolver)) { case MetadataPropertyName.Id: state.Current.JsonPropertyName = s_idPropertyName; if (state.ReferenceResolver is null) { // Found an $id property in a type that doesn't support reference preservation ThrowHelper.ThrowJsonException_MetadataUnexpectedProperty(propertyName, ref state); } if ((state.Current.MetadataPropertyNames & (MetadataPropertyName.Id | MetadataPropertyName.Ref)) != 0) { // No $id or $ref properties should precede $id properties. ThrowHelper.ThrowJsonException_MetadataIdIsNotFirstProperty(propertyName, ref state); } if (!converter.CanHaveMetadata) { // Should not be permitted unless the converter is capable of handling metadata. ThrowHelper.ThrowJsonException_MetadataCannotParsePreservedObjectIntoImmutable(converter.TypeToConvert); } break; case MetadataPropertyName.Ref: state.Current.JsonPropertyName = s_refPropertyName; if (state.ReferenceResolver is null) { // Found a $ref property in a type that doesn't support reference preservation ThrowHelper.ThrowJsonException_MetadataUnexpectedProperty(propertyName, ref state); } if (converter.IsValueType) { // Should not be permitted if the converter is a struct. ThrowHelper.ThrowJsonException_MetadataInvalidReferenceToValueType(converter.TypeToConvert); } if (state.Current.MetadataPropertyNames != 0) { // No metadata properties should precede a $ref property. ThrowHelper.ThrowJsonException_MetadataReferenceObjectCannotContainOtherProperties(reader.GetSpan(), ref state); } break; case MetadataPropertyName.Type: state.Current.JsonPropertyName = jsonTypeInfo.PolymorphicTypeResolver?.TypeDiscriminatorPropertyNameUtf8 ?? s_typePropertyName; if (jsonTypeInfo.PolymorphicTypeResolver is null) { // Found a $type property in a type that doesn't support polymorphism ThrowHelper.ThrowJsonException_MetadataUnexpectedProperty(propertyName, ref state); } if (state.PolymorphicTypeDiscriminator != null) { ThrowHelper.ThrowJsonException_MetadataDuplicateTypeProperty(); } break; case MetadataPropertyName.Values: state.Current.JsonPropertyName = s_valuesPropertyName; if (state.Current.MetadataPropertyNames == MetadataPropertyName.None) { // Cannot have a $values property unless there are preceding metadata properties. ThrowHelper.ThrowJsonException_MetadataStandaloneValuesProperty(ref state, propertyName); } break; default: Debug.Assert(state.Current.LatestMetadataPropertyName == MetadataPropertyName.None); // Encountered a non-metadata property, exit the reader. return(true); } state.Current.PropertyState = StackFramePropertyState.Name; } if (state.Current.PropertyState < StackFramePropertyState.ReadValue) { state.Current.PropertyState = StackFramePropertyState.ReadValue; // Read the property value. if (!reader.Read()) { return(false); } } Debug.Assert(state.Current.PropertyState == StackFramePropertyState.ReadValue); switch (state.Current.LatestMetadataPropertyName) { case MetadataPropertyName.Id: if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } if (state.ReferenceId != null) { ThrowHelper.ThrowNotSupportedException_ObjectWithParameterizedCtorRefMetadataNotSupported(s_refPropertyName, ref reader, ref state); } state.ReferenceId = reader.GetString(); break; case MetadataPropertyName.Ref: if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); } if (state.ReferenceId != null) { ThrowHelper.ThrowNotSupportedException_ObjectWithParameterizedCtorRefMetadataNotSupported(s_refPropertyName, ref reader, ref state); } state.ReferenceId = reader.GetString(); break; case MetadataPropertyName.Type: Debug.Assert(state.PolymorphicTypeDiscriminator == null); switch (reader.TokenType) { case JsonTokenType.String: state.PolymorphicTypeDiscriminator = reader.GetString(); break; case JsonTokenType.Number: state.PolymorphicTypeDiscriminator = reader.GetInt32(); break; default: ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); break; } break; case MetadataPropertyName.Values: if (reader.TokenType != JsonTokenType.StartArray) { ThrowHelper.ThrowJsonException_MetadataValuesInvalidToken(reader.TokenType); } state.Current.PropertyState = StackFramePropertyState.None; state.Current.MetadataPropertyNames |= state.Current.LatestMetadataPropertyName; return(true); // "$values" property contains the nested payload, exit the metadata reader now. default: Debug.Fail("Non-metadata properties should not reach this stage."); break; } state.Current.MetadataPropertyNames |= state.Current.LatestMetadataPropertyName; state.Current.PropertyState = StackFramePropertyState.None; state.Current.JsonPropertyName = null; } }