if (enumerable == null)
{
// Write a null object or enumerable.
- state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, writeNull : true);
+ state.Current.WriteObjectOrArrayStart(ClassType.Dictionary, writer, writeNull: true);
return true;
}
if (state.Current.Enumerator.MoveNext())
{
- // Handle DataExtension.
- if (ReferenceEquals(jsonPropertyInfo, state.Current.JsonClassInfo.DataExtensionProperty))
+ // Check for polymorphism.
+ if (elementClassInfo.ClassType == ClassType.Unknown)
{
- WriteExtensionData(writer, ref state.Current);
+ object currentValue = ((IDictionaryEnumerator)state.Current.Enumerator).Entry.Value;
+ GetRuntimeClassInfo(currentValue, ref elementClassInfo, options);
+ }
+
+ if (elementClassInfo.ClassType == ClassType.Value)
+ {
+ elementClassInfo.GetPolicyProperty().WriteDictionary(ref state.Current, writer);
+ }
+ else if (state.Current.Enumerator.Current == null)
+ {
+ writer.WriteNull(jsonPropertyInfo.Name);
}
else
{
- // Check for polymorphism.
- if (elementClassInfo.ClassType == ClassType.Unknown)
- {
- object currentValue = ((IDictionaryEnumerator)state.Current.Enumerator).Entry.Value;
- GetRuntimeClassInfo(currentValue, ref elementClassInfo, options);
- }
-
- if (elementClassInfo.ClassType == ClassType.Value)
- {
- elementClassInfo.GetPolicyProperty().WriteDictionary(ref state.Current, writer);
- }
- else if (state.Current.Enumerator.Current == null)
- {
- writer.WriteNull(jsonPropertyInfo.Name);
- }
- else
- {
- // An object or another enumerator requires a new stack frame.
- var enumerator = (IDictionaryEnumerator)state.Current.Enumerator;
- object value = enumerator.Value;
- state.Push(elementClassInfo, value);
- state.Current.KeyName = (string)enumerator.Key;
- }
+ // An object or another enumerator requires a new stack frame.
+ var enumerator = (IDictionaryEnumerator)state.Current.Enumerator;
+ object value = enumerator.Value;
+ state.Push(elementClassInfo, value);
+ state.Current.KeyName = (string)enumerator.Key;
}
return false;
converter.Write(escapedKey, value, writer);
}
}
-
- private static void WriteExtensionData(Utf8JsonWriter writer, ref WriteStackFrame frame)
- {
- DictionaryEntry entry = ((IDictionaryEnumerator)frame.Enumerator).Entry;
- if (entry.Value is JsonElement element)
- {
- Debug.Assert(entry.Key is string);
-
- string propertyName = (string)entry.Key;
- element.WriteProperty(propertyName, writer);
- }
- else
- {
- ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(frame.JsonClassInfo, entry.Value.GetType());
- }
- }
}
}
}
[Fact]
- public static void InvalidExtensionValue()
+ public static void ExtensionPropertyObjectValue_Empty()
+ {
+ // Baseline
+ ClassWithExtensionPropertyAlreadyInstantiated obj = JsonSerializer.Parse<ClassWithExtensionPropertyAlreadyInstantiated>(@"{}");
+ Assert.Equal(@"{""MyOverflow"":{}}", JsonSerializer.ToString(obj));
+ }
+
+ [Fact]
+ public static void ExtensionPropertyObjectValue()
{
// Baseline
ClassWithExtensionPropertyAlreadyInstantiated obj = JsonSerializer.Parse<ClassWithExtensionPropertyAlreadyInstantiated>(@"{}");
obj.MyOverflow.Add("test", new object());
+ obj.MyOverflow.Add("test1", 1);
- try
- {
- JsonSerializer.ToString(obj);
- Assert.True(false, "InvalidOperationException should have thrown.");
- }
- catch (InvalidOperationException e)
- {
- // Verify the exception contains the property name and invalid type.
- Assert.Contains("ClassWithExtensionPropertyAlreadyInstantiated.MyOverflow", e.Message);
- Assert.Contains("System.Object", e.Message);
- }
+ Assert.Equal(@"{""MyOverflow"":{""test"":{},""test1"":1}}", JsonSerializer.ToString(obj));
+ }
+
+ [Fact]
+ public static void ExtensionPropertyObjectValue_RoundTrip()
+ {
+ // Baseline
+ ClassWithExtensionPropertyAlreadyInstantiated obj = JsonSerializer.Parse<ClassWithExtensionPropertyAlreadyInstantiated>(@"{}");
+ obj.MyOverflow.Add("test", new object());
+ obj.MyOverflow.Add("test1", 1);
+ obj.MyOverflow.Add("test2", "text");
+ obj.MyOverflow.Add("test3", new DummyObj() { Prop = "ObjectProp" });
+ obj.MyOverflow.Add("test4", new DummyStruct() { Prop = "StructProp" });
+ obj.MyOverflow.Add("test5", new Dictionary<string, object>() { { "Key", "Value" }, { "Key1", "Value1" }, });
+
+ ClassWithExtensionPropertyAlreadyInstantiated roundTripObj = JsonSerializer.Parse<ClassWithExtensionPropertyAlreadyInstantiated>(JsonSerializer.ToString(obj));
+
+ Assert.Equal(6, roundTripObj.MyOverflow.Count);
+
+ Assert.IsType<JsonElement>(roundTripObj.MyOverflow["test"]);
+ Assert.IsType<JsonElement>(roundTripObj.MyOverflow["test1"]);
+ Assert.IsType<JsonElement>(roundTripObj.MyOverflow["test2"]);
+ Assert.IsType<JsonElement>(roundTripObj.MyOverflow["test3"]);
+
+ Assert.Equal(JsonValueType.Object, ((JsonElement)roundTripObj.MyOverflow["test"]).Type);
+
+ Assert.Equal(JsonValueType.Number, ((JsonElement)roundTripObj.MyOverflow["test1"]).Type);
+ Assert.Equal(1, ((JsonElement)roundTripObj.MyOverflow["test1"]).GetInt32());
+ Assert.Equal(1, ((JsonElement)roundTripObj.MyOverflow["test1"]).GetInt64());
+
+ Assert.Equal(JsonValueType.String, ((JsonElement)roundTripObj.MyOverflow["test2"]).Type);
+ Assert.Equal("text", ((JsonElement)roundTripObj.MyOverflow["test2"]).GetString());
+
+ Assert.Equal(JsonValueType.Object, ((JsonElement)roundTripObj.MyOverflow["test3"]).Type);
+ Assert.Equal("ObjectProp", ((JsonElement)roundTripObj.MyOverflow["test3"]).GetProperty("Prop").GetString());
+
+ Assert.Equal(JsonValueType.Object, ((JsonElement)roundTripObj.MyOverflow["test4"]).Type);
+ Assert.Equal("StructProp", ((JsonElement)roundTripObj.MyOverflow["test4"]).GetProperty("Prop").GetString());
+
+ Assert.Equal(JsonValueType.Object, ((JsonElement)roundTripObj.MyOverflow["test5"]).Type);
+ Assert.Equal("Value", ((JsonElement)roundTripObj.MyOverflow["test5"]).GetProperty("Key").GetString());
+ Assert.Equal("Value1", ((JsonElement)roundTripObj.MyOverflow["test5"]).GetProperty("Key1").GetString());
}
[Fact]
Assert.Equal(3, child.MyOverflow["MyIntMissingChild"].GetInt32());
}
+ [Fact]
+ public static void ExtensionProperty_InvalidDictionary()
+ {
+ ClassWithInvalidExtensionPropertyStringString obj1 = new ClassWithInvalidExtensionPropertyStringString();
+ Assert.Throws<InvalidOperationException>(() => JsonSerializer.ToString(obj1));
+
+ ClassWithInvalidExtensionPropertyObjectString obj2 = new ClassWithInvalidExtensionPropertyObjectString();
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.ToString(obj2));
+ }
+
+ public class DummyObj
+ {
+ public string Prop { get; set; }
+ }
+
+ public struct DummyStruct
+ {
+ public string Prop { get; set; }
+ }
+
public class ClassWithExtensionPropertyAlreadyInstantiated
{
public ClassWithExtensionPropertyAlreadyInstantiated()
public Dictionary<string, int> MyOverflow { get; set; }
}
+ public class ClassWithInvalidExtensionPropertyStringString
+ {
+ [JsonExtensionData]
+ public Dictionary<string, string> MyOverflow { get; set; }
+ }
+
+ public class ClassWithInvalidExtensionPropertyObjectString
+ {
+ [JsonExtensionData]
+ public Dictionary<DummyObj, string> MyOverflow { get; set; }
+ }
+
public class ClassWithTwoExtensionPropertys
{
[JsonExtensionData]