Skip to content

Commit

Permalink
Merge pull request MapsterMapper#53 from chaowlert/clone-setting
Browse files Browse the repository at this point in the history
cloning config
  • Loading branch information
eswann committed Mar 7, 2016
2 parents 77e49f6 + 3938e91 commit 2325f46
Show file tree
Hide file tree
Showing 24 changed files with 323 additions and 172 deletions.
2 changes: 1 addition & 1 deletion src/Mapster.Tests/Mapster.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@
<Compile Include="Classes\Customer.cs" />
<Compile Include="Classes\Product.cs" />
<Compile Include="Classes\TypeTestClass.cs" />
<Compile Include="WhenCloningConfig.cs" />
<Compile Include="WhenCreatingConfigInstance.cs" />
<Compile Include="WhenMappingRecordTypes.cs" />
<Compile Include="WhenMappingIgnoreNullValues.cs" />
<Compile Include="WhenMappingWithExtensionMethods.cs" />
<Compile Include="WhenPreserveReferences.cs" />
<Compile Include="WhenAddingCustomMappings.cs" />
<Compile Include="WhenAddingPrimitiveTypes.cs" />
<Compile Include="WhenHandlingUnmappedMembers.cs" />
<Compile Include="WhenExplicitMappingRequired.cs" />
<Compile Include="WhenMappingConditionally.cs" />
Expand Down
42 changes: 0 additions & 42 deletions src/Mapster.Tests/WhenAddingPrimitiveTypes.cs

This file was deleted.

86 changes: 86 additions & 0 deletions src/Mapster.Tests/WhenCloningConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Linq;
using Mapster.Models;
using NUnit.Framework;
using Should;

namespace Mapster.Tests
{
[TestFixture]
public class WhenCloningConfig
{
[TearDown]
public void TearDown()
{
TypeAdapterConfig.GlobalSettings.Clear();
}

[Test]
public void Alter_Config_After_Map_Should_Error()
{
TypeAdapterConfig<SimplePoco, SimpleDto>.NewConfig()
.Map(dest => dest.Name, src => "a");

var poco = new SimplePoco
{
Id = Guid.NewGuid(),
Name = "test",
};
var result = TypeAdapter.Adapt<SimpleDto>(poco);
result.Name.ShouldEqual("a");

var ex = Assert.Throws<InvalidOperationException>(() =>
TypeAdapterConfig<SimplePoco, SimpleDto>.ForType()
.Map(dest => dest.Name, src => "b"));
ex.Message.ShouldContain("TypeAdapter.Adapt was already called");
}

[Test]
public void Clone()
{
TypeAdapterConfig<SimplePoco, SimpleDto>.NewConfig()
.Map(dest => dest.Name, src => "a");

var poco = new SimplePoco
{
Id = Guid.NewGuid(),
Name = "test",
};
var result = TypeAdapter.Adapt<SimpleDto>(poco);
result.Name.ShouldEqual("a");

var config = TypeAdapterConfig.GlobalSettings.Clone();
var global = TypeAdapterConfig.GlobalSettings;
config.ShouldNotBeSameAs(global);
config.Default.ShouldNotBeSameAs(global.Default);
config.Default.Settings.ShouldNotBeSameAs(global.Default.Settings);
config.RuleMap.ShouldNotBeSameAs(global.RuleMap);
foreach (var kvp in config.RuleMap)
{
var globalRule = global.RuleMap[kvp.Key];
kvp.Value.ShouldNotBeSameAs(globalRule);
kvp.Value.Settings.ShouldNotBeSameAs(globalRule.Settings);
}
config.Rules.ShouldNotBeSameAs(global.Rules);
for (var i = 0; i < config.Rules.Count; i++)
{
config.Rules[i].ShouldNotBeSameAs(global.Rules[i]);
config.Rules[i].Settings.ShouldNotBeSameAs(global.Rules[i].Settings);
}
config.Rules.Any(rule => object.ReferenceEquals(rule.Settings, config.Default.Settings)).ShouldBeTrue();
config.Rules.ShouldContain(config.RuleMap[new TypeTuple(typeof(SimplePoco), typeof(SimpleDto))]);
}

public class SimplePoco
{
public Guid Id { get; set; }
public string Name { get; set; }
}

public class SimpleDto
{
public Guid Id { get; set; }
public string Name { get; protected set; }
}
}
}
2 changes: 1 addition & 1 deletion src/Mapster.Tests/WhenExplicitMappingRequired.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class WhenExplicitMappingRequired
public void TearDown()
{
TypeAdapterConfig.GlobalSettings.RequireExplicitMapping = false;
TypeAdapterConfig<SimplePoco, SimpleDto>.Clear();
TypeAdapterConfig.GlobalSettings.Clear();
}


Expand Down
2 changes: 1 addition & 1 deletion src/Mapster.Tests/WhenScanningForRegisters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public void Registers_Are_Found()
IList<IRegister> registers = TypeAdapterConfig.GlobalSettings.Scan(Assembly.GetExecutingAssembly());
registers.Count.ShouldEqual(2);

var typeTuples = TypeAdapterConfig.GlobalSettings.Dict.Keys.ToList();
var typeTuples = TypeAdapterConfig.GlobalSettings.RuleMap.Keys.ToList();

typeTuples.Any(x => x.Equals(new TypeTuple(typeof(Customer), typeof(CustomerDTO)))).ShouldBeTrue();
typeTuples.Any(x => x.Equals(new TypeTuple(typeof(Product), typeof(ProductDTO)))).ShouldBeTrue();
Expand Down
17 changes: 13 additions & 4 deletions src/Mapster/Adapters/BaseAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ namespace Mapster.Adapters
{
public abstract class BaseAdapter
{
public abstract int? Priority(Type sourceType, Type destinationType, MapType mapType);
protected virtual int Score => 0;

public virtual int? Priority(Type sourceType, Type destinationType, MapType mapType)
{
return CanMap(sourceType, destinationType, mapType) ? this.Score : (int?)null;
}

protected abstract bool CanMap(Type sourceType, Type destinationType, MapType mapType);

public LambdaExpression CreateAdaptFunc(CompileArgument arg)
{
Expand Down Expand Up @@ -73,13 +80,16 @@ protected virtual Expression CreateExpressionBody(Expression source, Expression

protected Expression CreateBlockExpressionBody(Expression source, Expression destination, CompileArgument arg)
{
if (arg.MapType == MapType.Projection)
throw new InvalidOperationException(
$"Mapping is invalid for projection: TSource: {arg.SourceType} TDestination: {arg.DestinationType}");

var result = Expression.Variable(arg.DestinationType);
Expression assign = Expression.Assign(result, destination ?? CreateInstantiationExpression(source, arg));

var set = CreateBlockExpression(source, result, arg);

if (arg.Settings.PreserveReference == true &&
arg.MapType != MapType.Projection &&
!arg.SourceType.GetTypeInfo().IsValueType &&
!arg.DestinationType.GetTypeInfo().IsValueType)
{
Expand Down Expand Up @@ -130,8 +140,7 @@ protected Expression CreateBlockExpressionBody(Expression source, Expression des
//else
// result = adapt(source);
//return result;
if (arg.MapType != MapType.Projection &&
(!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable()))
if (!arg.SourceType.GetTypeInfo().IsValueType || arg.SourceType.IsNullable())
{
var compareNull = Expression.Equal(source, Expression.Constant(null, source.Type));
set = Expression.IfThenElse(
Expand Down
26 changes: 13 additions & 13 deletions src/Mapster/Adapters/BaseClassAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ internal abstract class BaseClassAdapter : BaseAdapter

#region Build the Adapter Model

protected ClassConverter CreateClassConverter(Expression source, Expression destination, CompileArgument arg)
protected ClassMapping CreateClassConverter(Expression source, Expression destination, CompileArgument arg)
{
Type sourceType = source.Type;
var classModel = GetClassModel(arg.DestinationType);
var destinationMembers = classModel.Members;

var unmappedDestinationMembers = new List<string>();

var properties = new List<MemberConverter>();
var properties = new List<MemberMapping>();

for (int i = 0; i < destinationMembers.Count; i++)
{
Expand All @@ -34,7 +34,7 @@ protected ClassConverter CreateClassConverter(Expression source, Expression dest
var sourceMember = ReflectionUtils.GetMemberModel(sourceType, destinationMember.Name);
if (sourceMember != null)
{
var propertyModel = new MemberConverter
var propertyModel = new MemberMapping
{
ConvertType = 1,
Getter = sourceMember.GetExpression(source),
Expand All @@ -51,7 +51,7 @@ protected ClassConverter CreateClassConverter(Expression source, Expression dest

if (classModel.ConstructorInfo != null)
{
var propertyModel = new MemberConverter
var propertyModel = new MemberMapping
{
ConvertType = 0,
Getter = null,
Expand All @@ -74,7 +74,7 @@ protected ClassConverter CreateClassConverter(Expression source, Expression dest
throw new ArgumentOutOfRangeException($"The following members of destination class {arg.DestinationType} do not have a corresponding source member mapped or ignored:{string.Join(",", unmappedDestinationMembers)}");
}

return new ClassConverter
return new ClassMapping
{
ConstructorInfo = classModel.ConstructorInfo,
Members = properties,
Expand All @@ -85,13 +85,13 @@ protected ClassConverter CreateClassConverter(Expression source, Expression dest
Expression source,
Expression destination,
IMemberModel destinationMember,
List<MemberConverter> properties,
List<MemberMapping> properties,
bool isProjection)
{
var getter = ReflectionUtils.GetDeepFlattening(source, destinationMember.Name, isProjection);
if (getter != null)
{
var propertyModel = new MemberConverter
var propertyModel = new MemberMapping
{
ConvertType = 3,
Getter = getter,
Expand All @@ -109,12 +109,12 @@ protected ClassConverter CreateClassConverter(Expression source, Expression dest
Expression source,
Expression destination,
IMemberModel destinationMember,
List<MemberConverter> properties)
List<MemberMapping> properties)
{
var getMethod = source.Type.GetMethod(string.Concat("Get", destinationMember.Name));
var getMethod = source.Type.GetMethod(string.Concat("Get", destinationMember.Name), BindingFlags.Public | BindingFlags.Instance);
if (getMethod != null)
{
var propertyModel = new MemberConverter
var propertyModel = new MemberMapping
{
ConvertType = 2,
Getter = Expression.Call(source, getMethod),
Expand All @@ -134,13 +134,13 @@ protected ClassConverter CreateClassConverter(Expression source, Expression dest
Expression destination,
TypeAdapterSettings config,
IMemberModel destinationMember,
List<MemberConverter> properties)
List<MemberMapping> properties)
{
bool isAdded = false;
var resolvers = config.Resolvers;
if (resolvers != null && resolvers.Count > 0)
{
MemberConverter memberConverter = null;
MemberMapping memberConverter = null;
LambdaExpression lastCondition = null;
for (int j = 0; j < resolvers.Count; j++)
{
Expand All @@ -149,7 +149,7 @@ protected ClassConverter CreateClassConverter(Expression source, Expression dest
{
if (memberConverter == null)
{
memberConverter = new MemberConverter
memberConverter = new MemberMapping
{
ConvertType = 5,
Setter = destinationMember.GetExpression(destination),
Expand Down
15 changes: 8 additions & 7 deletions src/Mapster/Adapters/ClassAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Linq.Expressions;
using System.Reflection;
using Mapster.Models;
using Mapster.Utils;

namespace Mapster.Adapters
{
Expand All @@ -16,15 +15,17 @@ namespace Mapster.Adapters
/// </remarks>
internal class ClassAdapter : BaseClassAdapter
{
public override int? Priority(Type sourceType, Type destinationType, MapType mapType)
protected override int Score => -150;

protected override bool CanMap(Type sourceType, Type destinationType, MapType mapType)
{
if (sourceType == typeof (string) || sourceType == typeof (object))
return null;
return false;

if (destinationType.GetPublicFieldsAndProperties(allowNoSetter: false).Count == 0)
return null;
if (!destinationType.IsPoco())
return false;

return -150;
return true;
}

protected override bool CanInline(Expression source, Expression destination, CompileArgument arg)
Expand All @@ -40,7 +41,7 @@ protected override bool CanInline(Expression source, Expression destination, Com
protected override Expression CreateExpressionBody(Expression source, Expression destination, CompileArgument arg)
{
if (arg.Context.Config.RequireExplicitMapping
&& !arg.Context.Config.Dict.ContainsKey(new TypeTuple(arg.SourceType, arg.DestinationType)))
&& !arg.Context.Config.RuleMap.ContainsKey(new TypeTuple(arg.SourceType, arg.DestinationType)))
{
throw new InvalidOperationException(
$"Implicit mapping is not allowed (check GlobalSettings.RequireExplicitMapping) and no configuration exists for the following mapping: TSource: {arg.SourceType} TDestination: {arg.DestinationType}");
Expand Down
20 changes: 11 additions & 9 deletions src/Mapster/Adapters/CollectionAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ namespace Mapster.Adapters
{
internal class CollectionAdapter : BaseAdapter
{
public override int? Priority(Type sourceType, Type destinationType, MapType mapType)
protected override int Score => -125;

protected override bool CanMap(Type sourceType, Type destinationType, MapType mapType)
{
if (sourceType.IsCollection() && destinationType.IsCollection())
return -125;
else
return null;
return sourceType.IsCollection()
&& destinationType.IsCollection()
&& destinationType.IsListCompatible();
}

private static Expression CreateCountExpression(Expression source, bool allowCountAll)
Expand Down Expand Up @@ -43,9 +44,7 @@ protected override bool CanInline(Expression source, Expression destination, Com

if (arg.MapType == MapType.Projection)
{
var destinationElementType = arg.DestinationType.ExtractCollectionType();
var listType = typeof (List<>).MakeGenericType(destinationElementType);
if (arg.DestinationType.GetTypeInfo().IsAssignableFrom(listType.GetTypeInfo()))
if (arg.DestinationType.IsAssignableFromList())
return true;

throw new InvalidOperationException(
Expand All @@ -72,7 +71,10 @@ protected override Expression CreateInstantiationExpression(Expression source, C
: arg.DestinationType;
if (count == null)
return Expression.New(listType); //new List<T>()
var ctor = listType.GetConstructor(new[] { typeof(int) });
var ctor = (from c in listType.GetConstructors()
let args = c.GetParameters()
where args.Length == 1 && args[0].ParameterType == typeof (int)
select c).FirstOrDefault();
if (ctor == null)
return Expression.New(listType); //new List<T>()
else
Expand Down
Loading

0 comments on commit 2325f46

Please sign in to comment.