{
public override void Write(Utf8JsonWriter writer, JsonArray value, JsonSerializerOptions options)
{
- Debug.Assert(value != null);
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
value.WriteTo(writer, options);
}
public override void Write(Utf8JsonWriter writer, JsonObject value, JsonSerializerOptions options)
{
- Debug.Assert(value != null);
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
value.WriteTo(writer, options);
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Diagnostics;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization.Metadata;
{
public override void Write(Utf8JsonWriter writer, JsonValue value, JsonSerializerOptions options)
{
- Debug.Assert(value != null);
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
value.WriteTo(writer, options);
}
- public override JsonValue Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override JsonValue? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
+ if (reader.TokenType is JsonTokenType.Null)
+ {
+ return null;
+ }
+
JsonElement element = JsonElement.ParseValue(ref reader);
JsonValue value = new JsonValueTrimmable<JsonElement>(element, JsonMetadataServices.JsonElementConverter, options.GetNodeOptions());
return value;
public override void Write(Utf8JsonWriter writer, object? value, JsonSerializerOptions options)
{
- Debug.Assert(value?.GetType() == typeof(object));
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
writer.WriteStartObject();
writer.WriteEndObject();
}
public override void Write(Utf8JsonWriter writer, JsonDocument value, JsonSerializerOptions options)
{
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
value.WriteTo(writer);
}
}
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
-using System.Runtime.CompilerServices;
namespace System.Text.Json.Serialization.Converters
{
internal sealed class UriConverter : JsonPrimitiveConverter<Uri>
{
- public override Uri Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override Uri? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
- string? uriString = reader.GetString();
- if (Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out Uri? value))
- {
- return value;
- }
-
- ThrowHelper.ThrowJsonException();
- return null;
+ return reader.TokenType is JsonTokenType.Null ? null : ReadCore(ref reader);
}
public override void Write(Utf8JsonWriter writer, Uri value, JsonSerializerOptions options)
{
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
writer.WriteStringValue(value.OriginalString);
}
internal override Uri ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(reader.TokenType is JsonTokenType.PropertyName);
- return Read(ref reader, typeToConvert, options);
+ return ReadCore(ref reader);
+ }
+
+ private static Uri ReadCore(ref Utf8JsonReader reader)
+ {
+ string? uriString = reader.GetString();
+
+ if (!Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out Uri? value))
+ {
+ ThrowHelper.ThrowJsonException();
+ }
+
+ return value;
}
internal override void WriteAsPropertyNameCore(Utf8JsonWriter writer, Uri value, JsonSerializerOptions options, bool isWritingExtensionDataProperty)
private const int MaximumEscapedVersionLength = JsonConstants.MaxExpansionFactorWhileEscaping * MaximumVersionLength;
#endif
- public override Version Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override Version? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
+ if (reader.TokenType is JsonTokenType.Null)
+ {
+ return null;
+ }
+
if (reader.TokenType != JsonTokenType.String)
{
ThrowHelper.ThrowInvalidOperationException_ExpectedString(reader.TokenType);
public override void Write(Utf8JsonWriter writer, Version value, JsonSerializerOptions options)
{
+ if (value is null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
#if NETCOREAPP
Span<char> span = stackalloc char[MaximumVersionLength];
bool formattedSuccessfully = value.TryFormat(span, out int charsWritten);
Assert.Null(JsonSerializer.Deserialize("null", type, options));
}
}
+
+ [Theory]
+ [MemberData(nameof(GetBuiltInConvertersForNullableTypes))]
+ public static void ReadNullValue_BuiltInConverter<T>(JsonConverter<T> converter)
+ {
+ var reader = new Utf8JsonReader("null"u8);
+ Assert.True(reader.Read());
+ Assert.Equal(JsonTokenType.Null, reader.TokenType);
+
+ T? result = converter.Read(ref reader, typeof(T), JsonSerializerOptions.Default);
+ Assert.True(result is null or JsonDocument { RootElement.ValueKind: JsonValueKind.Null } or JsonElement { ValueKind: JsonValueKind.Null });
+ }
+
+ [Theory]
+ [MemberData(nameof(GetBuiltInConvertersForNullableTypes))]
+ public static void DeserializeNullValue_BuiltInConverter<T>(JsonConverter<T> converter)
+ {
+ _ = converter; // Not needed here.
+
+ T? value = JsonSerializer.Deserialize<T>("null");
+ AssertNull(value);
+
+ T[]? array = JsonSerializer.Deserialize<T[]>("[null]");
+ AssertNull(array[0]);
+
+ List<T>? list = JsonSerializer.Deserialize<List<T>>("[null]");
+ AssertNull(list[0]);
+
+ GenericRecord<T>? record = JsonSerializer.Deserialize<GenericRecord<T>>("""{"Value":null}""");
+ AssertNull(record.Value);
+
+ Dictionary<string, T>? dictionary = JsonSerializer.Deserialize<Dictionary<string, T>>("""{"Key":null}""");
+ AssertNull(dictionary["Key"]);
+
+ static void AssertNull(T? result) => Assert.True(
+ result is null
+ or JsonDocument { RootElement.ValueKind: JsonValueKind.Null }
+ or JsonElement { ValueKind: JsonValueKind.Null });
+ }
}
}
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text.Json.Serialization.Metadata;
using Xunit;
namespace System.Text.Json.Serialization.Tests
json = JsonSerializer.Serialize<int[,]>(arr, options);
Assert.Equal("null", json);
}
+
+ [Theory]
+ [MemberData(nameof(GetBuiltInConvertersForNullableTypes))]
+ public static void WriteNullValue_BuiltInConverter<T>(JsonConverter<T> converter)
+ {
+ T @null = default;
+ Assert.Null(@null);
+
+ using var stream = new Utf8MemoryStream();
+ using var writer = new Utf8JsonWriter(stream);
+
+ converter.Write(writer, @null, JsonSerializerOptions.Default);
+ writer.Flush();
+
+ Assert.Equal("null", stream.AsString());
+ }
+
+ [Theory]
+ [MemberData(nameof(GetBuiltInConvertersForNullableTypes))]
+ public static void SerializeNullValue_BuiltInConverter<T>(JsonConverter<T> converter)
+ {
+ _ = converter; // Not needed here.
+
+ T @null = default;
+ Assert.Null(@null);
+
+ string json = JsonSerializer.Serialize(@null);
+ Assert.Equal("null", json);
+
+ json = JsonSerializer.Serialize(new T[] { @null });
+ Assert.Equal("[null]", json);
+
+ json = JsonSerializer.Serialize(new List<T> { @null });
+ Assert.Equal("[null]", json);
+
+ json = JsonSerializer.Serialize(new GenericRecord<T>(@null));
+ Assert.Equal("""{"Value":null}""", json);
+
+ json = JsonSerializer.Serialize(new Dictionary<string, T> { ["Key"] = @null });
+ Assert.Equal("""{"Key":null}""", json);
+ }
+
+ public static IEnumerable<object?[]> GetBuiltInConvertersForNullableTypes()
+ {
+ return typeof(JsonMetadataServices)
+ .GetProperties(BindingFlags.Public | BindingFlags.Static)
+ .Where(prop =>
+ prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(JsonConverter<>) &&
+ !prop.PropertyType.GetGenericArguments()[0].IsValueType)
+ .Select(prop => new object?[] { prop.GetValue(null) });
+ }
+
+ public record GenericRecord<T>(T Value);
}
}