0
votes

I am using Json.NET (8.0.3) and I am trying to use the CamelCasePropertyNameContractResolver with JsonConvert.DeseralizeObject() so that I can read JSON with camel case properties. Here is an example of the JSON.

{ "name":"somename", "type":"sometype" }

Here is the class I am trying to deserialize to:

public class MyClass {
    public string Name { get; private set; }
    public string Type { get; private set; }
}

If I use JsonConvert.DeseralizeObject the Name and Type values are null because technically the class property names do not match the JSON property names. This was expected. If I add the JsonProperty attribute then it will deserialize correctly (also expected).

public class MyClass {
    [JsonProperty("name")]
    public string Name { get; private set; }
    [JsonProperty("type")]
    public string Type { get; private set; }
}

I do not want to put the JsonProperty attribute on all of the properties so I tried the CamelCasePropertyNameContractResolver.

JsonConvert.DefaultSettings = () => new JsonSerialierSettings {
    ContractResolver = new CamelCasePropertyNameContractResolver()
};

MyClass value = JsonConvert.DeserializeObject<MyClass>(json);

The Name and Type properties of the MyClass object are both null which was unexpected. If I make the setter public then it works correctly.

public class MyClass {
    public string Name { get; set; }
    public string Type { get; set; }
}

The obvious answer here is to just keep the setter public, but if I want/need to have the setter private, how can I get the CamelCasePropertyNameContractResolver to work with private setters? Am I doing something wrong, or is this a possible bug?

1

1 Answers

3
votes

You can do it by writing a custom ContractResolver

string json = @"{""name"":""somename"", ""type"":""sometype"" }";

var settings = new JsonSerializerSettings() { 
                         ContractResolver = new AllPropertiesContractResolver() };
var res = JsonConvert.DeserializeObject<MyClass>(json,settings);

public class MyClass
{
    public string Name { get; private set; }
    public string Type { get; private set; }
}

public class AllPropertiesContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var props = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
                    .Select(x => new Newtonsoft.Json.Serialization.JsonProperty()
                    {
                        PropertyName = x.Name,
                        PropertyType = x.PropertyType,
                        Readable = true,
                        ValueProvider = new AllPropertiesValueProvider(x),
                        Writable = true
                    })
                    .ToList();


        return props;
    }
}

public class AllPropertiesValueProvider : Newtonsoft.Json.Serialization.IValueProvider
{
    PropertyInfo _propertyInfo;

    public AllPropertiesValueProvider(PropertyInfo p)
    {
        _propertyInfo = p;
    }

    public object GetValue(object target)
    {
        return _propertyInfo.GetValue(target);  //Serialization
    }

    public void SetValue(object target, object value)
    {
        _propertyInfo.SetValue(target, value, null); //Deserialization
    }
}

BTW: If I use JsonConvert.DeseralizeObject the Name and Type values are null because technically the class property names do not match the JSON property names. is not correct. If your properties had public setters and getters, deserialization would ignore the cases when using default settings (this is what I use in this answer. My ContractResolver additionally includes private properties in deserialization process; that is all).....

See the other question I used the same ContractResolver: What am I doing wrong with JSON.NET's JsonConvert