• 基于grpc从零开始搭建一个准生产分布式应用(6) - 05 - MapStruct特殊实现


    一、Clone

    1. @Mapper(mappingControl = DeepClone.class)//这里需要注意用这个注解
    2. public interface Cloner {
    3. Cloner MAPPER = Mappers.getMapper( Cloner.class );
    4. CustomerDto clone(CustomerDto customerDto);
    5. }

    二、特殊注解

    2.1、@qualifiedBy

    这个注解的作用是当有重复的转换类时,指定一个,但也可以用注解来实现,下面的例子就是从一个集合中的对象中特定的地方取值然后mapping到特定的属性上,下面是一个集合应用。

    1. public class Source {
    2. private List<Integer> myIntegers;
    3. private List<String> myStrings;
    4. }
    5. public class Target {
    6. private Integer myInteger;
    7. private String myString;
    8. }
    9. public static void main( String[] args ) {
    10. Source s = new Source();
    11. s.setMyIntegers( Arrays.asList( 5, 3, 7 ) );
    12. s.setMyStrings( Arrays.asList( "five", "three", "seven " ) );
    13. Target t = SourceTargetMapper.MAPPER.toTarget( s );
    14. System.out.println( t.getMyInteger() );
    15. System.out.println( t.getMyString() );
    16. }
    17. //5
    18. //seven
    1. @Mapper( uses = IterableNonInterableUtil.class )
    2. public interface SourceTargetMapper {
    3. SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
    4. @Mapping( source = "myIntegers", target = "myInteger", qualifiedBy = FirstElement.class )
    5. @Mapping( source = "myStrings", target = "myString", qualifiedBy = LastElement.class )
    6. Target toTarget( Source s );
    7. }
    8. @Qualifier
    9. @Target(ElementType.METHOD)
    10. @Retention(RetentionPolicy.SOURCE)
    11. public @interface FirstElement {
    12. }
    13. @Qualifier
    14. @Target(ElementType.METHOD)
    15. @Retention(RetentionPolicy.SOURCE)
    16. public @interface LastElement {
    17. }
    1. public class IterableNonInterableUtil {
    2. @FirstElement
    3. public <T> T first( List<T> in ) {
    4. if ( in != null && !in.isEmpty() ) {
    5. return in.get( 0 );
    6. }
    7. else {
    8. return null;
    9. }
    10. }
    11. @LastElement
    12. public <T> T last( List<T> in ) {
    13. if ( in != null && !in.isEmpty() ) {
    14. return in.get( in.size() - 1 );
    15. }
    16. else {
    17. return null;
    18. }
    19. }
    20. }

    2.2、@ObjectFactory

    1. @Mapper
    2. public interface SourceTargetMapper {
    3. SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
    4. @Mapping( target = "descriptionArticle1", source = "brush.description" )
    5. @Mapping( target = "descriptionArticle2", source = "paste.description" )
    6. CombinedOfferingEntity toEntity(Toothbrush brush, ToothPaste paste, @Context ArticleRepository repo);
    7. @ObjectFactory
    8. default <T extends Entity> T lookup(Toothbrush brush, ToothPaste paste, @Context ArticleRepository repo,
    9. @TargetType Class<T> targetType ) {
    10. ComposedKey key = new ComposedKey(brush.getName(), paste.getName() );
    11. CombinedOfferingEntity entity = repo.lookup( key );
    12. if ( entity == null ) {
    13. entity = new CombinedOfferingEntity();
    14. }
    15. return (T) entity;
    16. }
    17. }
    18. //生成的代码如下,上面代码大概的逻辑是先执行工厂方法,然后先执行工厂方法,再执行余下的映射
    19. public CombinedOfferingEntity toEntity(Toothbrush brush, ToothPaste paste, ArticleRepository repo) {
    20. if ( brush == null && paste == null ) {
    21. return null;
    22. }
    23. CombinedOfferingEntity combinedOfferingEntity = lookup( brush, paste, repo, CombinedOfferingEntity.class );
    24. if ( brush != null ) {
    25. combinedOfferingEntity.setDescriptionArticle1( brush.getDescription() );
    26. }
    27. if ( paste != null ) {
    28. combinedOfferingEntity.setDescriptionArticle2( paste.getDescription() );
    29. }
    30. return combinedOfferingEntity;
    31. }

    2.3、@Context循环依赖

    1. public class Employee {
    2. private String name;
    3. private Employee reportsTo;
    4. private List team;
    5. }
    6. public class EmployeeDto {
    7. private String employeeName;
    8. private EmployeeDto reportsTo;
    9. private List team;
    10. }
    11. @Mapper
    12. public interface EmployeeMapper {
    13. EmployeeMapper MAPPER = Mappers.getMapper( EmployeeMapper.class );
    14. @Mapping(source = "employeeName", target = "name")
    15. Employee toEmployee(EmployeeDto employeeDto, @Context CycleAvoidingMappingContext context);
    16. @InheritInverseConfiguration
    17. EmployeeDto fromEmployee(Employee employee, @Context CycleAvoidingMappingContext context);
    18. }
    1. public class CycleAvoidingMappingContext {
    2. private Map<Object, Object> knownInstances = new IdentityHashMap<Object, Object>();
    3. @BeforeMapping
    4. public T getMappedInstance(Object source, @TargetType Class targetType) {
    5. return (T) knownInstances.get( source );
    6. }
    7. @BeforeMapping
    8. public void storeMappedInstance(Object source, @MappingTarget Object target) {
    9. knownInstances.put( source, target );
    10. }
    11. }

    三、MapToObject互转

    1. public class Source {
    2. private Map<String, Object> map;
    3. }
    4. public class Target {
    5. private String ip;
    6. private String server;
    7. }
    8. @Mapper( uses = MappingUtil.class )
    9. public interface SourceTargetMapper {
    10. SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
    11. @Mapping(source = "map", target = "ip", qualifiedBy = Ip.class )
    12. @Mapping(source = "map", target = "server", qualifiedBy = Server.class )
    13. Target toTarget(Source s);
    14. }
    15. public class MappingUtil {
    16. @Qualifier
    17. @Target(ElementType.METHOD)
    18. @Retention(RetentionPolicy.SOURCE)
    19. public @interface Ip {
    20. }
    21. @Qualifier
    22. @Target(ElementType.METHOD)
    23. @Retention(RetentionPolicy.SOURCE)
    24. public static @interface Server {
    25. }
    26. @Ip
    27. public String ip(Map<String, Object> in) {
    28. return (String) in.get("ip");
    29. }
    30. @Server
    31. public String server(Map<String, Object> in) {
    32. return (String) in.get("server");
    33. }
    34. }
    35. @Test
    36. public void testMapperOnExistingIpAndServer() {
    37. Map<String, Object> map = new HashMap<>();
    38. map.put("ip", "127.0.0.1");
    39. map.put("server", "168.192.1.1");
    40. Source s = new Source(map);
    41. Target t = SourceTargetMapper.MAPPER.toTarget( s );
    42. System.out.println(JSONUtil.toJsonStr(t));
    43. //{"server":"168.192.1.1","ip":"127.0.0.1"}
    44. }
    1. //下面的例子是从map中映射字段到object
    2. public class Employee {
    3. private String id;
    4. private String name;
    5. private Department department;
    6. }
    7. public class Department {
    8. private String id;
    9. private String name;
    10. }
    11. @Mapper
    12. public interface MapToBeanMapper {
    13. MapToBeanMapper INSTANCE = Mappers.getMapper(MapToBeanMapper.class);
    14. @Mapping(target = "department", ignore = true)
    15. Employee fromMap(Map<String, String> map);
    16. @AfterMapping
    17. default void finishEmployee(@MappingTarget Employee employee, Map<String, String> map) {
    18. employee.setDepartment(fromMapToDepartment(map));
    19. }
    20. @Mapping(target = "id", source = "did")
    21. @Mapping(target = "name", source = "dname")
    22. Department fromMapToDepartment(Map<String, String> map);
    23. }
    24. @Test
    25. public void shouldMapMapToBean() {
    26. Map<String, String> map = new HashMap<>();
    27. map.put("id", "1234");
    28. map.put("name", "Tester");
    29. map.put("did", "4321"); //Department Id
    30. map.put("dname", "Test");// Depart name
    31. Employee employee = MapToBeanMapper.INSTANCE.fromMap(map);
    32. }

    四、SPI实现

    1. //主要是用于一些特定的规则处理
    2. step-1
    3. public class CustomAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
    4. @Override
    5. public boolean isGetterMethod(ExecutableElement method) {
    6. String methodName = method.getSimpleName().toString();
    7. return !methodName.startsWith( "with" ) && method.getReturnType().getKind() != TypeKind.VOID;
    8. }
    9. @Override
    10. public boolean isSetterMethod(ExecutableElement method) {
    11. String methodName = method.getSimpleName().toString();
    12. return methodName.startsWith( "with" ) && methodName.length() > 4;
    13. }
    14. @Override
    15. public String getPropertyName(ExecutableElement getterOrSetterMethod) {
    16. String methodName = getterOrSetterMethod.getSimpleName().toString();
    17. return Introspector.decapitalize( methodName.startsWith( "with" ) ? methodName.substring( 4 ) : methodName );
    18. }
    19. }
    1. step-2
    2. 在 resources/META-INF.services目录下新建文件
    3. org.mapstruct.example.spi.CustomAccessorNamingStrategy
    4. 文件内容
    5. org.mapstruct.example.spi.CustomAccessorNamingStrategy

    五、lombok配置

    1. 这主要是配置,以指定comiple的顺序
    2. <!--处理lombok和mapstruft 加载顺序的问题 防止在生成的实体没有属性-->
    3. <plugins>
    4. <plugin>
    5. <groupId>org.apache.maven.plugins</groupId>
    6. <artifactId>maven-compiler-plugin</artifactId>
    7. <version>3.8.1</version>
    8. <configuration>
    9. <source>1.8</source>
    10. <target>1.8</target>
    11. <annotationProcessorPaths>
    12. <path>
    13. <groupId>org.projectlombok</groupId>
    14. <artifactId>lombok</artifactId>
    15. <version>${lombok.version}</version> //1.18.20 || 1.18.20
    16. </path>
    17. <path>
    18. <groupId>org.mapstruct</groupId>
    19. <artifactId>mapstruct-processor</artifactId>
    20. <version>${mapstruct.version}</version> //1.4.2.Final || 1.5.0.Beta2
    21. </path>
    22. <!-- additional annotation processor required as of Lombok 1.18.16 -->
    23. <path>
    24. <groupId>org.projectlombok</groupId>
    25. <artifactId>lombok-mapstruct-binding</artifactId>
    26. <version>0.1.0</version> //0.1.0 || 0.2.0
    27. </path>
    28. </annotationProcessorPaths>
    29. </configuration>
    30. </plugin>
    31. </plugins>
  • 相关阅读:
    使用LDA(线性判别公式)进行iris鸢尾花的分类
    简单理解旁路电容和去耦电容
    5.浮点数及其运算
    238. 除自身以外数组的乘积
    OpenCV(二十八):连通域分割
    RabbitMQ生产故障问题分析
    DeepStream-gst-dsexample
    Vue3中的setup和ref && reactive函数
    红队内网攻防渗透:内网渗透之内网对抗:横向移动篇&Kerberos&委派安全&RBCD资源&Operators组成员&HTLMRelay结合
    PyCharm使用心得体会1
  • 原文地址:https://blog.csdn.net/liudonglovehemin/article/details/133545231