Beispiel #1
0
        public void WriteEnumerable(ref WriteStack state, Utf8JsonWriter writer)
        {
            Debug.Assert(ShouldSerialize);

            int originalDepth = writer.CurrentDepth;

            OnWriteEnumerable(ref state.Current, writer);
            VerifyWrite(originalDepth, ref state, ref writer);
        }
        private static bool WriteEndObject(ref WriteStack state)
        {
            if (state.Current.PopStackOnEndObject)
            {
                state.Pop();
            }

            return(true);
        }
        public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
        {
            Debug.Assert(EscapedName.HasValue);

            bool success;
            T    value = Get !(obj);

            if (value == null)
            {
                Debug.Assert(s_defaultValue == null && Converter.CanBeNull);

                success = true;
                if (!IgnoreDefaultValuesOnWrite)
                {
                    if (!Converter.HandleNull)
                    {
                        writer.WriteNull(EscapedName.Value);
                    }
                    else
                    {
                        // No object, collection, or re-entrancy converter handles null.
                        Debug.Assert(Converter.ClassType == ClassType.Value);

                        if (state.Current.PropertyState < StackFramePropertyState.Name)
                        {
                            state.Current.PropertyState = StackFramePropertyState.Name;
                            writer.WritePropertyName(EscapedName.Value);
                        }

                        int originalDepth = writer.CurrentDepth;
                        Converter.Write(writer, value, Options);
                        if (originalDepth != writer.CurrentDepth)
                        {
                            ThrowHelper.ThrowJsonException_SerializationConverterWrite(Converter);
                        }
                    }
                }
            }
            else if (IgnoreDefaultValuesOnWrite && Converter._defaultComparer.Equals(s_defaultValue, value))
            {
                Debug.Assert(s_defaultValue != null && !Converter.CanBeNull);
                success = true;
            }
            else
            {
                if (state.Current.PropertyState < StackFramePropertyState.Name)
                {
                    state.Current.PropertyState = StackFramePropertyState.Name;
                    writer.WritePropertyName(EscapedName.Value);
                }

                success = Converter.TryWrite(writer, value, Options, ref state);
            }

            return(success);
        }
Beispiel #4
0
        public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
        {
            T value = Get !(obj);

            if (Options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.IgnoreCycles &&
                !Converter.IsValueType && value != null &&
                state.ReferenceResolver.ContainsReferenceForCycleDetection(value))
            {
                // If a reference cycle is detected, treat value as null.
                value = default !;
Beispiel #5
0
        // There are three conditions to consider for an object (primitive value, enumerable or object) being processed here:
        // 1) The object type was specified as the root-level return type to a Parse\Read method.
        // 2) The object is property on a parent object.
        // 3) The object is an element in an enumerable.
        private static bool Write(
            Utf8JsonWriter writer,
            int flushThreshold,
            JsonSerializerOptions options,
            ref WriteStack state)
        {
            bool finishedSerializing;

            do
            {
                WriteStackFrame current = state.Current;
                switch (current.JsonClassInfo.ClassType)
                {
                case ClassType.Enumerable:
                    finishedSerializing = HandleEnumerable(current.JsonClassInfo.ElementClassInfo, options, writer, ref state);
                    break;

                case ClassType.Value:
                    Debug.Assert(current.JsonPropertyInfo.ClassType == ClassType.Value);
                    current.JsonPropertyInfo.Write(ref current, writer);
                    finishedSerializing = true;
                    break;

                case ClassType.Object:
                case ClassType.KeyValuePair:
                    finishedSerializing = WriteObject(options, writer, ref state);
                    break;

                case ClassType.Dictionary:
                case ClassType.IDictionaryConstructible:
                    finishedSerializing = HandleDictionary(current.JsonClassInfo.ElementClassInfo, options, writer, ref state);
                    break;

                default:
                    Debug.Assert(state.Current.JsonClassInfo.ClassType == ClassType.Unknown);

                    // Treat typeof(object) as an empty object.
                    finishedSerializing = WriteObject(options, writer, ref state);
                    break;
                }

                if (finishedSerializing && writer.CurrentDepth == 0)
                {
                    break;
                }

                // If serialization is not yet end and we surpass beyond flush threshold return false and flush stream.
                if (flushThreshold >= 0 && writer.BytesPending > flushThreshold)
                {
                    return(false);
                }
            } while (true);

            return(true);
        }
        private static async Task WriteAsyncCore(Stream utf8Json, object?value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                options = JsonSerializerOptions.s_defaultOptions;
            }

            JsonWriterOptions writerOptions = options.GetWriterOptions();

            using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize))
                using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions))
                {
                    if (value == null)
                    {
                        writer.WriteNullValue();
                        writer.Flush();

                        await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false);

                        return;
                    }

                    if (inputType == null)
                    {
                        inputType = value.GetType();
                    }

                    WriteStack state = default;
                    state.InitializeRoot(inputType, options, supportContinuation: true);

                    bool isFinalBlock;

                    do
                    {
                        // todo: determine best value here
                        // https://github.com/dotnet/runtime/issues/32356
                        state.FlushThreshold = (int)(bufferWriter.Capacity * .9);
                        isFinalBlock         = WriteCore(
                            writer,
                            value,
                            options,
                            ref state,
                            state.Current.JsonClassInfo !.PolicyProperty !.ConverterBase);

                        writer.Flush();

                        await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false);

                        bufferWriter.Clear();
                    } while (!isFinalBlock);
                }

            // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best.
        }
Beispiel #7
0
        private static async Task WriteAsyncCore(Stream utf8Json, object?value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                options = JsonSerializerOptions.s_defaultOptions;
            }

            JsonWriterOptions writerOptions = options.GetWriterOptions();

            using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize))
                using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions))
                {
                    if (value == null)
                    {
                        writer.WriteNullValue();
                        writer.Flush();

                        await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false);

                        return;
                    }

                    if (inputType == null)
                    {
                        inputType = value.GetType();
                    }

                    WriteStack state = default;
                    if (options.ReferenceHandling.ShouldWritePreservedReferences())
                    {
                        state.ReferenceResolver = new DefaultReferenceResolver(writing: true);
                    }
                    state.Current.Initialize(inputType, options);
                    state.Current.CurrentValue = value;

                    bool isFinalBlock;
                    int  flushThreshold;

                    do
                    {
                        flushThreshold = (int)(bufferWriter.Capacity * .9); //todo: determine best value here

                        isFinalBlock = Write(writer, originalWriterDepth: 0, flushThreshold, options, ref state);
                        writer.Flush();

                        await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false);

                        bufferWriter.Clear();
                    } while (!isFinalBlock);
                }

            // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best.
        }
Beispiel #8
0
        private static bool WriteObject(
            JsonSerializerOptions options,
            Utf8JsonWriter writer,
            ref WriteStack state)
        {
            // Write the start.
            if (!state.Current.StartObjectWritten)
            {
                state.Current.WriteObjectOrArrayStart(ClassType.Object, writer);
                state.Current.PropertyEnumerator       = state.Current.JsonClassInfo.PropertyCache.GetEnumerator();
                state.Current.PropertyEnumeratorActive = true;
                state.Current.NextProperty();
            }
            else if (state.Current.MoveToNextProperty)
            {
                state.Current.NextProperty();
            }

            // Determine if we are done enumerating properties.
            // If the ClassType is unknown, there will be a policy property applied
            JsonClassInfo classInfo = state.Current.JsonClassInfo;

            if (classInfo.ClassType != ClassType.Unknown && state.Current.PropertyEnumeratorActive)
            {
                var kvp = (KeyValuePair <string, JsonPropertyInfo>)state.Current.PropertyEnumerator.Current;
                JsonPropertyInfo jsonPropertyInfo = kvp.Value;
                HandleObject(jsonPropertyInfo, options, writer, ref state);
                return(false);
            }

            if (state.Current.ExtensionDataStatus == Serialization.ExtensionDataWriteStatus.Writing)
            {
                JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.DataExtensionProperty;
                if (jsonPropertyInfo != null)
                {
                    HandleObject(jsonPropertyInfo, options, writer, ref state);
                    return(false);
                }
            }

            writer.WriteEndObject();

            if (state.Current.PopStackOnEndObject)
            {
                state.Pop();
            }
            else
            {
                state.Current.EndObject();
            }

            return(true);
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        public void WriteEnumerable(ref WriteStack state, Utf8JsonWriter writer)
        {
            Debug.Assert(ShouldSerialize);
            int originalDepth = writer.CurrentDepth;

            OnWriteEnumerable(ref state.Current, writer);

            if (originalDepth != writer.CurrentDepth)
            {
                ThrowHelper.ThrowJsonException_SerializationConverterWrite(state.PropertyPath(), ConverterBase.ToString());
            }
        }
Beispiel #11
0
        private static bool WriteEndDictionary(ref WriteStack state)
        {
            if (state.Current.PopStackOnEndCollection)
            {
                state.Pop();
            }
            else
            {
                state.Current.EndDictionary();
            }

            return(true);
        }
Beispiel #12
0
        public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
        {
            T value = Get !(obj);

            // Since devirtualization only works in non-shared generics,
            // the default comparer is uded only for value types for now.
            // For reference types there is a quick check for null.
            if (default(T) == null && IgnoreDefaultValuesForReferenceTypesOnWrite && value == null)
            {
                return(true);
            }

            if (default(T) != null && IgnoreDefaultValuesForValueTypesOnWrite && EqualityComparer <T> .Default.Equals(default, value))
Beispiel #13
0
        private static async Task WriteAsyncCore <TValue>(
            Stream utf8Json,
            TValue value,
            Type inputType,
            JsonSerializerOptions?options,
            CancellationToken cancellationToken)
        {
            // We flush the Stream when the buffer is >=90% of capacity.
            // This threshold is a compromise between buffer utilization and minimizing cases where the buffer
            // needs to be expanded\doubled because it is not large enough to write the current property or element.
            // We check for flush after each object property and array element is written to the buffer.
            // Once the buffer is expanded to contain the largest single element\property, a 90% thresold
            // means the buffer may be expanded a maximum of 4 times: 1-(1\(2^4))==.9375.
            const float FlushThreshold = .9f;

            if (options == null)
            {
                options = JsonSerializerOptions.s_defaultOptions;
            }

            JsonWriterOptions writerOptions = options.GetWriterOptions();

            using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize))
                using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions))
                {
                    //  We treat typeof(object) special and allow polymorphic behavior.
                    if (inputType == typeof(object) && value != null)
                    {
                        inputType = value !.GetType();
                    }

                    WriteStack state = default;
                    state.Initialize(inputType, options, supportContinuation: true);

                    JsonConverter converterBase = state.Current.JsonClassInfo !.PropertyInfoForClassInfo.ConverterBase;

                    bool isFinalBlock;

                    do
                    {
                        state.FlushThreshold = (int)(bufferWriter.Capacity * FlushThreshold);

                        isFinalBlock = WriteCore(converterBase, writer, value, options, ref state);

                        await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false);

                        bufferWriter.Clear();
                    } while (!isFinalBlock);
                }
        }
        internal static MetadataPropertyName WriteReferenceForCollection(
            JsonConverter jsonConverter,
            object currentValue,
            ref WriteStack state,
            Utf8JsonWriter writer)
        {
            MetadataPropertyName writtenMetadataName;

            if (state.BoxedStructReferenceId != null)
            {
                // We're serializing a struct that has been handled by a polymorphic converter;
                // emit the reference id that was recorded for the boxed instance.

                Debug.Assert(jsonConverter.IsValueType && jsonConverter.CanHaveIdMetadata);

                writer.WriteStartObject();
                writer.WriteString(s_metadataId, state.BoxedStructReferenceId);
                writer.WriteStartArray(s_metadataValues);
                writtenMetadataName          = MetadataPropertyName.Id;
                state.BoxedStructReferenceId = null;
            }
            else if (!jsonConverter.CanHaveIdMetadata || jsonConverter.IsValueType)
            {
                // If the jsonConverter supports immutable enumerables or value type collections, don't write any metadata
                writer.WriteStartArray();
                writtenMetadataName = MetadataPropertyName.NoMetadata;
            }
            else
            {
                string referenceId = state.ReferenceResolver.GetReference(currentValue, out bool alreadyExists);
                Debug.Assert(referenceId != null);

                if (alreadyExists)
                {
                    writer.WriteStartObject();
                    writer.WriteString(s_metadataRef, referenceId);
                    writer.WriteEndObject();
                    writtenMetadataName = MetadataPropertyName.Ref;
                }
                else
                {
                    writer.WriteStartObject();
                    writer.WriteString(s_metadataId, referenceId);
                    writer.WriteStartArray(s_metadataValues);
                    writtenMetadataName = MetadataPropertyName.Id;
                }
            }

            return(writtenMetadataName);
        }
        private static bool WriteObject(
            JsonSerializerOptions options,
            Utf8JsonWriter writer,
            ref WriteStack state)
        {
            // Write the start.
            if (!state.Current.StartObjectWritten)
            {
                // If true, we are writing a root object or a value that doesn't belong
                // to an object e.g. a dictionary value.
                if (state.Current.CurrentValue == null)
                {
                    state.Current.WriteObjectOrArrayStart(ClassType.Object, writer, options, writeNull: true);
                    return(WriteEndObject(ref state));
                }

                state.Current.WriteObjectOrArrayStart(ClassType.Object, writer, options);
                state.Current.PropertyEnumerator       = state.Current.JsonClassInfo.PropertyCache.GetEnumerator();
                state.Current.PropertyEnumeratorActive = true;
                state.Current.NextProperty();
            }
            else if (state.Current.MoveToNextProperty)
            {
                state.Current.NextProperty();
            }

            // Determine if we are done enumerating properties.
            // If the ClassType is unknown, there will be a policy property applied
            JsonClassInfo classInfo = state.Current.JsonClassInfo;

            if (classInfo.ClassType != ClassType.Unknown && state.Current.PropertyEnumeratorActive)
            {
                HandleObject(state.Current.PropertyEnumerator.Current.Value, options, writer, ref state);
                return(false);
            }

            if (state.Current.ExtensionDataStatus == Serialization.ExtensionDataWriteStatus.Writing)
            {
                JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.DataExtensionProperty;
                if (jsonPropertyInfo != null)
                {
                    HandleObject(jsonPropertyInfo, options, writer, ref state);
                    return(false);
                }
            }

            writer.WriteEndObject();
            return(WriteEndObject(ref state));
        }
        internal static MetadataPropertyName WriteReferenceForObject(
            JsonConverter jsonConverter,
            ref WriteStack state,
            Utf8JsonWriter writer)
        {
            if (state.NewReferenceId != null)
            {
                Debug.Assert(jsonConverter.CanHaveMetadata);
                writer.WriteString(s_metadataId, state.NewReferenceId);
                state.NewReferenceId = null;
                return(MetadataPropertyName.Id);
            }

            return(MetadataPropertyName.None);
        }
        public override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer)
        {
            bool success;
            T    value = Get !(obj);

            if (value == null)
            {
                success = true;
            }
            else
            {
                success = Converter.TryWriteDataExtensionProperty(writer, value, Options, ref state);
            }

            return(success);
        }
Beispiel #18
0
        public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
        {
            Debug.Assert(EscapedName.HasValue);

            bool success;
            T    value = Get !(obj);

            if (value == null)
            {
                if (!IgnoreNullValues)
                {
                    if (!Converter.HandleNull)
                    {
                        writer.WriteNull(EscapedName.Value);
                    }
                    else
                    {
                        if (state.Current.PropertyState < StackFramePropertyState.Name)
                        {
                            state.Current.PropertyState = StackFramePropertyState.Name;
                            writer.WritePropertyName(EscapedName.Value);
                        }

                        int originalDepth = writer.CurrentDepth;
                        Converter.Write(writer, value, Options);
                        if (originalDepth != writer.CurrentDepth)
                        {
                            ThrowHelper.ThrowJsonException_SerializationConverterWrite(Converter);
                        }
                    }
                }

                success = true;
            }
            else
            {
                if (state.Current.PropertyState < StackFramePropertyState.Name)
                {
                    state.Current.PropertyState = StackFramePropertyState.Name;
                    writer.WritePropertyName(EscapedName.Value);
                }

                success = Converter.TryWrite(writer, value, Options, ref state);
            }

            return(success);
        }
Beispiel #19
0
        public override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer)
        {
            bool           success;
            TTypeToConvert value = Get !(obj);

            if (value == null)
            {
                success = true;
            }
            else
            {
                state.Current.PolymorphicJsonPropertyInfo = state.Current.DeclaredJsonPropertyInfo !.RuntimeClassInfo.ElementClassInfo !.PropertyInfoForClassInfo;
                success = Converter.TryWriteDataExtensionProperty(writer, value, Options, ref state);
            }

            return(success);
        }
Beispiel #20
0
        public void Write(ref WriteStack state, Utf8JsonWriter writer)
        {
            Debug.Assert(ShouldSerialize);

            if (state.Current.Enumerator != null)
            {
                // Forward the setter to the value-based JsonPropertyInfo.
                JsonPropertyInfo propertyInfo = ElementClassInfo.GetPolicyProperty();
                propertyInfo.OnWriteEnumerable(ref state.Current, writer);
            }
            else
            {
                int originalDepth = writer.CurrentDepth;
                OnWrite(ref state.Current, writer);
                VerifyWrite(originalDepth, ref state, ref writer);
            }
        }
Beispiel #21
0
        public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer)
        {
            T value = Get !(obj);

            if (IgnoreDefaultValuesOnWrite)
            {
                // If value is null, it is a reference type or nullable<T>.
                if (value == null)
                {
                    return(true);
                }

                if (!PropertyTypeCanBeNull)
                {
                    if (_propertyTypeEqualsTypeToConvert)
                    {
                        // The converter and property types are the same, so we can use T for EqualityComparer<>.
                        if (EqualityComparer <T> .Default.Equals(default, value))
Beispiel #22
0
        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 object discriminator)
            {
                Debug.Assert(state.Parent.JsonPropertyInfo !.JsonTypeInfo.PolymorphicTypeResolver != null);

                JsonEncodedText propertyName =
                    state.Parent.JsonPropertyInfo.JsonTypeInfo.PolymorphicTypeResolver.CustomTypeDiscriminatorPropertyNameJsonEncoded is JsonEncodedText customPropertyName
                    ? customPropertyName
                    : s_metadataType;

                if (discriminator is string stringId)
                {
                    writer.WriteString(propertyName, stringId);
                }
                else
                {
                    Debug.Assert(discriminator is int);
                    writer.WriteNumber(propertyName, (int)discriminator);
                }

                writtenMetadata |= MetadataPropertyName.Type;
                state.PolymorphicTypeDiscriminator = null;
            }

            Debug.Assert(writtenMetadata != MetadataPropertyName.None);
            return(writtenMetadata);
        }
Beispiel #23
0
        private static void WriteCore <TValue>(Utf8JsonWriter writer, TValue value, Type inputType, JsonSerializerOptions options)
        {
            Debug.Assert(writer != null);

            //  We treat typeof(object) special and allow polymorphic behavior.
            if (inputType == typeof(object) && value != null)
            {
                inputType = value !.GetType();
            }

            WriteStack state = default;

            state.Initialize(inputType, options, supportContinuation: false);
            JsonConverter jsonConverter = state.Current.JsonClassInfo !.PropertyInfoForClassInfo.ConverterBase;

            bool success = WriteCore(jsonConverter, writer, value, options, ref state);

            Debug.Assert(success);
        }
        internal static MetadataPropertyName WriteReferenceForCollection(
            JsonConverter jsonConverter,
            ref WriteStack state,
            Utf8JsonWriter writer)
        {
            if (state.NewReferenceId != null)
            {
                Debug.Assert(jsonConverter.CanHaveMetadata);
                writer.WriteStartObject();
                writer.WriteString(s_metadataId, state.NewReferenceId);
                writer.WriteStartArray(s_metadataValues);
                state.NewReferenceId = null;
                return(MetadataPropertyName.Id);
            }

            // If the jsonConverter supports immutable enumerables or value type collections, don't write any metadata
            writer.WriteStartArray();
            return(MetadataPropertyName.None);
        }
Beispiel #25
0
        private static bool WriteObject(
            JsonSerializerOptions options,
            Utf8JsonWriter writer,
            ref WriteStack state)
        {
            // Write the start.
            if (!state.Current.StartObjectWritten)
            {
                // If true, we are writing a root object or a value that doesn't belong
                // to an object e.g. a dictionary value.
                if (state.Current.CurrentValue == null)
                {
                    state.Current.WriteObjectOrArrayStart(ClassType.Object, writer, options, writeNull: true);
                    return(WriteEndObject(ref state));
                }

                if (options.ReferenceHandling.ShouldWritePreservedReferences())
                {
                    if (WriteReference(ref state, writer, options, ClassType.Object, state.Current.CurrentValue))
                    {
                        return(WriteEndObject(ref state));
                    }
                }
                else
                {
                    state.Current.WriteObjectOrArrayStart(ClassType.Object, writer, options);
                }

                state.Current.MoveToNextProperty = true;
            }

            if (state.Current.MoveToNextProperty)
            {
                state.Current.NextProperty();
            }

            // Determine if we are done enumerating properties.
            if (state.Current.ExtensionDataStatus != ExtensionDataWriteStatus.Finished)
            {
                // If ClassType.Unknown at this point, we are typeof(object) which should not have any properties.
                Debug.Assert(state.Current.JsonClassInfo !.ClassType != ClassType.Unknown);

                JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.PropertyCacheArray ![state.Current.PropertyEnumeratorIndex - 1];
Beispiel #26
0
        internal static MetadataPropertyName GetResolvedReferenceHandling(
            JsonConverter converter,
            object value,
            ref WriteStack state,
            out string?referenceId)
        {
            if (!converter.CanHaveIdMetadata || converter.TypeToConvert.IsValueType)
            {
                referenceId = default;
                return(MetadataPropertyName.NoMetadata);
            }

            if (state.ReferenceResolver.TryGetOrAddReferenceOnSerialize(value, out referenceId))
            {
                return(MetadataPropertyName.Ref);
            }

            return(MetadataPropertyName.Id);
        }
Beispiel #27
0
        internal static MetadataPropertyName WriteReferenceForObject(
            JsonConverter jsonConverter,
            object currentValue,
            ref WriteStack state,
            Utf8JsonWriter writer)
        {
            MetadataPropertyName metadataToWrite = GetResolvedReferenceHandling(jsonConverter, currentValue, ref state, out string?referenceId);

            if (metadataToWrite == MetadataPropertyName.Ref)
            {
                writer.WriteString(s_metadataRef, referenceId !);
                writer.WriteEndObject();
            }
            else if (metadataToWrite == MetadataPropertyName.Id)
            {
                writer.WriteString(s_metadataId, referenceId !);
            }

            return(metadataToWrite);
        }
        private static async Task WriteAsyncCore <TValue>(Stream utf8Json, TValue value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                options = JsonSerializerOptions.s_defaultOptions;
            }

            JsonWriterOptions writerOptions = options.GetWriterOptions();

            using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize))
                using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions))
                {
                    //  We treat typeof(object) special and allow polymorphic behavior.
                    if (inputType == typeof(object) && value != null)
                    {
                        inputType = value !.GetType();
                    }

                    WriteStack state = default;
                    state.Initialize(inputType, options, supportContinuation: true);

                    JsonConverter converterBase = state.Current.JsonClassInfo !.PropertyInfoForClassInfo.ConverterBase;

                    bool isFinalBlock;

                    do
                    {
                        // todo: determine best value here
                        // https://github.com/dotnet/runtime/issues/32356
                        state.FlushThreshold = (int)(bufferWriter.Capacity * .9);

                        isFinalBlock = WriteCore(converterBase, writer, value, options, ref state);

                        await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false);

                        bufferWriter.Clear();
                    } while (!isFinalBlock);
                }

            // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best.
        }
Beispiel #29
0
        private static bool WriteObject(
            JsonSerializerOptions options,
            Utf8JsonWriter writer,
            ref WriteStack state)
        {
            // Write the start.
            if (!state.Current.StartObjectWritten)
            {
                // If true, we are writing a root object or a value that doesn't belong
                // to an object e.g. a dictionary value.
                if (state.Current.CurrentValue == null)
                {
                    state.Current.WriteObjectOrArrayStart(ClassType.Object, writer, options, writeNull: true);
                    return(WriteEndObject(ref state));
                }

                state.Current.WriteObjectOrArrayStart(ClassType.Object, writer, options);
                state.Current.PropertyEnumeratorActive = true;
                state.Current.MoveToNextProperty       = true;
            }

            if (state.Current.MoveToNextProperty)
            {
                state.Current.NextProperty();
            }

            // Determine if we are done enumerating properties.
            if (state.Current.PropertyEnumeratorActive)
            {
                // If ClassType.Unknown at this point, we are typeof(object) which should not have any properties.
                Debug.Assert(state.Current.JsonClassInfo.ClassType != ClassType.Unknown);

                JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.PropertyCacheArray[state.Current.PropertyEnumeratorIndex - 1];
                HandleObject(jsonPropertyInfo, options, writer, ref state);

                return(false);
            }

            writer.WriteEndObject();
            return(WriteEndObject(ref state));
        }
        private static bool WriteObject(
            JsonSerializerOptions options,
            Utf8JsonWriter writer,
            ref WriteStack state)
        {
            // Write the start.
            if (!state.Current.StartObjectWritten)
            {
                state.Current.WriteObjectOrArrayStart(ClassType.Object, writer);
            }

            if (state.Current.MoveToNextProperty)
            {
                state.Current.NextProperty();
            }

            // Determine if we are done enumerating properties.
            // If the ClassType is unknown, there will be a policy property applied. There is probably
            // a better way to identify policy properties- maybe not put them in the normal property bag?
            JsonClassInfo classInfo = state.Current.JsonClassInfo;

            if (classInfo.ClassType != ClassType.Unknown && state.Current.PropertyIndex != classInfo.PropertyCount)
            {
                HandleObject(options, writer, ref state);
                return(false);
            }

            writer.WriteEndObject();

            if (state.Current.PopStackOnEndObject)
            {
                state.Pop();
            }
            else
            {
                state.Current.EndObject();
            }

            return(true);
        }