title: JsonConverter applied to class causes JsonConverter applied to property to be ignored
body: <p>I defined two <code>JsonConverter</code> classes. One I attach to the class, the other I attach to a property of that class. If I only attach the converter to the property, it works fine. As soon as I attach a separate converter to the class, it ignores the one attached to the property. <strong>How can I make it not skip such JsonConverterAttributes?</strong></p>
  
  <p>Here is the class-level converter (which I adapted from this: <a href="https://stackoverflow.com/questions/19792274/alternate-property-name-while-deserializing">Alternate property name while deserializing</a>). I attach it to the test class like so:</p>
  
  <pre><code>[JsonConverter(typeof(FuzzyMatchingJsonConverter&lt;JsonTestData&gt;))]
  </code></pre>
  
  <p>Then here is the <code>FuzzyMatchingJsonConverter</code> itself:</p>
  
  <pre><code>using Newtonsoft.Json;
  using Newtonsoft.Json.Linq;
  using Optimizer.models;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  
  namespace Optimizer.Serialization
  {
      /// &lt;summary&gt;
      /// Permit the property names in the Json to be deserialized to have spelling variations and not exactly match the
      /// property name in the object. Thus puntuation, capitalization and whitespace differences can be ignored.
      /// 
      /// NOTE: As implemented, this can only deserialize objects from a string, not serialize from objects to a string.
      /// &lt;/summary&gt;
      /// &lt;seealso cref="https://stackoverflow.com/questions/19792274/alternate-property-name-while-deserializing"/&gt;
      public class FuzzyMatchingJsonConverter&lt;T&gt; : JsonConverter
      {
          /// &lt;summary&gt;
          /// Map the json property names to the object properties.
          /// &lt;/summary&gt;
          private static DictionaryToObjectMapper&lt;T&gt; Mapper { get; set; } = null;
  
          private static object SyncToken { get; set; } = new object();
  
          static void InitMapper(IEnumerable&lt;string&gt; jsonPropertyNames)
          {
              if (Mapper == null)
                  lock(SyncToken)
                  {
                      if (Mapper == null)
                      {
                          Mapper = new DictionaryToObjectMapper&lt;T&gt;(
                              jsonPropertyNames,
                              EnumHelper.StandardAbbreviations,
                              ModelBase.ACCEPTABLE_RELATIVE_EDIT_DISTANCE,
                              ModelBase.ABBREVIATION_SCORE
                          );
                      }
                  }
              else
              {
                  lock(SyncToken)
                  {
                      // Incremental mapping of additional attributes not seen the first time for the second and subsequent objects.
                      // (Some records may have more attributes than others.)
                      foreach (var jsonPropertyName in jsonPropertyNames)
                      {
                          if (!Mapper.CanMatchKeyToProperty(jsonPropertyName))
                              throw new MatchingAttributeNotFoundException(jsonPropertyName, typeof(T).Name);
                      }
                  }
              }
          }
  
          public override bool CanConvert(Type objectType) =&gt; objectType.IsClass;
  
          /// &lt;summary&gt;
          /// If false, this class cannot serialize (write) objects.
          /// &lt;/summary&gt;
          public override bool CanWrite { get =&gt; false; }
  
          /// &lt;summary&gt;
          /// Call the default constructor for the object and then set all its properties,
          /// matching the json property names to the object attribute names.
          /// &lt;/summary&gt;
          /// &lt;param name="reader"&gt;&lt;/param&gt;
          /// &lt;param name="objectType"&gt;This should match the type parameter T.&lt;/param&gt;
          /// &lt;param name="existingValue"&gt;&lt;/param&gt;
          /// &lt;param name="serializer"&gt;&lt;/param&gt;
          /// &lt;returns&gt;The deserialized object of type T.&lt;/returns&gt;
          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
          {
              // Note: This assumes that there is a default (parameter-less) constructor and not a constructor tagged with the JsonCOnstructorAttribute.
              // It would be better if it supported those cases.
              object instance = objectType.GetConstructor(Type.EmptyTypes).Invoke(null);
              JObject jo = JObject.Load(reader);
              InitMapper(jo.Properties().Select(jp =&gt; jp.Name));
  
              foreach (JProperty jp in jo.Properties())
              {
                  var prop = Mapper.KeyToProperty[jp.Name];
                  prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
              }
              return instance;
          }
  
          public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
          {
              throw new NotImplementedException();
          }
      }
  }
  </code></pre>
  
  <p>Do not get bogged down with <code>DictionaryToObjectMapper</code> (it is proprietary, but uses fuzzy matching logic to deal with spelling variations). Here is the next <code>JsonConverter</code>, that will change <code>"Y"</code>, <code>"Yes"</code>, <code>"T"</code>, <code>"True"</code>, etc into Boolean true values. I adapted it from this source: <a href="https://gist.github.com/randyburden/5924981" rel="nofollow noreferrer">https://gist.github.com/randyburden/5924981</a></p>
  
  <pre><code>using System;
  using System.Linq;
  using Newtonsoft.Json;
  using Newtonsoft.Json.Linq;
  
  namespace Optimizer.Serialization
  {
      /// &lt;summary&gt;
      /// Handles converting JSON string values into a C# boolean data type.
      /// &lt;/summary&gt;
      /// &lt;see cref="https://gist.github.com/randyburden/5924981"/&gt;
      public class BooleanJsonConverter : JsonConverter
      {
          private static readonly string[] Truthy = new[] { "t", "true", "y", "yes", "1" };
          private static readonly string[] Falsey = new[] { "f", "false", "n", "no", "0" };
  
          /// &lt;summary&gt;
          /// Parse a Boolean from a string where alternative spellings are permitted, such as 1, t, T, true or True for true.
          /// 
          /// All values that are not true are considered false, so no parse error will occur.
          /// &lt;/summary&gt;
          public static Func&lt;object, bool&gt; ParseBoolean
              = (obj) =&gt; { var b = (obj ?? "").ToString().ToLower().Trim(); return Truthy.Any(t =&gt; t.Equals(b)); };
  
          public static bool ParseBooleanWithValidation(object obj)
          {
              var b = (obj ?? "").ToString().ToLower().Trim();
              if (Truthy.Any(t =&gt; t.Equals(b)))
                  return true;
              if (Falsey.Any(t =&gt; t.Equals(b)))
                  return false;
              throw new ArgumentException($"Unable to convert ${obj}into a Boolean attribute.");
          }
  
          #region Overrides of JsonConverter
  
          /// &lt;summary&gt;
          /// Determines whether this instance can convert the specified object type.
          /// &lt;/summary&gt;
          /// &lt;param name="objectType"&gt;Type of the object.&lt;/param&gt;
          /// &lt;returns&gt;
          /// &lt;c&gt;true&lt;/c&gt; if this instance can convert the specified object type; otherwise, &lt;c&gt;false&lt;/c&gt;.
          /// &lt;/returns&gt;
          public override bool CanConvert(Type objectType)
          {
              // Handle only boolean types.
              return objectType == typeof(bool);
          }
  
          /// &lt;summary&gt;
          /// Reads the JSON representation of the object.
          /// &lt;/summary&gt;
          /// &lt;param name="reader"&gt;The &lt;see cref="T:Newtonsoft.Json.JsonReader"/&gt; to read from.&lt;/param&gt;
          /// &lt;param name="objectType"&gt;Type of the object.&lt;/param&gt;
          /// &lt;param name="existingValue"&gt;The existing value of object being read.&lt;/param&gt;
          /// &lt;param name="serializer"&gt;The calling serializer.&lt;/param&gt;
          /// &lt;returns&gt;
          /// The object value.
          /// &lt;/returns&gt;
          public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
              =&gt; ParseBooleanWithValidation(reader.Value);
  
  
          /// &lt;summary&gt;
          /// Specifies that this converter will not participate in writing results.
          /// &lt;/summary&gt;
          public override bool CanWrite { get { return false; } }
  
          /// &lt;summary&gt;
          /// Writes the JSON representation of the object.
          /// &lt;/summary&gt;
          /// &lt;param name="writer"&gt;The &lt;see cref="T:Newtonsoft.Json.JsonWriter"/&gt; to write to.&lt;/param&gt;&lt;param name="value"&gt;The value.&lt;/param&gt;&lt;param name="serializer"&gt;The calling serializer.&lt;/param&gt;
          public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
          {
              //TODO: Implement for serialization
              //throw new NotImplementedException("Serialization of Boolean");
              // I have no idea if this is correct:
              var b = (bool)value;
              JToken valueToken;
              valueToken = JToken.FromObject(b); 
              valueToken.WriteTo(writer);
          }
  
          #endregion Overrides of JsonConverter
      }
  }
  </code></pre>
  
  <p>And here is how I created the test class used in my unit tests:</p>
  
  <pre><code>[JsonConverter(typeof(FuzzyMatchingJsonConverter&lt;JsonTestData&gt;))]
  public class JsonTestData: IEquatable&lt;JsonTestData&gt;
  {
      public string TestId { get; set; }
      public double MinimumDistance { get; set; }
  
      [JsonConverter(typeof(BooleanJsonConverter))]
      public bool TaxIncluded { get; set; }
  
      [JsonConverter(typeof(BooleanJsonConverter))]
      public bool IsMetsFan { get; set; }
  
      [JsonConstructor]
      public JsonTestData()
      {
          TestId = null;
          MinimumDistance = double.NaN;
          TaxIncluded = false;
          IsMetsFan = false;
      }
  
      public JsonTestData(string testId, double minimumDistance, bool taxIncluded, bool isMetsFan)
      {
          TestId = testId;
          MinimumDistance = minimumDistance;
          TaxIncluded = taxIncluded;
          IsMetsFan = isMetsFan;
      }
  
      public override bool Equals(object obj) =&gt; Equals(obj as JsonTestData);
  
      public bool Equals(JsonTestData other)
      {
          if (other == null) return false;
          return ((TestId ?? "") == other.TestId)
              &amp;&amp; (MinimumDistance == other.MinimumDistance)
              &amp;&amp; (TaxIncluded == other.TaxIncluded)
              &amp;&amp; (IsMetsFan == other.IsMetsFan);
      }
  
      public override string ToString() =&gt; $"TestId: {TestId}, MinimumDistance: {MinimumDistance}, TaxIncluded: {TaxIncluded}, IsMetsFan: {IsMetsFan}";
  
      public override int GetHashCode()
      {
          return -1448189120 + EqualityComparer&lt;string&gt;.Default.GetHashCode(TestId);
      }
  }
  </code></pre>