Beispiel #1
0
 internal abstract void SetValueAsObject(object obj, object value, JsonSerializerOptions options);
Beispiel #2
0
 internal abstract void WriteEnumerable(JsonSerializerOptions options, ref WriteStackFrame current, Utf8JsonWriter writer);
Beispiel #3
0
 internal abstract void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state);
Beispiel #4
0
 internal abstract void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
Beispiel #5
0
        private void DetermineSerializationCapabilities(JsonSerializerOptions options)
        {
            bool hasIgnoreAttribute = (GetAttribute <JsonIgnoreAttribute>() != null);

            if (hasIgnoreAttribute)
            {
                // We don't serialize or deserialize.
                return;
            }

            if (ClassType != ClassType.Enumerable)
            {
                // We serialize if there is a getter + no [Ignore] attribute + not ignoring readonly properties.
                ShouldSerialize = HasGetter && (HasSetter || !options.IgnoreReadOnlyProperties);

                // We deserialize if there is a setter + no [Ignore] attribute.
                ShouldDeserialize = HasSetter;
            }
            else
            {
                if (HasGetter)
                {
                    if (HasSetter)
                    {
                        ShouldDeserialize = true;
                    }
                    else if (RuntimePropertyType.IsAssignableFrom(typeof(IList)))
                    {
                        ShouldDeserialize = true;
                    }
                    //else
                    //{
                    //    // todo: future feature that allows non-List types (e.g. from System.Collections.Immutable) to have converters.
                    //}
                }
                //else if (HasSetter)
                //{
                //    // todo: Special case where there is no getter but a setter (and an EnumerableConverter)
                //}

                if (ShouldDeserialize)
                {
                    ShouldSerialize = HasGetter;

                    if (RuntimePropertyType.IsArray)
                    {
                        EnumerableConverter = s_jsonArrayConverter;
                    }
                    else if (typeof(IEnumerable).IsAssignableFrom(RuntimePropertyType))
                    {
                        Type elementType = JsonClassInfo.GetElementType(RuntimePropertyType);

                        // If the property type only has interface(s) exposed by JsonEnumerableT<T> then use JsonEnumerableT as the converter.
                        if (RuntimePropertyType.IsAssignableFrom(typeof(JsonEnumerableT <>).MakeGenericType(elementType)))
                        {
                            EnumerableConverter = s_jsonEnumerableConverter;
                        }
                    }
                }
                else
                {
                    ShouldSerialize = HasGetter && !options.IgnoreReadOnlyProperties;
                }
            }
        }
Beispiel #6
0
 internal abstract object GetValueAsObject(object obj, JsonSerializerOptions options);
Beispiel #7
0
 internal virtual void GetPolicies(JsonSerializerOptions options)
 {
     DetermineSerializationCapabilities(options);
     DeterminePropertyName(options);
     IgnoreNullValues = options.IgnoreNullValues;
 }
Beispiel #8
0
        private void DeterminePropertyName(JsonSerializerOptions options)
        {
            if (PropertyInfo != null)
            {
                JsonPropertyNameAttribute nameAttribute = GetAttribute <JsonPropertyNameAttribute>();
                if (nameAttribute != null)
                {
                    NameAsString = nameAttribute.Name;

                    // This is detected and thrown by caller.
                    if (NameAsString == null)
                    {
                        return;
                    }
                }
                else if (options.PropertyNamingPolicy != null)
                {
                    NameAsString = options.PropertyNamingPolicy.ConvertName(PropertyInfo.Name);

                    // This is detected and thrown by caller.
                    if (NameAsString == null)
                    {
                        return;
                    }
                }
                else
                {
                    NameAsString = PropertyInfo.Name;
                }

                // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder.
                _name = Encoding.UTF8.GetBytes(NameAsString);

                // Set the compare name.
                if (options.PropertyNameCaseInsensitive)
                {
                    CompareNameAsString = NameAsString.ToUpperInvariant();
                    _compareName        = Encoding.UTF8.GetBytes(CompareNameAsString);
                }
                else
                {
                    CompareNameAsString = NameAsString;
                    _compareName        = _name;
                }

                // Cache the escaped name.
                int valueIdx = JsonWriterHelper.NeedsEscaping(_name);
                if (valueIdx == -1)
                {
                    _escapedName = _name;
                }
                else
                {
                    int length = JsonWriterHelper.GetMaxEscapedLength(_name.Length, valueIdx);

                    byte[] tempArray = ArrayPool <byte> .Shared.Rent(length);

                    JsonWriterHelper.EscapeString(_name, tempArray, valueIdx, out int written);
                    _escapedName = new byte[written];
                    tempArray.CopyTo(_escapedName, 0);

                    // We clear the array because it is "user data" (although a property name).
                    new Span <byte>(tempArray, 0, written).Clear();
                    ArrayPool <byte> .Shared.Return(tempArray);
                }
            }
        }
Beispiel #9
0
            /// <inheritdoc/>
            public override TimeSpan?Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            {
                if (reader.TokenType != JsonTokenType.String)
                {
                    throw ThrowHelper.GenerateJsonException_DeserializeUnableToConvertValue(typeof(TimeSpan?));
                }

                string value = reader.GetString() !;

                try
                {
                    return(TimeSpan.ParseExact(value, "c", CultureInfo.InvariantCulture));
                }
                catch (Exception parseException)
                {
                    throw ThrowHelper.GenerateJsonException_DeserializeUnableToConvertValue(typeof(TimeSpan?), value, parseException);
                }
            }
Beispiel #10
0
 /// <inheritdoc/>
 public override void Write(Utf8JsonWriter writer, TimeSpan?value, JsonSerializerOptions options)
 => writer.WriteStringValue(value !.Value.ToString("c", CultureInfo.InvariantCulture));
Beispiel #11
0
        internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, out T?value)
        {
            if (ConverterStrategy == ConverterStrategy.Value)
            {
                // A value converter should never be within a continuation.
                Debug.Assert(!state.IsContinuation);

                // For perf and converter simplicity, handle null here instead of forwarding to the converter.
                if (reader.TokenType == JsonTokenType.Null && !HandleNullOnRead)
                {
                    if (!CanBeNull)
                    {
                        ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
                    }

                    value = default;
                    return(true);
                }

#if !DEBUG
                // For performance, only perform validation on internal converters on debug builds.
                if (IsInternalConverter)
                {
                    if (state.Current.NumberHandling != null)
                    {
                        value = ReadNumberWithCustomHandling(ref reader, state.Current.NumberHandling.Value, options);
                    }
                    else
                    {
                        value = Read(ref reader, typeToConvert, options);
                    }
                }
                else
#endif
                {
                    JsonTokenType originalPropertyTokenType     = reader.TokenType;
                    int           originalPropertyDepth         = reader.CurrentDepth;
                    long          originalPropertyBytesConsumed = reader.BytesConsumed;

                    if (state.Current.NumberHandling != null)
                    {
                        value = ReadNumberWithCustomHandling(ref reader, state.Current.NumberHandling.Value, options);
                    }
                    else
                    {
                        value = Read(ref reader, typeToConvert, options);
                    }

                    VerifyRead(
                        originalPropertyTokenType,
                        originalPropertyDepth,
                        originalPropertyBytesConsumed,
                        isValueConverter: true,
                        ref reader);
                }

                if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve &&
                    CanBePolymorphic && value is JsonElement element)
                {
                    // Edge case where we want to lookup for a reference when parsing into typeof(object)
                    // instead of return `value` as a JsonElement.
                    Debug.Assert(TypeToConvert == typeof(object));

                    if (JsonSerializer.TryGetReferenceFromJsonElement(ref state, element, out object?referenceValue))
                    {
                        value = (T?)referenceValue;
                    }
                }

                return(true);
            }

            bool success;

            // Remember if we were a continuation here since Push() may affect IsContinuation.
            bool wasContinuation = state.IsContinuation;

            state.Push();

#if !DEBUG
            // For performance, only perform validation on internal converters on debug builds.
            if (IsInternalConverter)
            {
                if (reader.TokenType == JsonTokenType.Null && !HandleNullOnRead && !wasContinuation)
                {
                    if (!CanBeNull)
                    {
                        ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
                    }

                    // For perf and converter simplicity, handle null here instead of forwarding to the converter.
                    value   = default;
                    success = true;
                }
                else
                {
                    success = OnTryRead(ref reader, typeToConvert, options, ref state, out value);
                }
            }
            else
#endif
            {
                if (!wasContinuation)
                {
                    // For perf and converter simplicity, handle null here instead of forwarding to the converter.
                    if (reader.TokenType == JsonTokenType.Null && !HandleNullOnRead)
                    {
                        if (!CanBeNull)
                        {
                            ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert);
                        }

                        value = default;
                        state.Pop(true);
                        return(true);
                    }

                    Debug.Assert(state.Current.OriginalTokenType == JsonTokenType.None);
                    state.Current.OriginalTokenType = reader.TokenType;

                    Debug.Assert(state.Current.OriginalDepth == 0);
                    state.Current.OriginalDepth = reader.CurrentDepth;
                }

                success = OnTryRead(ref reader, typeToConvert, options, ref state, out value);
                if (success)
                {
                    if (state.IsContinuation)
                    {
                        // The resumable converter did not forward to the next converter that previously returned false.
                        ThrowHelper.ThrowJsonException_SerializationConverterRead(this);
                    }

                    VerifyRead(
                        state.Current.OriginalTokenType,
                        state.Current.OriginalDepth,
                        bytesConsumed: 0,
                        isValueConverter: false,
                        ref reader);

                    // No need to clear state.Current.* since a stack pop will occur.
                }
            }

            state.Pop(success);
            return(success);
        }
Beispiel #12
0
 /// <summary>
 /// Read and convert the JSON to T.
 /// </summary>
 /// <remarks>
 /// A converter may throw any Exception, but should throw <cref>JsonException</cref> when the JSON is invalid.
 /// </remarks>
 /// <param name="reader">The <see cref="Utf8JsonReader"/> to read from.</param>
 /// <param name="typeToConvert">The <see cref="Type"/> being converted.</param>
 /// <param name="options">The <see cref="JsonSerializerOptions"/> being used.</param>
 /// <returns>The value that was converted.</returns>
 public abstract T?Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options);
Beispiel #13
0
 // Provide a default implementation for value converters.
 internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, out T?value)
 {
     value = Read(ref reader, typeToConvert, options);
     return(true);
 }
Beispiel #14
0
 // Provide a default implementation for value converters.
 internal virtual bool OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state)
 {
     Write(writer, value, options);
     return(true);
 }
Beispiel #15
0
        // This non-generic API is sealed as it just forwards to the generic version.
        internal sealed override bool TryWriteAsObject(Utf8JsonWriter writer, object?value, JsonSerializerOptions options, ref WriteStack state)
        {
            T valueOfT = (T)value !;

            return(TryWrite(writer, valueOfT, options, ref state));
        }