Add MissingMemberHandling to JsonObjectAttribute (#2050)

This commit is contained in:
James Newton-King
2019-04-21 14:40:36 +12:00
committed by GitHub
parent a088299eee
commit b34a3ccca7
5 changed files with 77 additions and 3 deletions
@@ -27,6 +27,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Tests.TestObjects;
#if DNXCORE50
using Xunit;
@@ -154,6 +155,20 @@ namespace Newtonsoft.Json.Tests.Serialization
});
}
[Test]
public void MissingErrorAttribute()
{
string json = @"{""Missing"":1}";
ExceptionAssert.Throws<JsonSerializationException>(() => { JsonConvert.DeserializeObject<NameWithMissingError>(json); }, "Could not find member 'Missing' on object of type 'NameWithMissingError'. Path 'Missing', line 1, position 11.");
}
[JsonObject(MissingMemberHandling = MissingMemberHandling.Error)]
public class NameWithMissingError
{
public string First { get; set; }
}
public class Name
{
public string First { get; set; }
@@ -215,5 +230,46 @@ namespace Newtonsoft.Json.Tests.Serialization
Assert.AreEqual(1, errors.Count);
Assert.AreEqual("Could not find member 'firstERROR' on object of type 'Name'. Path 'name.firstERROR', line 1, position 20.", errors[0]);
}
[JsonObject(MissingMemberHandling = MissingMemberHandling.Ignore)]
public class SimpleExtendableObject
{
[JsonExtensionData]
public IDictionary<string, object> Data { get; } = new Dictionary<string, object>();
}
public class ObjectWithExtendableChild
{
public SimpleExtendableObject Data;
}
[Test]
public void TestMissingMemberHandlingForDirectObjects()
{
string json = @"{""extensionData1"": [1,2,3]}";
SimpleExtendableObject e2 = JsonConvert.DeserializeObject<SimpleExtendableObject>(json, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error });
JArray o1 = (JArray)e2.Data["extensionData1"];
Assert.AreEqual(JTokenType.Array, o1.Type);
}
[Test]
public void TestMissingMemberHandlingForChildObjects()
{
string json = @"{""Data"":{""extensionData1"": [1,2,3]}}";
ObjectWithExtendableChild e3 = JsonConvert.DeserializeObject<ObjectWithExtendableChild>(json, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error });
JArray o1 = (JArray)e3.Data.Data["extensionData1"];
Assert.AreEqual(JTokenType.Array, o1.Type);
}
[Test]
public void TestMissingMemberHandlingForChildObjectsWithInvalidData()
{
string json = @"{""InvalidData"":{""extensionData1"": [1,2,3]}}";
ExceptionAssert.Throws<JsonSerializationException>(() =>
{
JsonConvert.DeserializeObject<ObjectWithExtendableChild>(json, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error });
}, "Could not find member 'InvalidData' on object of type 'ObjectWithExtendableChild'. Path 'InvalidData', line 1, position 15.");
}
}
}
+12 -1
View File
@@ -34,7 +34,8 @@ namespace Newtonsoft.Json
public sealed class JsonObjectAttribute : JsonContainerAttribute
{
private MemberSerialization _memberSerialization = MemberSerialization.OptOut;
internal MissingMemberHandling? _missingMemberHandling;
// yuck. can't set nullable properties on an attribute in C#
// have to use this approach to get an unset default state
internal Required? _itemRequired;
@@ -50,6 +51,16 @@ namespace Newtonsoft.Json
set => _memberSerialization = value;
}
/// <summary>
/// Gets or sets the missing member handling used when deserializing this object.
/// </summary>
/// <value>The missing member handling.</value>
public MissingMemberHandling MissingMemberHandling
{
get => _missingMemberHandling ?? default;
set => _missingMemberHandling = value;
}
/// <summary>
/// Gets or sets how the object's properties with null values are handled during serialization and deserialization.
/// </summary>
@@ -356,6 +356,7 @@ namespace Newtonsoft.Json.Serialization
{
contract.ItemRequired = attribute._itemRequired;
contract.ItemNullValueHandling = attribute._itemNullValueHandling;
contract.MissingMemberHandling = attribute._missingMemberHandling;
if (attribute.NamingStrategyType != null)
{
@@ -44,6 +44,12 @@ namespace Newtonsoft.Json.Serialization
/// <value>The member object serialization.</value>
public MemberSerialization MemberSerialization { get; set; }
/// <summary>
/// Gets or sets the missing member handling used when deserializing this object.
/// </summary>
/// <value>The missing member handling.</value>
public MissingMemberHandling? MissingMemberHandling { get; set; }
/// <summary>
/// Gets or sets a value that indicates whether the object's properties are required.
/// </summary>
@@ -2223,7 +2223,7 @@ namespace Newtonsoft.Json.Serialization
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}.".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null);
}
if (Serializer._missingMemberHandling == MissingMemberHandling.Error)
if ((contract.MissingMemberHandling ?? Serializer._missingMemberHandling) == MissingMemberHandling.Error)
{
throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name));
}
@@ -2342,7 +2342,7 @@ namespace Newtonsoft.Json.Serialization
TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}".FormatWith(CultureInfo.InvariantCulture, propertyName, contract.UnderlyingType)), null);
}
if (Serializer._missingMemberHandling == MissingMemberHandling.Error)
if ((contract.MissingMemberHandling ?? Serializer._missingMemberHandling) == MissingMemberHandling.Error)
{
throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, propertyName, contract.UnderlyingType.Name));
}