From 641b03de410b2c867255451aaf2e8a1c1e4762ab Mon Sep 17 00:00:00 2001 From: Haacked Date: Tue, 30 Dec 2014 17:50:11 -0800 Subject: [PATCH] Improve support for base64 strings --- Octokit.Tests/SimpleJsonSerializerTests.cs | 12 ++++ Octokit/Helpers/PropertyOrField.cs | 81 +++++++++++++++++++--- Octokit/Helpers/StringExtensions.cs | 1 - Octokit/Http/SimpleJsonSerializer.cs | 37 +++------- 4 files changed, 94 insertions(+), 37 deletions(-) diff --git a/Octokit.Tests/SimpleJsonSerializerTests.cs b/Octokit.Tests/SimpleJsonSerializerTests.cs index 0956ea59..6f68971b 100644 --- a/Octokit.Tests/SimpleJsonSerializerTests.cs +++ b/Octokit.Tests/SimpleJsonSerializerTests.cs @@ -113,6 +113,18 @@ namespace Octokit.Tests public string Content { get { return "*" + EncodedContent + "*"; } } } + [Fact] + public void HandlesBase64EncodedStrings() + { + const string json = "{\"name\":\"RmVycmlzIEJ1ZWxsZXI=\",\"description\":\"stuff\",\"content\":\"RGF5IG9mZg==\"}"; + + var item = new SimpleJsonSerializer().Deserialize(json); + + Assert.Equal("Ferris Bueller", item.Name); + Assert.Equal("Day off", item.Content); + Assert.Equal("stuff", item.Description); + } + [Fact] public void CanDeserializeOrganization() { diff --git a/Octokit/Helpers/PropertyOrField.cs b/Octokit/Helpers/PropertyOrField.cs index af3e7870..97d51b20 100644 --- a/Octokit/Helpers/PropertyOrField.cs +++ b/Octokit/Helpers/PropertyOrField.cs @@ -19,8 +19,6 @@ 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) @@ -31,8 +29,6 @@ namespace Octokit CanWrite = true; IsStatic = fieldInfo.IsStatic; IsPublic = fieldInfo.IsPublic; - - CanDeserialize = (IsPublic || HasParameterAttribute) && !IsStatic && CanWrite && !fieldInfo.IsInitOnly; } protected PropertyOrField(MemberInfo memberInfo) @@ -88,19 +84,74 @@ namespace Octokit get { return MemberInfo.GetJsonFieldName(); } } + public ReflectionUtils.GetDelegate GetDelegate + { + get + { + ReflectionUtils.GetDelegate getDelegate = null; + if (_propertyInfo != null) + { + getDelegate = ReflectionUtils.GetGetMethod(_propertyInfo); + } + if (_fieldInfo != null) + { + getDelegate = ReflectionUtils.GetGetMethod(_fieldInfo); + } + + + if (getDelegate == null) + { + throw new InvalidOperationException("Property and Field cannot both be null"); + } + + if (Base64Encoded) + { + return delegate(object source) + { + var value = getDelegate(source); + var stringValue = value as string; + if (stringValue == null) + { + return value; + } + return stringValue.ToBase64String(); + }; + } + + return getDelegate; + } + } public ReflectionUtils.SetDelegate SetDelegate { get { + ReflectionUtils.SetDelegate setDelegate = null; if (_propertyInfo != null) { - return ReflectionUtils.GetSetMethod(_propertyInfo); + setDelegate = ReflectionUtils.GetSetMethod(_propertyInfo); } if (_fieldInfo != null) { - return ReflectionUtils.GetSetMethod(_fieldInfo); + setDelegate = ReflectionUtils.GetSetMethod(_fieldInfo); } - throw new InvalidOperationException("Property and Field cannot both be null"); + if (setDelegate == null) + { + throw new InvalidOperationException("Property and Field cannot both be null"); + } + if (Base64Encoded) + { + return delegate(object source, object value) + { + var stringValue = value as string; + if (stringValue == null) + { + setDelegate(source, value); + } + setDelegate(source, stringValue.FromBase64String()); + }; + + } + return setDelegate; } } @@ -120,6 +171,20 @@ namespace Octokit } } - public bool CanDeserialize { get; set; } + public bool CanDeserialize + { + get + { + return (IsPublic || HasParameterAttribute) + && !IsStatic + && CanWrite + && (_fieldInfo == null || !_fieldInfo.IsInitOnly); + } + } + + public bool CanSerialize + { + get { return IsPublic && CanRead && !IsStatic; } + } } } diff --git a/Octokit/Helpers/StringExtensions.cs b/Octokit/Helpers/StringExtensions.cs index 333884d7..e49198f7 100644 --- a/Octokit/Helpers/StringExtensions.cs +++ b/Octokit/Helpers/StringExtensions.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Reflection; using System.Text; using System.Text.RegularExpressions; diff --git a/Octokit/Http/SimpleJsonSerializer.cs b/Octokit/Http/SimpleJsonSerializer.cs index ff95c4ec..c8f93ea2 100644 --- a/Octokit/Http/SimpleJsonSerializer.cs +++ b/Octokit/Http/SimpleJsonSerializer.cs @@ -24,7 +24,6 @@ namespace Octokit.Internal class GitHubSerializerStrategy : PocoJsonSerializerStrategy { readonly List _membersWhichShouldPublishNull = new List(); - readonly List _membersWhichShouldBeBase64Encoded = new List(); protected override string MapClrMemberToJsonFieldName(MemberInfo member) { @@ -33,28 +32,19 @@ namespace Octokit.Internal internal override IDictionary GetterValueFactory(Type type) { - var fullName = type.FullName + "-"; + var propertiesAndFields = type.GetPropertiesAndFields().Where(p => p.CanSerialize).ToList(); - // sometimes Octokit needs to send a null with the payload so the user - // can unset the value of a property. - // This method uses the same checks as PocoJsonSerializerStrategy - // to identify the right fields and properties to serialize - // but it then filters on the presence of SerializeNullAttribute. - - foreach (var propertyOrField in type.GetPropertiesAndFields()) + foreach (var property in propertiesAndFields.Where(p => p.SerializeNull)) { - if (!propertyOrField.CanRead) - continue; - if (propertyOrField.Base64Encoded) - { - _membersWhichShouldBeBase64Encoded.Add(fullName + MapClrMemberToJsonFieldName(propertyOrField.MemberInfo)); - } - if (!propertyOrField.SerializeNull) - continue; - _membersWhichShouldPublishNull.Add(fullName + MapClrMemberToJsonFieldName(propertyOrField.MemberInfo)); + var key = type.FullName + "-" + property.JsonFieldName; + + _membersWhichShouldPublishNull.Add(key); } - return base.GetterValueFactory(type); + return propertiesAndFields + .ToDictionary( + p => p.JsonFieldName, + p => p.GetDelegate); } // This is overridden so that null values are omitted from serialized objects. @@ -77,15 +67,6 @@ namespace Octokit.Internal if (!_membersWhichShouldPublishNull.Contains(key)) continue; } - else - { - var key = type.FullName + "-" + getter.Key; - if (_membersWhichShouldBeBase64Encoded.Contains(key)) - { - var stringValue = value as string ?? ""; - value = stringValue.ToBase64String(); - } - } jsonObject.Add(getter.Key, value); } }