0

I am working to create a JsonConverter and a ContractResolver that I can use to manage property and type serialization without using NewtonSoft attributes.

p.s., I am surprised these features are not already created somewhere

I've created a Contract Resolver that I think will work for the serialization step. But am stuck getting a converter that will work for deserialization. I can't seem to get the values from jProperty or JToken

internal class JsonPropertyConverter : JsonConverter
{
    private readonly Dictionary<string, string> _propertyMappings = new Dictionary<string, string>();

    // allows caller to specify name mappings
    public void RenameProperty(string oldName, string newName)
    {
        if (_propertyMappings.ContainsKey(oldName)) return;
        _propertyMappings.Add(oldName, newName);
    }

    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

    public override bool CanConvert(Type objectType)
    {
        return objectType.GetTypeInfo().IsClass;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        string clrName;
        string jsonName;
        PropertyInfo currentProp = null;

        // create a blank instance to set the values on
        object instance = Activator.CreateInstance(objectType);

        // get the properties from the object to be filled
        IEnumerable<PropertyInfo> props = objectType.GetTypeInfo().DeclaredProperties.ToList();

        JObject jObj = JObject.Load(reader);
        List<JProperty> jProperties = jObj.Properties().ToList();

        foreach (JProperty jp in jProperties)
        {
            // set the json and clr names
            jsonName = jp.Name;
            clrName = jp.Name;
            if (_propertyMappings.ContainsValue(jsonName)) clrName = _propertyMappings.GeyKeyFromValue(jsonName);

            // get the property
            PropertyInfo prop = props.FirstOrDefault(pi => pi.CanWrite && pi.Name == clrName);
            JToken tok = jObj.GetValue(jsonName);

            // this is where I am stuck

            // prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));                
        }
        return instance;
    }

    // was running into a recursive call to jp.Value.ToObject(prop.PropertyType, serializer) that threw errors when the type was a string
    private bool RequiresSeriailzation(Type t)
    {
        if (t.FullName == typeof(string).FullName) return false;
        if (t.GetTypeInfo().IsValueType) return false;
        return true;
    }
}

During serialization

clrProp: Nickname => jsonProp: nick_name (this is working in the ContractResolver)

During Deserialization

jsonProp: nick_name => clrProp: Nickname (the class above)

p.s. - can we just use the converter for both directions?

Jens Bright
  • 33
  • 1
  • 4
  • 1
    I don't understand why you need this converter. If you have a contract resolver to do the property name mapping, that should work for both serialization and deserialization. What you are trying to do sounds similar to [Json.NET deserialize or serialize json string and map properties to different property names defined at runtime](https://stackoverflow.com/q/38111298/10263). – Brian Rogers Sep 26 '19 at 23:21
  • It looks like the ContractResolver can only serialize things. It has a CreatPropertymethod, but no ReadProperty method. – Jens Bright Sep 27 '19 at 01:04
  • `CreateProperty` is called both when serializing and deserializing. Did you try it? Here is a round-trip demo which renames properties going each way: https://dotnetfiddle.net/EJOLoP – Brian Rogers Sep 27 '19 at 05:18
  • You are correct sir. It is not intuitive to me that the ContractResolver would do that as well, but it does. Thanks for your help - problem solved. – Jens Bright Sep 27 '19 at 17:49

0 Answers0