I have taken the code from this example and changed a few things:
- remove the custom constructor and hardcode the
CanConvert
type. - removed the converter from the calls
JsonConvert.SerializeObject()
andJsonConvert.DeserializeObject()
- 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.