Skip to content

Commit

Permalink
Add MissingMemberHandling to JsonObjectAttribute (#2050)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK authored Apr 21, 2019
1 parent a088299 commit b34a3cc
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Tests.TestObjects;
#if DNXCORE50
using Xunit;
Expand Down Expand Up @@ -154,6 +155,20 @@ public void MissingJson()
});
}

[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; }
Expand Down Expand Up @@ -215,5 +230,46 @@ public void MissingMemberHandling_InnerObject()
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.");
}
}
}
13 changes: 12 additions & 1 deletion Src/Newtonsoft.Json/JsonObjectAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -50,6 +51,16 @@ public MemberSerialization MemberSerialization
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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ protected virtual JsonObjectContract CreateObjectContract(Type objectType)
{
contract.ItemRequired = attribute._itemRequired;
contract.ItemNullValueHandling = attribute._itemNullValueHandling;
contract.MissingMemberHandling = attribute._missingMemberHandling;

if (attribute.NamingStrategyType != null)
{
Expand Down
6 changes: 6 additions & 0 deletions Src/Newtonsoft.Json/Serialization/JsonObjectContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public class JsonObjectContract : JsonContainerContract
/// <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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2223,7 +2223,7 @@ private List<CreatorPropertyContext> ResolvePropertyAndCreatorValues(JsonObjectC
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));
}
Expand Down Expand Up @@ -2342,7 +2342,7 @@ private object PopulateObject(object newObject, JsonReader reader, JsonObjectCon
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));
}
Expand Down

0 comments on commit b34a3cc

Please sign in to comment.