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