Possible problem in ReflectionUtils Auto-Mapping methods

174 views
Skip to first unread message

Joachim Rosskopf

unread,
May 17, 2013, 3:16:48 AM5/17/13
to servic...@googlegroups.com, j...@gluelogic.de
Hello,

I currently have a problem with the Auto-Mapping methods, defined in ServiceStack.Common.Utils.ReflectionUtils. Whenever I try to map a collection-property, which setter-method is private or protected, the mapping fails with the following exception:

System.ArgumentNullException : Der Wert darf nicht NULL sein.
Parametername: method
   bei System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
   bei System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments)
   bei ServiceStack.Common.Support.PropertyInvoker.GetPropertySetterFn(PropertyInfo propertyInfo) in PropertyInvoker.cs: line 31.
   bei ServiceStack.Common.Support.AssignmentMember.GetSetValueFn() in AssignmentDefinition.cs: line 75.
   bei ServiceStack.Common.Support.AssignmentEntry..ctor(String name, AssignmentMember from, AssignmentMember to) in AssignmentDefinition.cs: line 26.
   bei ServiceStack.Common.Support.AssignmentDefinition.AddMatch(String name, AssignmentMember readMember, AssignmentMember writeMember) in AssignmentDefinition.cs: line 101.
   bei ServiceStack.Common.Utils.ReflectionUtils.<>c__DisplayClass2.<GetAssignmentDefinition>b__1(String param0) in ReflectionUtils.cs: line 117.
   bei ServiceStack.Net30.Collections.Concurrent.ConcurrentDictionary`2.<>c__DisplayClassb.<GetOrAdd>b__a() in ConcurrentDictionary.cs: line 162.
   bei ServiceStack.Net30.Collections.Concurrent.SplitOrderedList`2.ListInsert(Node newNode, Node startPoint, ref Node current, Func`1 dataCreator) in SplitOrderedList.cs: line 412.
   bei ServiceStack.Net30.Collections.Concurrent.SplitOrderedList`2.InsertInternal(UInt32 key, TKey subKey, T data, Func`1 dataCreator, ref Node current) in SplitOrderedList.cs: line 166.
   bei ServiceStack.Net30.Collections.Concurrent.SplitOrderedList`2.InsertOrGet(UInt32 key, TKey subKey, T data, Func`1 dataCreator) in SplitOrderedList.cs: line 152.
   bei ServiceStack.Net30.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) in ConcurrentDictionary.cs: line 162.
   bei ServiceStack.Common.Utils.ReflectionUtils.GetAssignmentDefinition(Type toType, Type fromType) in ReflectionUtils.cs: line 102.
   bei ServiceStack.Common.Utils.ReflectionUtils.PopulateObject(To to, From from) in ReflectionUtils.cs: line 200.
   bei ServiceStack.Common.ReflectionExtensions.PopulateWith(To to, From from) in ReflectionExtensions.cs: line 13.
   bei ServiceStack.Common.ReflectionExtensions.TranslateTo(Object from) in ReflectionExtensions.cs: line 35.
   bei ServiceStack.Common.Tests.ReflectionExtensionsTests.Can_translate_generic_list_with_protected_setter() in ReflectionExtensionsTests.cs: line 76.

The root cause of this problem is in ServiceStack.Common.Support.PropertyInvoker::GetPropertySetterFn. Here the call to propertyInfo.GetSetMethod() returns null for private or protected properties. On the other hand in ServiceStack.Common.Utils.ReflectionUtils::GetMembers, where the write-properties are collected, a call to propertyInfo.CanWrite determines wether the property is writeable or not. But as far as I understand the CanWrite-Property is true, if a setter exists, regardless of the access modifier. So in the end this means, that the current implementation adds properites to the AssignmentDefinition, on which it later fails to compile a SetterFn.

A test-case to reproduce the problem looks like this:

public class TestClassA
{
public IList<string> ToStringList { get; set; }
public ArrayOfString FromStringList { get; set; }
public IList<UserFileType> FromUserFileTypes { get; set; }
}


public class TestClassC
{
    public IList<string> FromStringList { get; protected set; }
}

[Test]
public void Can_translate_generic_list_with_protected_setter()
{
    var values = new[] { "A", "B", "C" };
    var testA = new TestClassA
    {
        ToStringList = new List<string>(values),   
    };

    var fromTestA = testA.TranslateTo<TestClassC>();
    Assert.NotNull(fromTestA);
}

And now comes the question to the group. There are two possible fixes to the problem: 
- Ignore protected properties: This would mean to not only check CanWrite on the propertyInfo but also if GetPropertySetterFn() != null
- Also include protected/private setter by adding GetSetMethod(nonPublic: true)

Currently I don't know which one fits better the Auto-Mapping mindset.
Let me know what you think, so that I can prepare a pull request.

Thank you
---
Joachim

Demis Bellot

unread,
May 17, 2013, 3:19:49 AM5/17/13
to servic...@googlegroups.com, j...@gluelogic.de
Hi Joachim,

Ideally it should ignore protected properties.

Cheers,



--
You received this message because you are subscribed to the Google Groups "ServiceStack .NET Open Source REST Web Services Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to servicestack...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
- Demis

Reply all
Reply to author
Forward
0 new messages