facebook-csharp-sdk/simple-json

Support naming strategies to map JSON to POCO and back

Closed this issue · 3 comments

The GitHub API uses Ruby casing for its JSON property names. For example:

{"user_name": "haacked", "id": 123}

But I'd like to still use proper .NET naming conventions on my POCO objects.

public class User {
    public int Id { get; set; }
    public string UserName { get; set; }
}

I looked at what it would take to implement an IJsonSerializerStrategy by simply inheriting from PocoJsonSerializerStrategy. The problem is there doesn't seem to be an easy hook to map JSON property names to CLR property names and back. I'd pretty much have to fully reimplement PocoJsonSerializerStrategy.

I'd like to propose a simple mapping for property to field names and back that by default would be an identity (it's always the same). But implementers could replace this mapping without having to rewrite all of PocoJsonSerializerStrategy.

The main reason for us to have IJsonSerializerStrategy was to support this. But never landed up implementing in a clean way.

Definitely need to implement some variant of CanAdd found in DataContractJsonSerializer.

private static bool CanAdd(MemberInfo info, out string jsonKey)
{
jsonKey = null;
if (ReflectionUtils.GetAttribute(info, typeof(IgnoreDataMemberAttribute)) != null)
return false;
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)ReflectionUtils.GetAttribute(info, typeof(DataMemberAttribute));
if (dataMemberAttribute == null)
return false;
jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? info.Name : dataMemberAttribute.Name;
return true;
}

Currently the only way is to use. #define SIMPLE_JSON_DATACONTRACT

[DataContract]
public class User {
    [DataMember(Name="id")]
    public int Id { get; set; }

    [DataMember(Name="user_name")]
    public string UserName { get; set; }
}

A virtual method in PocoJsonSerializerStrategy would be good. Or this could even go in IJsonSerializerStrategy..

Something like this.

public virtual string MapKey(string key, IDictionary<string, object> json,object obj, IDictionary<string, MemberInfo> members) {
    // return null if not found.
    return ToRubyCasing(key);
}

Can get some ideas from RestSharp too. https://github.com/restsharp/RestSharp/blob/master/RestSharp/Deserializers/JsonDeserializer.cs

The RestSharp approach looks good. I always try to advocate composition over inheritance as a solution. The mapping is a separate concern and could be fine as a class or a simple Func.

Do you think this is worthwhile and something you'll get to this soon? If not, I can work on it tonight or tomorrow. But I'd love for you to review my other PR first since I'd like to base this work off that code. :)

might need to use delegates as we need to support .net 2.0

RestSharp actually does use SimpleJson internally (restsharp/RestSharp@f962354) so should be able to port it easily.

due to my cast in the hand typing with one hand is very difficult. you could work on a PR for it :)