string propertyName = reader.GetString();
if (propertyName == KeyName)
{
- k = ReadProperty<TKey>(ref reader, options);
+ k = ReadProperty<TKey>(ref reader, typeToConvert, options);
keySet = true;
}
else if (propertyName == ValueName)
{
- v = ReadProperty<TValue>(ref reader, options);
+ v = ReadProperty<TValue>(ref reader, typeToConvert, options);
valueSet = true;
}
else
propertyName = reader.GetString();
if (propertyName == ValueName)
{
- v = ReadProperty<TValue>(ref reader, options);
+ v = ReadProperty<TValue>(ref reader, typeToConvert, options);
valueSet = true;
}
else if (propertyName == KeyName)
{
- k = ReadProperty<TKey>(ref reader, options);
+ k = ReadProperty<TKey>(ref reader, typeToConvert, options);
keySet = true;
}
else
return new KeyValuePair<TKey, TValue>(k, v);
}
- private T ReadProperty<T>(ref Utf8JsonReader reader, JsonSerializerOptions options)
+ private T ReadProperty<T>(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
T k;
- Type typeToConvert = typeof(T);
- // Attempt to use existing converter first before re-entering through JsonSerializer.Read().
- JsonConverter<T> keyConverter = options.GetConverter(typeToConvert) as JsonConverter<T>;
- if (keyConverter == null)
+ // Attempt to use existing converter first before re-entering through JsonSerializer.Deserialize().
+ // The default converter for objects does not parse null objects as null, so it is not used here.
+ if (typeToConvert != typeof(object) && (options.GetConverter(typeToConvert) is JsonConverter<T> keyConverter))
{
- k = JsonSerializer.Deserialize<T>(ref reader, options);
+ reader.Read();
+ k = keyConverter.Read(ref reader, typeToConvert, options);
}
else
{
- reader.Read();
- k = keyConverter.Read(ref reader, typeToConvert, options);
+ k = JsonSerializer.Deserialize<T>(ref reader, options);
}
return k;
private void WriteProperty<T>(Utf8JsonWriter writer, T value, JsonEncodedText name, JsonSerializerOptions options)
{
+ Type typeToConvert = typeof(T);
+
writer.WritePropertyName(name);
- // Attempt to use existing converter first before re-entering through JsonSerializer.Write().
- JsonConverter<T> keyConverter = options.GetConverter(typeof(T)) as JsonConverter<T>;
- if (keyConverter == null)
+ // Attempt to use existing converter first before re-entering through JsonSerializer.Serialize().
+ // The default converter for object does not support writing.
+ if (typeToConvert != typeof(object) && (options.GetConverter(typeToConvert) is JsonConverter<T> keyConverter))
{
- JsonSerializer.Serialize<T>(writer, value, options);
+ keyConverter.Write(writer, value, options);
}
else
{
- keyConverter.Write(writer, value, options);
+ JsonSerializer.Serialize<T>(writer, value, options);
}
}
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
enumerable = (IEnumerable)jsonPropertyInfo.GetValueAsObject(state.Current.CurrentValue);
if (enumerable == null)
{
- if (!state.Current.JsonPropertyInfo.IgnoreNullValues)
+ // 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);
+ state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, writeNull: true);
+ }
+
+ if (state.Current.PopStackOnEndCollection)
+ {
+ state.Pop();
}
return true;
if (enumerable == null)
{
- if (!state.Current.JsonPropertyInfo.IgnoreNullValues)
+ // 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;
}
// 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, writeNull: true);
+ return WriteEndObject(ref state);
+ }
+
state.Current.WriteObjectOrArrayStart(ClassType.Object, writer);
state.Current.PropertyEnumerator = state.Current.JsonClassInfo.PropertyCache.GetEnumerator();
state.Current.PropertyEnumeratorActive = true;
}
writer.WriteEndObject();
+ return WriteEndObject(ref state);
+ }
+ private static bool WriteEndObject(ref WriteStack state)
+ {
if (state.Current.PopStackOnEndObject)
{
state.Pop();
return endOfEnumerable;
}
- // A property that returns an immutable dictionary keeps the same stack frame.
+ // A property that returns a type that is deserialized by passing an
+ // IDictionary to its constructor keeps the same stack frame.
if (jsonPropertyInfo.ClassType == ClassType.IDictionaryConstructible)
{
state.Current.IsIDictionaryConstructibleProperty = true;
Assert.Null(dictionaryLast.Dict);
}
+ [Fact]
+ public static void NullDictionaryValuesShouldDeserializeAsNull()
+ {
+ const string json =
+ @"{" +
+ @"""StringVals"":{" +
+ @"""key"":null" +
+ @"}," +
+ @"""ObjectVals"":{" +
+ @"""key"":null" +
+ @"}," +
+ @"""StringDictVals"":{" +
+ @"""key"":null" +
+ @"}," +
+ @"""ObjectDictVals"":{" +
+ @"""key"":null" +
+ @"}," +
+ @"""ClassVals"":{" +
+ @"""key"":null" +
+ @"}" +
+ @"}";
+
+ SimpleClassWithDictionaries obj = JsonSerializer.Deserialize<SimpleClassWithDictionaries>(json);
+ Assert.Null(obj.StringVals["key"]);
+ Assert.Null(obj.ObjectVals["key"]);
+ Assert.Null(obj.StringDictVals["key"]);
+ Assert.Null(obj.ObjectDictVals["key"]);
+ Assert.Null(obj.ClassVals["key"]);
+ }
+
public class ClassWithNotSupportedDictionary
{
public Dictionary<int, int> MyDictionary { get; set; }
public Dictionary<string, string> Dict { get; set; }
public string Test { get; set; }
}
+
+ public class SimpleClassWithDictionaries
+ {
+ public Dictionary<string, string> StringVals { get; set; }
+ public Dictionary<string, object> ObjectVals { get; set; }
+ public Dictionary<string, Dictionary<string, string>> StringDictVals { get; set; }
+ public Dictionary<string, Dictionary<string, object>> ObjectDictVals { get; set; }
+ public Dictionary<string, SimpleClassWithDictionaries> ClassVals { get; set; }
+ }
}
}
Assert.Null(obj.MyInt);
Assert.Null(obj.MyIntArray);
Assert.Null(obj.MyIntList);
+ Assert.Null(obj.MyObjectList[0]);
+ Assert.Null(obj.MyListList[0][0]);
+ Assert.Null(obj.MyDictionaryList[0]["key"]);
+ Assert.Null(obj.MyStringDictionary["key"]);
+ Assert.Null(obj.MyObjectDictionary["key"]);
+ Assert.Null(obj.MyStringDictionaryDictionary["key"]["key"]);
+ Assert.Null(obj.MyListDictionary["key"][0]);
+ Assert.Null(obj.MyObjectDictionaryDictionary["key"]["key"]);
}
[Fact]
options.IgnoreNullValues = true;
TestClassWithInitializedProperties obj = JsonSerializer.Deserialize<TestClassWithInitializedProperties>(TestClassWithInitializedProperties.s_null_json, options);
+
Assert.Equal("Hello", obj.MyString);
Assert.Equal(1, obj.MyInt);
Assert.Equal(1, obj.MyIntArray[0]);
Assert.Equal(1, obj.MyIntList[0]);
+
+ Assert.Null(obj.MyObjectList[0]);
+ Assert.Null(obj.MyObjectList[0]);
+ Assert.Null(obj.MyListList[0][0]);
+ Assert.Null(obj.MyDictionaryList[0]["key"]);
+ Assert.Null(obj.MyStringDictionary["key"]);
+ Assert.Null(obj.MyObjectDictionary["key"]);
+ Assert.Null(obj.MyStringDictionaryDictionary["key"]["key"]);
+ Assert.Null(obj.MyListDictionary["key"][0]);
+ Assert.Null(obj.MyObjectDictionaryDictionary["key"]["key"]);
}
[Fact]
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using Xunit;
namespace System.Text.Json.Serialization.Tests
[Fact]
public static void DefaultIgnoreNullValuesOnWrite()
{
- var obj = new TestClassWithInitializedProperties();
- obj.MyString = null;
- obj.MyInt = null;
- obj.MyIntArray = null;
- obj.MyIntList = null;
+ var obj = new TestClassWithInitializedProperties
+ {
+ MyString = null,
+ MyInt = null,
+ MyIntArray = null,
+ MyIntList = null,
+ MyObjectList = new List<object> { null },
+ MyListList = new List<List<object>> { new List<object> { null } },
+ MyDictionaryList = new List<Dictionary<string, string>> { new Dictionary<string, string>() { ["key"] = null } },
+ MyStringDictionary = new Dictionary<string, string>() { ["key"] = null },
+ MyObjectDictionary = new Dictionary<string, object>() { ["key"] = null },
+ MyStringDictionaryDictionary = new Dictionary<string, Dictionary<string, string>>() { ["key"] = null },
+ MyListDictionary = new Dictionary<string, List<object>>() { ["key"] = null },
+ MyObjectDictionaryDictionary = new Dictionary<string, Dictionary<string, object>>() { ["key"] = null }
+ };
string json = JsonSerializer.Serialize(obj);
Assert.Contains(@"""MyString"":null", json);
Assert.Contains(@"""MyInt"":null", json);
Assert.Contains(@"""MyIntArray"":null", json);
Assert.Contains(@"""MyIntList"":null", json);
+ Assert.Contains(@"""MyObjectList"":[null],", json);
+ Assert.Contains(@"""MyListList"":[[null]],", json);
+ Assert.Contains(@"""MyDictionaryList"":[{""key"":null}],", json);
+ Assert.Contains(@"""MyStringDictionary"":{""key"":null},", json);
+ Assert.Contains(@"""MyObjectDictionary"":{""key"":null},", json);
+ Assert.Contains(@"""MyStringDictionaryDictionary"":{""key"":null},", json);
+ Assert.Contains(@"""MyListDictionary"":{""key"":null},", json);
+ Assert.Contains(@"""MyObjectDictionaryDictionary"":{""key"":null}", json);
}
[Fact]
JsonSerializerOptions options = new JsonSerializerOptions();
options.IgnoreNullValues = true;
- var obj = new TestClassWithInitializedProperties();
- obj.MyString = null;
- obj.MyInt = null;
- obj.MyIntArray = null;
- obj.MyIntList = null;
+ var obj = new TestClassWithInitializedProperties
+ {
+ MyString = null,
+ MyInt = null,
+ MyIntArray = null,
+ MyIntList = null,
+ MyObjectList = new List<object> { null },
+ MyListList = new List<List<object>> { new List<object> { null } },
+ MyDictionaryList = new List<Dictionary<string, string>> { new Dictionary<string, string>() { ["key"] = null } },
+ MyStringDictionary = new Dictionary<string, string>() { ["key"] = null },
+ MyObjectDictionary = new Dictionary<string, object>() { ["key"] = null },
+ MyStringDictionaryDictionary = new Dictionary<string, Dictionary<string, string>>() { ["key"] = null },
+ MyListDictionary = new Dictionary<string, List<object>>() { ["key"] = null },
+ MyObjectDictionaryDictionary = new Dictionary<string, Dictionary<string, object>>() { ["key"] = null }
+ };
+
+ string expectedJson =
+ @"{" +
+ @"""MyObjectList"":[null]," +
+ @"""MyListList"":[[null]]," +
+ @"""MyDictionaryList"":[" +
+ @"{" +
+ @"""key"":null" +
+ @"}" +
+ @"]," +
+ @"""MyStringDictionary"":{" +
+ @"""key"":null" +
+ @"}," +
+ @"""MyObjectDictionary"":{" +
+ @"""key"":null" +
+ @"}," +
+ @"""MyStringDictionaryDictionary"":{" +
+ @"""key"":null" +
+ @"}," +
+ @"""MyListDictionary"":{" +
+ @"""key"":null" +
+ @"}," +
+ @"""MyObjectDictionaryDictionary"":{" +
+ @"""key"":null" +
+ @"}" +
+ @"}";
- string json = JsonSerializer.Serialize(obj, options);
- Assert.Equal(@"{}", json);
+ Assert.Equal(expectedJson, JsonSerializer.Serialize(obj, options));
+
+ var parentObj = new WrapperForTestClassWithInitializedProperties
+ {
+ MyClass = obj
+ };
+
+ expectedJson = @"{""MyClass"":" + expectedJson + "}";
+ Assert.Equal(expectedJson, JsonSerializer.Serialize(parentObj, options));
}
[Fact]
Assert.Equal("null", output);
}
}
+
+ class WrapperForTestClassWithInitializedProperties
+ {
+ public TestClassWithInitializedProperties MyClass { get; set; }
+ }
+
+ [Fact]
+ public static void SerializeDictionaryWithNullValues()
+ {
+ Dictionary<string, string> StringVals = new Dictionary<string, string>()
+ {
+ ["key"] = null,
+ };
+ Assert.Equal(@"{""key"":null}", JsonSerializer.Serialize(StringVals));
+
+ Dictionary<string, object> ObjVals = new Dictionary<string, object>()
+ {
+ ["key"] = null,
+ };
+ Assert.Equal(@"{""key"":null}", JsonSerializer.Serialize(ObjVals));
+
+ Dictionary<string, Dictionary<string, string>> StringDictVals = new Dictionary<string, Dictionary<string, string>>()
+ {
+ ["key"] = null,
+ };
+ Assert.Equal(@"{""key"":null}", JsonSerializer.Serialize(StringDictVals));
+
+ Dictionary<string, Dictionary<string, object>> ObjectDictVals = new Dictionary<string, Dictionary<string, object>>()
+ {
+ ["key"] = null,
+ };
+ Assert.Equal(@"{""key"":null}", JsonSerializer.Serialize(ObjectDictVals));
+ }
+
+ [Fact]
+ public static void DeserializeDictionaryWithNullValues()
+ {
+ {
+ Dictionary<string, string> dict = JsonSerializer.Deserialize<Dictionary<string, string>>(@"{""key"":null}");
+ Assert.Null(dict["key"]);
+ }
+
+ {
+ Dictionary<string, object> dict = JsonSerializer.Deserialize<Dictionary<string, object>>(@"{""key"":null}");
+ Assert.Null(dict["key"]);
+ }
+
+ {
+ Dictionary<string, Dictionary<string, string>> dict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(@"{""key"":null}");
+ Assert.Null(dict["key"]);
+ }
+
+ {
+ Dictionary<string, Dictionary<string, object>> dict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, object>>>(@"{""key"":null}");
+ Assert.Null(dict["key"]);
+ }
+ }
}
}
public int? MyInt { get; set; } = 1;
public int[] MyIntArray { get; set; } = new int[] { 1 };
public List<int> MyIntList { get; set; } = new List<int> { 1 };
+ public List<object> MyObjectList { get; set; } = new List<object> { 1 };
+ public List<List<object>> MyListList { get; set; } = new List<List<object>> { new List<object> { 1 } };
+ public List<Dictionary<string, string>> MyDictionaryList { get; set; } = new List<Dictionary<string, string>> {
+ new Dictionary<string, string> { ["key"] = "value" }
+ };
+ public Dictionary<string, string> MyStringDictionary { get; set; } = new Dictionary<string, string> { ["key"] = "value" };
+ public Dictionary<string, object> MyObjectDictionary { get; set; } = new Dictionary<string, object> { ["key"] = "value" };
+ public Dictionary<string, Dictionary<string, string>> MyStringDictionaryDictionary { get; set; } = new Dictionary<string, Dictionary<string, string>>
+ {
+ ["key"] = new Dictionary<string, string>
+ {
+ ["key"] = "value"
+ }
+ };
+ public Dictionary<string, List<object>> MyListDictionary { get; set; } = new Dictionary<string, List<object>> {
+ ["key"] = new List<object> { "value" }
+ };
+ public Dictionary<string, Dictionary<string, object>> MyObjectDictionaryDictionary { get; set; } = new Dictionary<string, Dictionary<string, object>>
+ {
+ ["key"] = new Dictionary<string, object>
+ {
+ ["key"] = "value"
+ }
+ };
+
public static readonly string s_null_json =
@"{" +
- @"""MyString"" : null," +
- @"""MyInt"" : null," +
- @"""MyIntArray"" : null," +
- @"""MyIntList"" : null" +
+ @"""MyString"" : null," +
+ @"""MyInt"" : null," +
+ @"""MyIntArray"" : null," +
+ @"""MyIntList"" : null," +
+ @"""MyObjectList"" : [null]," +
+ @"""MyListList"" : [[null]]," +
+ @"""MyDictionaryList"" : [{""key"" : null}]," +
+ @"""MyStringDictionary"" : {""key"" : null}," +
+ @"""MyObjectDictionary"" : {""key"" : null}," +
+ @"""MyStringDictionaryDictionary"" : {""key"" : {""key"" : null}}," +
+ @"""MyListDictionary"" : {""key"" : [null]}," +
+ @"""MyObjectDictionaryDictionary"" : {""key"" : {""key"" : null}}" +
@"}";
public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_null_json);
}
[Fact]
+ public static void ReadKeyValuePairWithNullValues()
+ {
+ {
+ KeyValuePair<string, string> kvp = JsonSerializer.Deserialize<KeyValuePair<string, string>>(@"{""Key"":""key"",""Value"":null}");
+ Assert.Equal("key", kvp.Key);
+ Assert.Null(kvp.Value);
+ }
+
+ {
+ KeyValuePair<string, object> kvp = JsonSerializer.Deserialize<KeyValuePair<string, object>>(@"{""Key"":""key"",""Value"":null}");
+ Assert.Equal("key", kvp.Key);
+ Assert.Null(kvp.Value);
+ }
+
+ {
+ KeyValuePair<string, SimpleClassWithKeyValuePairs> kvp = JsonSerializer.Deserialize<KeyValuePair<string, SimpleClassWithKeyValuePairs>>(@"{""Key"":""key"",""Value"":null}");
+ Assert.Equal("key", kvp.Key);
+ Assert.Null(kvp.Value);
+ }
+
+ {
+ KeyValuePair<string, KeyValuePair<string, string>> kvp = JsonSerializer.Deserialize<KeyValuePair<string, KeyValuePair<string, string>>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}");
+ Assert.Equal("key", kvp.Key);
+ Assert.Equal("key", kvp.Value.Key);
+ Assert.Null(kvp.Value.Value);
+ }
+
+ {
+ KeyValuePair<string, KeyValuePair<string, object>> kvp = JsonSerializer.Deserialize<KeyValuePair<string, KeyValuePair<string, object>>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}");
+ Assert.Equal("key", kvp.Key);
+ Assert.Equal("key", kvp.Value.Key);
+ Assert.Null(kvp.Value.Value);
+ }
+
+ {
+ KeyValuePair<string, KeyValuePair<string, SimpleClassWithKeyValuePairs>> kvp = JsonSerializer.Deserialize<KeyValuePair<string, KeyValuePair<string, SimpleClassWithKeyValuePairs>>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}");
+ Assert.Equal("key", kvp.Key);
+ Assert.Equal("key", kvp.Value.Key);
+ Assert.Null(kvp.Value.Value);
+ }
+ }
+
+ [Fact]
+ public static void ReadClassWithNullKeyValuePairValues()
+ {
+ string json =
+ @"{" +
+ @"""KvpWStrVal"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":null" +
+ @"}," +
+ @"""KvpWObjVal"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":null" +
+ @"}," +
+ @"""KvpWClassVal"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":null" +
+ @"}," +
+ @"""KvpWStrKvpVal"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":null" +
+ @"}" +
+ @"}," +
+ @"""KvpWObjKvpVal"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":null" +
+ @"}" +
+ @"}," +
+ @"""KvpWClassKvpVal"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":{" +
+ @"""Key"":""key""," +
+ @"""Value"":null" +
+ @"}" +
+ @"}" +
+ @"}";
+ SimpleClassWithKeyValuePairs obj = JsonSerializer.Deserialize<SimpleClassWithKeyValuePairs>(json);
+
+ Assert.Equal("key", obj.KvpWStrVal.Key);
+ Assert.Equal("key", obj.KvpWObjVal.Key);
+ Assert.Equal("key", obj.KvpWClassVal.Key);
+ Assert.Equal("key", obj.KvpWStrKvpVal.Key);
+ Assert.Equal("key", obj.KvpWObjKvpVal.Key);
+ Assert.Equal("key", obj.KvpWClassKvpVal.Key);
+ Assert.Equal("key", obj.KvpWStrKvpVal.Value.Key);
+ Assert.Equal("key", obj.KvpWObjKvpVal.Value.Key);
+ Assert.Equal("key", obj.KvpWClassKvpVal.Value.Key);
+
+ Assert.Null(obj.KvpWStrVal.Value);
+ Assert.Null(obj.KvpWObjVal.Value);
+ Assert.Null(obj.KvpWClassVal.Value);
+ Assert.Null(obj.KvpWStrKvpVal.Value.Value);
+ Assert.Null(obj.KvpWObjKvpVal.Value.Value);
+ Assert.Null(obj.KvpWClassKvpVal.Value.Value);
+ }
+
+ [Fact]
public static void ReadSimpleTestClass_GenericCollectionWrappers()
{
SimpleTestClassWithGenericCollectionWrappers obj = JsonSerializer.Deserialize<SimpleTestClassWithGenericCollectionWrappers>(SimpleTestClassWithGenericCollectionWrappers.s_json);
}
[Fact]
+ public static void WriteKeyValuePairWithNullValues()
+ {
+ {
+ KeyValuePair<string, string> kvp = new KeyValuePair<string, string>("key", null);
+ Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp));
+ }
+
+ {
+ KeyValuePair<string, object> kvp = new KeyValuePair<string, object>("key", null);
+ Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp));
+ }
+
+ {
+ KeyValuePair<string, SimpleClassWithKeyValuePairs> kvp = new KeyValuePair<string, SimpleClassWithKeyValuePairs>("key", null);
+ Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp));
+ }
+
+ {
+ KeyValuePair<string, KeyValuePair<string, string>> kvp = new KeyValuePair<string, KeyValuePair<string, string>>("key", new KeyValuePair<string, string>("key", null));
+ Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp));
+ }
+
+ {
+ KeyValuePair<string, KeyValuePair<string, object>> kvp = new KeyValuePair<string, KeyValuePair<string, object>>("key", new KeyValuePair<string, object>("key", null));
+ Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp));
+ }
+
+ {
+ KeyValuePair<string, KeyValuePair<string, SimpleClassWithKeyValuePairs>> kvp = new KeyValuePair<string, KeyValuePair<string, SimpleClassWithKeyValuePairs>>("key", new KeyValuePair<string, SimpleClassWithKeyValuePairs>("key", null));
+ Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp));
+ }
+ }
+
+ // https://github.com/dotnet/corefx/issues/39808
+ [Fact]
+ public static void WriteClassWithNullKeyValuePairValues_Regression39808()
+ {
+ var value = new SimpleClassWithKeyValuePairs()
+ {
+ KvpWStrVal = new KeyValuePair<string, string>("key", null),
+ KvpWObjVal = new KeyValuePair<string, object>("key", null),
+ KvpWClassVal = new KeyValuePair<string, SimpleClassWithKeyValuePairs>("key", null),
+ KvpWStrKvpVal = new KeyValuePair<string, KeyValuePair<string, string>>("key", new KeyValuePair<string, string>("key", null)),
+ KvpWObjKvpVal = new KeyValuePair<string, KeyValuePair<string, object>>("key", new KeyValuePair<string, object>("key", null)),
+ KvpWClassKvpVal = new KeyValuePair<string, KeyValuePair<string, SimpleClassWithKeyValuePairs>>("key", new KeyValuePair<string, SimpleClassWithKeyValuePairs>("key", null)),
+ };
+
+ string expectedJson = @"{""KvpWStrVal"":{""Key"":""key"",""Value"":null},""KvpWObjVal"":{""Key"":""key"",""Value"":null},""KvpWClassVal"":{""Key"":""key"",""Value"":null},""KvpWStrKvpVal"":{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}},""KvpWObjKvpVal"":{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}},""KvpWClassKvpVal"":{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}}";
+ string result = JsonSerializer.Serialize(value);
+ Assert.Equal(expectedJson, result);
+ }
+
+ [Fact]
public static void WriteGenericCollectionWrappers()
{
SimpleTestClassWithGenericCollectionWrappers obj1 = new SimpleTestClassWithGenericCollectionWrappers();
Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5));
Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize<object>(obj5));
}
+
+ public class SimpleClassWithKeyValuePairs
+ {
+ public KeyValuePair<string, string> KvpWStrVal { get; set; }
+ public KeyValuePair<string, object> KvpWObjVal { get; set; }
+ public KeyValuePair<string, SimpleClassWithKeyValuePairs> KvpWClassVal { get; set; }
+ public KeyValuePair<string, KeyValuePair<string, string>> KvpWStrKvpVal { get; set; }
+ public KeyValuePair<string, KeyValuePair<string, object>> KvpWObjKvpVal { get; set; }
+ public KeyValuePair<string, KeyValuePair<string, SimpleClassWithKeyValuePairs>> KvpWClassKvpVal { get; set; }
+ }
}
}
using System.Globalization;
using Xunit;
-using Newtonsoft.Json;
namespace System.Text.Json.Tests
{