mirror of
https://github.com/zoriya/octokit.net.git
synced 2025-12-20 14:15:12 +00:00
Add support for deserializing non-public members
But only ones with ParameterAttribute applied.
This commit is contained in:
@@ -96,15 +96,21 @@ namespace Octokit.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnencodesBase64Strings()
|
||||
public void DeserializesProtectedProperties()
|
||||
{
|
||||
const string json = "{\"name\":\"RmVycmlzIEJ1ZWxsZXI=\",\"description\":\"stuff\",\"content\":\"RGF5IG9mZg==\"}";
|
||||
|
||||
var someObject = new SimpleJsonSerializer().Deserialize<SomeObject>(json);
|
||||
const string json = "{\"content\":\"hello\"}";
|
||||
|
||||
Assert.Equal("Ferris Bueller", someObject.Name);
|
||||
Assert.Equal("Day off", someObject.Content);
|
||||
Assert.Equal("stuff", someObject.Description);
|
||||
var someObject = new SimpleJsonSerializer().Deserialize<AnotherObject>(json);
|
||||
|
||||
Assert.Equal("*hello*", someObject.Content);
|
||||
}
|
||||
|
||||
public class AnotherObject
|
||||
{
|
||||
[Parameter(Key = "content")]
|
||||
protected string EncodedContent { get; set; }
|
||||
|
||||
public string Content { get { return "*" + EncodedContent + "*"; } }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace Octokit
|
||||
var url = ApiUrls.RepositoryContent(owner, name, path);
|
||||
|
||||
return await ApiConnection.GetAll<RepositoryContent>(url);
|
||||
// return new List<RepositoryContent> { await ApiConnection.Get<RepositoryContent>(url) }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace Octokit
|
||||
CanWrite = propertyInfo.CanWrite;
|
||||
IsStatic = ReflectionUtils.GetGetterMethodInfo(propertyInfo).IsStatic;
|
||||
IsPublic = ReflectionUtils.GetGetterMethodInfo(propertyInfo).IsPublic;
|
||||
|
||||
CanDeserialize = (IsPublic || HasParameterAttribute) && !IsStatic && CanWrite;
|
||||
}
|
||||
|
||||
public PropertyOrField(FieldInfo fieldInfo) : this((MemberInfo)fieldInfo)
|
||||
@@ -29,6 +31,8 @@ namespace Octokit
|
||||
CanWrite = true;
|
||||
IsStatic = fieldInfo.IsStatic;
|
||||
IsPublic = fieldInfo.IsPublic;
|
||||
|
||||
CanDeserialize = (IsPublic || HasParameterAttribute) && !IsStatic && CanWrite && !fieldInfo.IsInitOnly;
|
||||
}
|
||||
|
||||
protected PropertyOrField(MemberInfo memberInfo)
|
||||
@@ -36,6 +40,7 @@ namespace Octokit
|
||||
MemberInfo = memberInfo;
|
||||
Base64Encoded = memberInfo.GetCustomAttribute<SerializeAsBase64Attribute>() != null;
|
||||
SerializeNull = memberInfo.GetCustomAttribute<SerializeNullAttribute>() != null;
|
||||
HasParameterAttribute = memberInfo.GetCustomAttribute<ParameterAttribute>() != null;
|
||||
}
|
||||
|
||||
public bool CanRead { get; private set; }
|
||||
@@ -50,6 +55,8 @@ namespace Octokit
|
||||
|
||||
public bool IsPublic { get; private set; }
|
||||
|
||||
public bool HasParameterAttribute { get; private set; }
|
||||
|
||||
public MemberInfo MemberInfo { get; private set; }
|
||||
|
||||
public object GetValue(object instance)
|
||||
@@ -75,5 +82,44 @@ namespace Octokit
|
||||
}
|
||||
throw new InvalidOperationException("Property and Field cannot both be null");
|
||||
}
|
||||
|
||||
public string JsonFieldName
|
||||
{
|
||||
get { return MemberInfo.GetJsonFieldName(); }
|
||||
}
|
||||
|
||||
public ReflectionUtils.SetDelegate SetDelegate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_propertyInfo != null)
|
||||
{
|
||||
return ReflectionUtils.GetSetMethod(_propertyInfo);
|
||||
}
|
||||
if (_fieldInfo != null)
|
||||
{
|
||||
return ReflectionUtils.GetSetMethod(_fieldInfo);
|
||||
}
|
||||
throw new InvalidOperationException("Property and Field cannot both be null");
|
||||
}
|
||||
}
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_propertyInfo != null)
|
||||
{
|
||||
return _propertyInfo.PropertyType;
|
||||
}
|
||||
if (_fieldInfo != null)
|
||||
{
|
||||
return _fieldInfo.FieldType;
|
||||
}
|
||||
throw new InvalidOperationException("Property and Field cannot both be null");
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanDeserialize { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Octokit.Internal;
|
||||
using Octokit.Reflection;
|
||||
|
||||
namespace Octokit
|
||||
{
|
||||
internal static class ReflectionExtensions
|
||||
{
|
||||
public static string GetJsonFieldName(this MemberInfo memberInfo)
|
||||
{
|
||||
var memberName = memberInfo.Name;
|
||||
var paramAttr = memberInfo.GetCustomAttribute<ParameterAttribute>();
|
||||
|
||||
if (paramAttr != null && !string.IsNullOrEmpty(paramAttr.Key))
|
||||
{
|
||||
memberName = paramAttr.Key;
|
||||
}
|
||||
|
||||
return memberName.ToRubyCase();
|
||||
}
|
||||
|
||||
public static IEnumerable<PropertyOrField> GetPropertiesAndFields(this Type type)
|
||||
{
|
||||
return ReflectionUtils.GetProperties(type).Select(property => new PropertyOrField(property))
|
||||
.Union(ReflectionUtils.GetFields(type).Select(field => new PropertyOrField(field)))
|
||||
.Where(p => p.IsPublic && !p.IsStatic);
|
||||
.Where(p => (p.IsPublic || p.HasParameterAttribute) && !p.IsStatic);
|
||||
}
|
||||
|
||||
public static bool IsDateTimeOffset(this Type type)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Octokit.Reflection;
|
||||
|
||||
@@ -27,15 +28,7 @@ namespace Octokit.Internal
|
||||
|
||||
protected override string MapClrMemberToJsonFieldName(MemberInfo member)
|
||||
{
|
||||
var memberName = member.Name;
|
||||
var paramAttr = member.GetCustomAttribute<ParameterAttribute>();
|
||||
|
||||
if (paramAttr != null && !string.IsNullOrEmpty(paramAttr.Key))
|
||||
{
|
||||
memberName = paramAttr.Key;
|
||||
}
|
||||
|
||||
return memberName.ToRubyCase();
|
||||
return member.GetJsonFieldName();
|
||||
}
|
||||
|
||||
internal override IDictionary<string, ReflectionUtils.GetDelegate> GetterValueFactory(Type type)
|
||||
@@ -141,25 +134,16 @@ namespace Octokit.Internal
|
||||
}
|
||||
}
|
||||
|
||||
var deserialized = base.DeserializeObject(value, type);
|
||||
return base.DeserializeObject(value, type);
|
||||
}
|
||||
|
||||
// Handle base64 encoding
|
||||
foreach (var propertyInfo in type.GetPropertiesAndFields())
|
||||
{
|
||||
if (!propertyInfo.CanRead) continue;
|
||||
if (!propertyInfo.CanWrite) continue;
|
||||
if (propertyInfo.Base64Encoded)
|
||||
{
|
||||
var propertyValue = propertyInfo.GetValue(deserialized) as string;
|
||||
if (propertyValue != null)
|
||||
{
|
||||
var unencoded = propertyValue.FromBase64String();
|
||||
propertyInfo.SetValue(deserialized, unencoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deserialized;
|
||||
internal override IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> SetterValueFactory(Type type)
|
||||
{
|
||||
return type.GetPropertiesAndFields()
|
||||
.Where(p => p.CanDeserialize)
|
||||
.ToDictionary(
|
||||
p => p.JsonFieldName,
|
||||
p => new KeyValuePair<Type, ReflectionUtils.SetDelegate>(p.Type, p.SetDelegate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Octokit.Internal;
|
||||
|
||||
namespace Octokit
|
||||
{
|
||||
@@ -16,7 +17,13 @@ namespace Octokit
|
||||
/// <summary>
|
||||
/// The encoded content if this is a file. Otherwise it's null.
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
[Parameter(Key = "content")]
|
||||
protected string EncodedContent { get; set; }
|
||||
|
||||
public string Content
|
||||
{
|
||||
get { return EncodedContent.FromBase64String(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to the target file in the repository if this is a symlink. Otherwise it's null.
|
||||
|
||||
Reference in New Issue
Block a user