0

I need to have some parts of an object serialize default values and some not.

In the following post, I understand how to do this according to types: Json.NET: How to make DefaultValueHandling only apply to certain types?

But this solution only applies to types and won't be recursive.

Expected behaviour:

{
  {
    "keepDefaults" : {
      "prop1" : true,
      "prop2" : false,
    },
    "ignoreDefaults" : {
      "prop3" : true,
      "prop4" : false,
    }
}

When reserialized:

  {
    "keepDefaults" : {
      "prop1" : true,
      "prop2" : false
    },
    "ignoreDefaults" : {
      "prop3" : true
    }
}

Is there something I could override in the ContractProvider or an attribute I could add to the members or classes to select the DefaultValueHandling?

sinsedrix
  • 4,336
  • 4
  • 29
  • 53
  • Does this answer your question? [Default value for missing properties with JSON.net](https://stackoverflow.com/questions/29611445/default-value-for-missing-properties-with-json-net) – Sinatr May 07 '21 at 09:44
  • @Sinatr not really, as I'll need to add the JsonProperty attribute to each attribute of the ignoreDefaults class or keepDefaults class – sinsedrix May 07 '21 at 11:03

1 Answers1

0

Inspired by the solution from @dbc in the quoted post, I adapted it to apply DefaultValueHandling to a whole class.

public class DefaultValueContractResolver : DefaultContractResolver
{
    readonly Dictionary<Type, DefaultValueHandling> _overrides = new Dictionary<Type, DefaultValueHandling>();

    public DefaultValueContractResolver(IEnumerable<KeyValuePair<Type, DefaultValueHandling>> overrides = null) : base()
    {
        _overrides = overrides?.ToDictionary(p => p.Key, p => p.Value) ?? _overrides;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        if (property.DefaultValueHandling == null)
        {
            if(_overrides.TryGetValue(property.DeclaringType, out DefaultValueHandling handling))
                property.DefaultValueHandling = handling;
        }
    
        return property;
    }
}

Then I can serialize this way:

var keepDefaults = new KeepDefaults
{
    Prop1 = true,
    Prop2 = false
};

var ignoreDefaults = new IgnoreDefaults
{
    Prop3 = true,
    Prop4 = false
};

var jsSettings = new JsonSerializerSettings
{
    //DefaultValueHandling = DefaultValueHandling.Populate,
    ContractResolver = new DefaultValueContractResolver(
        new Dictionary<Type, DefaultValueHandling>
        { 
            { typeof(IgnoreDefaults), DefaultValueHandling.Ignore } ,
            { typeof(KeepDefaults), DefaultValueHandling.Populate } 
        }),
    Converters = new List<JsonConverter> { new Newtonsoft.Json.Converters.StringEnumConverter() },
    Formatting = Formatting.Indented
};



var json1 = JsonConvert.SerializeObject(keepDefaults, settings);
var json2 = JsonConvert.SerializeObject(ignoreDefaults, settings);

And voila, I get the expected result.

sinsedrix
  • 4,336
  • 4
  • 29
  • 53