0

I have taken the code from this example and changed a few things:

  1. remove the custom constructor and hardcode the CanConvert type.
  2. removed the converter from the calls JsonConvert.SerializeObject() and JsonConvert.DeserializeObject()
  3. added a JsonConverter attribute to the Employee type

So I ended up with this console app:

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Testapp
{
    class Program
    {
        static void Main(string[] args)
        {
            Employee employee = new Employee
            {
                FirstName = "James",
                Roles = new List<string> {"Admin"}
            };

            string json = JsonConvert.SerializeObject(employee, Formatting.Indented);

            Console.WriteLine(json);

            Employee newEmployee = JsonConvert.DeserializeObject<Employee>(json);

            Console.WriteLine(newEmployee.FirstName);
        }
    }

    [JsonConverter(typeof(KeysJsonConverter))]
    public class Employee
    {
        public string        FirstName { get; set; }
        public IList<string> Roles     { get; set; }
    }

    public class KeysJsonConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            JToken t = JToken.FromObject(value);

            if (t.Type != JTokenType.Object)
            {
                t.WriteTo(writer);
            }
            else
            {
                JObject o = (JObject)t;
                IList<string> propertyNames = o.Properties().Select(p => p.Name).ToList();

                o.AddFirst(new JProperty("Keys", new JArray(propertyNames)));

                o.WriteTo(writer);
            }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
        }

        public override bool CanRead
        {
            get { return false; }
        }

        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Employee);
        }
    }
}

Unfortunately the use of the attribute instead of explicitly specifying the converter when serializing and de-serializing has a side effect: The assignment JToken t = JToken.FromObject(value); now causes WriteJson() to be called recursively, resulting in a stack overflow!

It would really be nice to use the attribute rather than specifying converters everywhere the items are serialized/deserialized.

I am trying to add some generic type info while serializing/deserializing an interface, and I would like to reuse the default behavior of serialization for the most part. Is there any alternative way to do so without calling JToken.FromObject() or anything else that would cause the recursion loop?

Already tried calling base.WriteJson() on JsonConverter but it is an abstract method.

Louis Somers
  • 2,560
  • 3
  • 27
  • 57
  • 1
    Take a look at [JSON.Net throws StackOverflowException when using `[JsonConvert()]`](https://stackoverflow.com/q/29719509/3744182). In fact I think this is a duplicate, agree? – dbc Dec 18 '20 at 02:31
  • 1
    I did not find that one, so yes mine is a duplicate. Glad to find there are some answers as well, thanks! – Louis Somers Dec 21 '20 at 00:43
  • You're welcome, glad to help. – dbc Dec 21 '20 at 00:47

0 Answers0