From d6f58c39f3a9fb127c99a578373fa195f1f9e023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SAL=C4=B0H=20=C3=96ZKARA?= Date: Wed, 13 Aug 2025 14:38:45 +0300 Subject: [PATCH] test --- .../Mapperly/MapExtraPropertiesAttribute.cs | 122 +++++++++++++++++- .../MapperlyAutoObjectMappingProvider.cs | 122 ++++++++++-------- 2 files changed, 186 insertions(+), 58 deletions(-) diff --git a/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapExtraPropertiesAttribute.cs b/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapExtraPropertiesAttribute.cs index 705a1af72d..9059a494c9 100644 --- a/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapExtraPropertiesAttribute.cs +++ b/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapExtraPropertiesAttribute.cs @@ -1,14 +1,132 @@ using System; +using System.Collections.Generic; +using System.Reflection; +using Volo.Abp.Data; using Volo.Abp.ObjectExtending; namespace Volo.Abp.Mapperly; +// [AttributeUsage(AttributeTargets.Class)] +// public class MapExtraPropertiesAttribute : Attribute +// { +// public MappingPropertyDefinitionChecks DefinitionChecks { get; set; } = MappingPropertyDefinitionChecks.Null; +// +// public string[]? IgnoredProperties { get; set; } +// +// public bool MapToRegularProperties { get; set; } +// } + + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public abstract class BeforeMap : Attribute +{ + public abstract void Execute(TSource source); + + public Type GetSourceType() + { + return typeof(TSource); + } +} + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public abstract class AfterMap : Attribute +{ + public abstract void Execute(TSource source, TDestination destination); + + public Type GetSourceType() + { + return typeof(TSource); + } + + public Type GetDestinationType() + { + return typeof(TDestination); + } +} + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public abstract class AfterMap : Attribute +{ + public abstract TContext CreateContext(TSource source); + public abstract TContext CreateContextWithDestination(TSource source, TDestination destination); + public abstract void Execute(TSource source, TDestination destination, TContext context); +} + [AttributeUsage(AttributeTargets.Class)] -public class MapExtraPropertiesAttribute : Attribute +public class MapExtraPropertiesAttribute : AfterMap { public MappingPropertyDefinitionChecks DefinitionChecks { get; set; } = MappingPropertyDefinitionChecks.Null; public string[]? IgnoredProperties { get; set; } public bool MapToRegularProperties { get; set; } -} + + protected virtual void MapExtraProperties( + IHasExtraProperties source, + IHasExtraProperties destination, + ExtraPropertyDictionary destinationExtraProperty, + MappingPropertyDefinitionChecks? definitionChecks = null, + string[]? ignoredProperties = null, + bool mapToRegularProperties = false) + { + var result = destinationExtraProperty.IsNullOrEmpty() + ? new Dictionary() + : new Dictionary(destinationExtraProperty); + + if (source.ExtraProperties != null && destination.ExtraProperties != null) + { + ExtensibleObjectMapper + .MapExtraPropertiesTo( + typeof(TSource), + typeof(TDestination), + source.ExtraProperties, + result, + definitionChecks, + ignoredProperties + ); + } + + ObjectHelper.TrySetProperty(destination, x => x.ExtraProperties, () => new ExtraPropertyDictionary(result)); + if (mapToRegularProperties) + { + destination.SetExtraPropertiesToRegularProperties(); + } + } + + protected virtual ExtraPropertyDictionary GetExtraProperties(TDestination destination) + { + var extraProperties = new ExtraPropertyDictionary(); + if (destination is not IHasExtraProperties hasExtraProperties) + { + return extraProperties; + } + + foreach (var property in hasExtraProperties.ExtraProperties) + { + extraProperties.Add(property.Key, property.Value); + } + return extraProperties; + } + + public override ExtraPropertyDictionary CreateContext(IHasExtraProperties source) + { + return new ExtraPropertyDictionary(); + } + + public override ExtraPropertyDictionary CreateContextWithDestination(IHasExtraProperties source, IHasExtraProperties destination) + { + return GetExtraProperties(destination); + } + + public override void Execute(IHasExtraProperties source, IHasExtraProperties destination, ExtraPropertyDictionary context) + { + MapExtraProperties( + source, + destination, + context, + DefinitionChecks, + IgnoredProperties, + MapToRegularProperties + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs b/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs index 677649b79a..dbda4c8733 100644 --- a/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs +++ b/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs @@ -34,18 +34,69 @@ public class MapperlyAutoObjectMappingProvider : IAutoObjectMappingProvider public virtual TDestination Map(object source) { - if (TryToMapCollection((TSource)source, default, out var collectionResult)) - { - return collectionResult; - } - var mapper = ServiceProvider.GetService>(); if (mapper != null) { + var beforeMapAttributes = mapper.GetType().GetCustomAttributes(typeof(BeforeMap<>)).Where(x => typeof(TSource).IsAssignableFrom(x.GetType().GetGenericArguments().FirstOrDefault())) + .ToList(); + var beforeMapAttributeExecuteMethod = typeof(BeforeMap<>).GetMethod(nameof(BeforeMap.Execute), + BindingFlags.Instance | BindingFlags.Public); + if (beforeMapAttributeExecuteMethod != null) + { + foreach (var beforeMapAttribute in beforeMapAttributes) + { + var executeMethod = beforeMapAttributeExecuteMethod.MakeGenericMethod(typeof(TSource)); + executeMethod.Invoke(beforeMapAttribute, [source]); + } + } mapper.BeforeMap((TSource)source); + var afterMapAttributes = mapper.GetType().GetCustomAttributes(typeof(AfterMap<,>)).Where(x => typeof(TSource).IsAssignableFrom(x.GetType().GetGenericArguments().FirstOrDefault()) && + typeof(TDestination).IsAssignableFrom(x.GetType().GetGenericArguments().LastOrDefault())).ToArray(); + var afterMapAttributesWithContext = afterMapAttributes + .Where(x => typeof(AfterMap<, ,>).IsInstanceOfType(x)) + .ToList(); + var contexts = new List(); + var createContextMethod = typeof(AfterMap<, ,>).GetMethod(nameof(AfterMap.CreateContext), + BindingFlags.Instance | BindingFlags.Public); + if (createContextMethod != null) + { + foreach (var afterMapAttribute in afterMapAttributesWithContext) + { + var context = createContextMethod.Invoke(afterMapAttribute, [source]); + contexts.Add(context); + } + } var destination = mapper.Map((TSource)source); TryMapExtraProperties(mapper.GetType().GetSingleAttributeOrNull(), (TSource)source, destination, new ExtraPropertyDictionary()); mapper.AfterMap((TSource)source, destination); + + var afterMapExecuteMethod = typeof(AfterMap<, ,>).GetMethod(nameof(AfterMap.Execute), + BindingFlags.Instance | BindingFlags.Public); + if (afterMapExecuteMethod != null) + { + for (var i = 0; i < afterMapAttributesWithContext.Count; i++) + { + var afterMapAttribute = afterMapAttributesWithContext[i]; + var executeMethod = afterMapExecuteMethod.MakeGenericMethod(typeof(TSource), typeof(TDestination)); + executeMethod.Invoke(afterMapAttribute, [source, destination, contexts[i]]); + } + } + + var afterMapAttributesWithoutContext = afterMapAttributes + .Where(x => !typeof(AfterMap<, ,>).IsInstanceOfType(x)) + .ToList(); + + var afterMapExecuteMethodWithoutContext = typeof(AfterMap<,>).GetMethod(nameof(AfterMap.Execute), + BindingFlags.Instance | BindingFlags.Public); + if (afterMapExecuteMethodWithoutContext != null) + { + foreach (var afterMapAttribute in afterMapAttributesWithoutContext) + { + var executeMethod = afterMapExecuteMethodWithoutContext.MakeGenericMethod(typeof(TSource), typeof(TDestination)); + executeMethod.Invoke(afterMapAttribute, [source, destination]); + } + } + return destination; } @@ -58,6 +109,11 @@ public class MapperlyAutoObjectMappingProvider : IAutoObjectMappingProvider reverseMapper.AfterReverseMap((TSource)source, destination); return destination; } + + if (TryToMapCollection((TSource)source, default, out var collectionResult)) + { + return collectionResult; + } throw new AbpException($"No {TypeHelper.GetFullNameHandlingNullableAndGenerics(typeof(IAbpMapperlyMapper))} or" + $" {TypeHelper.GetFullNameHandlingNullableAndGenerics(typeof(IAbpReverseMapperlyMapper))} was found"); @@ -65,11 +121,6 @@ public class MapperlyAutoObjectMappingProvider : IAutoObjectMappingProvider public virtual TDestination Map(TSource source, TDestination destination) { - if (TryToMapCollection(source, destination, out var collectionResult)) - { - return collectionResult; - } - var mapper = ServiceProvider.GetService>(); if (mapper != null) { @@ -91,6 +142,11 @@ public class MapperlyAutoObjectMappingProvider : IAutoObjectMappingProvider reverseMapper.AfterReverseMap(source, destination); return destination; } + + if (TryToMapCollection(source, destination, out var collectionResult)) + { + return collectionResult; + } throw new AbpException($"No {TypeHelper.GetFullNameHandlingNullableAndGenerics(typeof(IAbpMapperlyMapper))} or" + $" {TypeHelper.GetFullNameHandlingNullableAndGenerics(typeof(IAbpReverseMapperlyMapper))} was found"); @@ -216,21 +272,6 @@ public class MapperlyAutoObjectMappingProvider : IAutoObjectMappingProvider return Expression.Lambda>(callConvert, instanceParam, sourceParam, destinationParam).Compile(); } - protected virtual ExtraPropertyDictionary GetExtraProperties(TDestination destination) - { - var extraProperties = new ExtraPropertyDictionary(); - if (destination is not IHasExtraProperties hasExtraProperties) - { - return extraProperties; - } - - foreach (var property in hasExtraProperties.ExtraProperties) - { - extraProperties.Add(property.Key, property.Value); - } - return extraProperties; - } - protected virtual void TryMapExtraProperties(MapExtraPropertiesAttribute? mapExtraPropertiesAttribute, TSource source, TDestination destination, ExtraPropertyDictionary destinationExtraProperty) { if (mapExtraPropertiesAttribute != null && @@ -247,35 +288,4 @@ public class MapperlyAutoObjectMappingProvider : IAutoObjectMappingProvider ); } } - protected virtual void MapExtraProperties( - IHasExtraProperties source, - IHasExtraProperties destination, - ExtraPropertyDictionary destinationExtraProperty, - MappingPropertyDefinitionChecks? definitionChecks = null, - string[]? ignoredProperties = null, - bool mapToRegularProperties = false) - { - var result = destinationExtraProperty.IsNullOrEmpty() - ? new Dictionary() - : new Dictionary(destinationExtraProperty); - - if (source.ExtraProperties != null && destination.ExtraProperties != null) - { - ExtensibleObjectMapper - .MapExtraPropertiesTo( - typeof(TSource), - typeof(TDestination), - source.ExtraProperties, - result, - definitionChecks, - ignoredProperties - ); - } - - ObjectHelper.TrySetProperty(destination, x => x.ExtraProperties, () => new ExtraPropertyDictionary(result)); - if (mapToRegularProperties) - { - destination.SetExtraPropertiesToRegularProperties(); - } - } }