public override void Write(Utf8JsonWriter writer, TimeSpan?value, JsonSerializerOptions options) { if (value is null) { writer.WriteNullValue(); } else { writer.WriteStringValue(value.Value.ToString("c", CultureInfo.InvariantCulture)); } }
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. }
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. }
private static TValue?ReadNode <TValue>(JsonNode?node, JsonTypeInfo jsonTypeInfo) { JsonSerializerOptions options = jsonTypeInfo.Options; // For performance, share the same buffer across serialization and deserialization. using var output = new PooledByteBufferWriter(options.DefaultBufferSize); using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { if (node is null) { writer.WriteNullValue(); } else { node.WriteTo(writer, options); } } return(ReadFromSpan <TValue>(output.WrittenMemory.Span, jsonTypeInfo)); }
private static void WriteCore(Utf8JsonWriter writer, object?value, Type type, JsonSerializerOptions options) { Debug.Assert(type != null || value == null); Debug.Assert(writer != null); if (value == null) { writer.WriteNullValue(); } else { // We treat typeof(object) special and allow polymorphic behavior. if (type == typeof(object)) { type = value.GetType(); } WriteStack state = default; state.InitializeRoot(type !, options, supportContinuation: false); WriteCore(writer, value, options, ref state, state.Current.JsonClassInfo !.PolicyProperty !.ConverterBase); } writer.Flush(); }
private static bool HandleEnumerable( JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, ref WriteStack state) { Debug.Assert(state.Current.JsonPropertyInfo.ClassType == ClassType.Enumerable); if (state.Current.CollectionEnumerator == null) { IEnumerable enumerable = (IEnumerable)state.Current.JsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue); if (enumerable == null) { // If applicable, we only want to ignore object properties. if (state.Current.JsonClassInfo.ClassType != ClassType.Object || !state.Current.JsonPropertyInfo.IgnoreNullValues) { // Write a null object or enumerable. state.Current.WriteObjectOrArrayStart(ClassType.Enumerable, writer, writeNull: true); } if (state.Current.PopStackOnEndCollection) { state.Pop(); } return(true); } state.Current.CollectionEnumerator = enumerable.GetEnumerator(); state.Current.WriteObjectOrArrayStart(ClassType.Enumerable, writer); } if (state.Current.CollectionEnumerator.MoveNext()) { // Check for polymorphism. if (elementClassInfo.ClassType == ClassType.Unknown) { object currentValue = state.Current.CollectionEnumerator.Current; GetRuntimeClassInfo(currentValue, ref elementClassInfo, options); } if (elementClassInfo.ClassType == ClassType.Value) { elementClassInfo.PolicyProperty.WriteEnumerable(ref state, writer); } else if (state.Current.CollectionEnumerator.Current == null) { // Write a null object or enumerable. writer.WriteNullValue(); } else { // An object or another enumerator requires a new stack frame. object nextValue = state.Current.CollectionEnumerator.Current; state.Push(elementClassInfo, nextValue); } return(false); } // We are done enumerating. writer.WriteEndArray(); if (state.Current.PopStackOnEndCollection) { state.Pop(); } else { state.Current.EndArray(); } return(true); }
/// <summary> /// Writes this instance to provided writer. /// </summary> /// <param name="writer">Writer to wrtire this instance to.</param> public void WriteTo(Utf8JsonWriter writer) { var recursionStack = new Stack <RecursionStackFrame>(); recursionStack.Push(new RecursionStackFrame(null, this)); while (recursionStack.Any()) { RecursionStackFrame currentFrame = recursionStack.Peek(); recursionStack.Pop(); if (currentFrame.PropertyValue == null) { // Current object/array is finished. // PropertyValue is null, so we need to check ValueKind: Debug.Assert(currentFrame.ValueKind == JsonValueKind.Object || currentFrame.ValueKind == JsonValueKind.Array); if (currentFrame.ValueKind == JsonValueKind.Object) { writer.WriteEndObject(); } if (currentFrame.ValueKind == JsonValueKind.Array) { writer.WriteEndArray(); } continue; } if (currentFrame.PropertyName != null) { writer.WritePropertyName(currentFrame.PropertyName); } switch (currentFrame.PropertyValue) { case JsonObject jsonObject: writer.WriteStartObject(); // Add end of object marker: recursionStack.Push(new RecursionStackFrame(null, null, JsonValueKind.Object)); // Add properties to recursion stack. Reverse enumerator to keep properties order: foreach (KeyValuePair <string, JsonNode> jsonProperty in jsonObject.Reverse()) { recursionStack.Push(new RecursionStackFrame(jsonProperty.Key, jsonProperty.Value)); } break; case JsonArray jsonArray: writer.WriteStartArray(); // Add end of array marker: recursionStack.Push(new RecursionStackFrame(null, null, JsonValueKind.Array)); // Add items to recursion stack. Reverse enumerator to keep items order: foreach (JsonNode item in jsonArray.Reverse()) { recursionStack.Push(new RecursionStackFrame(null, item)); } break; case JsonString jsonString: writer.WriteStringValue(jsonString.Value); break; case JsonNumber jsonNumber: writer.WriteNumberValue(Encoding.UTF8.GetBytes(jsonNumber.ToString())); break; case JsonBoolean jsonBoolean: writer.WriteBooleanValue(jsonBoolean.Value); break; case JsonNull _: writer.WriteNullValue(); break; } writer.Flush(); } writer.Flush(); }