Reputation: 35
I am trying to figure out how to use a custom JsonConverter as an Attribute. The problem is that I cannot figure out how to get the FOO object within the converter.
Example
[Newtonsoft.Json.JsonConverter(typeof(FOOConverter))]
public interface IFOO
{
...
}
public class FOOConverter : Newtonsoft.Json.JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jobj = serializer.Deserialize<JObject>(reader);
...
var foo = jobj.ToObject<IFOO>() // Calls the converter again?
}
}
The .ToObject() will run the converter again and cause a stack overflow, which makes sense since it looks at the attribute, but how can I get the IFOO object then?
Edit: The WriteJson will be simular, but with JObject.FromObject(value);
The usage needs to be flexible, for ex: some properties might be encrypted/encrypted during serialization, other times, there may be property values that needs to be cached. To think of a few use cases.
Upvotes: 0
Views: 15219
Reputation: 48
JSON classes:
[KnownType(typeof(B))]
public class A
{
public string Name { get; set; }
}
public class B : A
{
public string LastName { get; set; }
}
Converter code:
public class KnownTypeConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return System.Attribute.GetCustomAttributes(objectType).Any(v => v is KnownTypeAttribute);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
System.Attribute[] attrs = System.Attribute.GetCustomAttributes(objectType); // Reflection.
// Displaying output.
foreach (System.Attribute attr in attrs)
{
if (attr is KnownTypeAttribute)
{
KnownTypeAttribute k = (KnownTypeAttribute) attr;
var props = k.Type.GetProperties();
bool found = true;
foreach (var f in jObject)
{
if (!props.Any(z => z.Name == f.Key))
{
found = false;
break;
}
}
if (found)
{
var target = Activator.CreateInstance(k.Type);
serializer.Populate(jObject.CreateReader(),target);
return target;
}
}
}
throw new ObjectNotFoundException();
// Populate the object properties
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Usage:
var ret = JsonConvert.DeserializeObject<A>(json, new KnownTypeConverter());
Upvotes: 2