3

This is following an example based on code from this question (albeit for Serialization). Is it possible to override all Required.Always to be Required.Default (i.e. "optional"), and allow me to deserialize an object regardless of the "required" attributes?

    public class OverrideToDefaultContractResolver : DefaultContractResolver
    {
        protected override JsonObjectContract CreateObjectContract(Type objectType)
        {
            var contract = base.CreateObjectContract(objectType);
            contract.ItemRequired = Required.Default;
            return contract;
        }
    }

    public class MyClass
    {
        [JsonProperty("MyRequiredProperty", Required = Required.Always, NullValueHandling = NullValueHandling.Ignore)]
        public string MyRequiredProperty { get; set; }
    }

    public static void Test()
    {
        var settings = new JsonSerializerSettings { ContractResolver = new OverrideToDefaultContractResolver() };
        MyClass obj = JsonConvert.DeserializeObject<MyClass>(@"{""Nope"": ""Hi there""}", settings);
        Console.WriteLine($"Json property: {obj.MyRequiredProperty}");
    }
noelicus
  • 14,468
  • 3
  • 92
  • 111

1 Answers1

6

In general, with Json.NET the precedence of settings is:

  1. An attribute applied to a property or parameter.
  2. An attribute applied to an object.
  3. Serialization settings applied to the serializer.

Your OverrideToDefaultContractResolver cancels Required attributes applied at the object level, but not at the individual property level. As the latter take precedence over the former, they need to be cancelled also. The following contract resolver does the job:

public class OverrideToDefaultContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(System.Reflection.MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        property.Required = Required.Default;
        return property;
    }

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var contract = base.CreateObjectContract(objectType);
        contract.ItemRequired = Required.Default;
        return contract;
    }
    
    protected override JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo)
    {
        var property = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo);
        property.Required = Required.Default;
        return property;
    }
}

Notes:

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Thanks for that, super helpful ;) One thing that's left me puzzled though - your original answer was to a question about Properties, so that doesn't actually work either. This is the real answer :) ... or does "property" mean something else in F# land? – noelicus Sep 10 '20 at 11:40
  • @noelicus - that question wasn't asking how to override anything. It was just asking how to apply `Required = Required.Always` by default to prevent deserialized members from coming back `null`, without having to set it manually for each member (field or property). The answer does that by setting `JsonObjectContract.ItemRequired` on the contract for each object, which was sufficient. – dbc Sep 10 '20 at 15:59
  • @noelicus but [`JsonProperty.IsRequiredSpecified`](https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/JsonProperty.cs#L208) was only recently introduced, in [12.0.2](https://github.com/JamesNK/Newtonsoft.Json/releases/tag/12.0.2), so at the time I had no easy way to tell whether the user had already explicitly marked the field or property as required or not, and so no way of setting `JsonProperty.Required` only if not already set by the user. – dbc Sep 10 '20 at 16:09
  • Thanks for clarifying the difference. FWIW I think they were asking to override. The first line is "how do I make ALL properties required upon deserialization". But I've learned stuff and so I thank you ;) – noelicus Sep 11 '20 at 08:56