• 基于grpc从零开始搭建一个准生产分布式应用(6) - 03 - MapStruct高级映射


    一、对象工厂

    在映射成目标对象时,创建目标对象实例,可以使用@ObjectFactory注解的方法取代调用默认的构造方法创建目标对象,工厂方法可以是无参返回类型是目标类型的方法,无参的工厂方法可以不设置@ObjectFactory注解;或有参返回类型是目标类型的方法,参数可以用@TargetType或@Context注解。

    • 为避免返回类型有泛型时的匹配错误,特别是继承List的类的情况下,不建议使用无参的工厂方法。
    • 例如protobuf中的repeated·string生成的ProtocolStringList要在CollectionMappingStrategy.ACCESSOR_ONLY策略下使用。

    1.1、自定义工厂@ObjectFactory

    可用来生成默认source。

    1. @Data
    2. public class TestFivePO {
    3. private TestFourPO test;
    4. private TestPO testPO;
    5. }
    6. @Mapper
    7. public class BaseMapper {
    8. @ObjectFactory-------注解
    9. public TestSixBO createSixBO() {
    10. TestSixBO testSixBO = new TestSixBO();
    11. testSixBO.setId(1L);
    12. return testSixBO;
    13. }
    14. }
    15. @Mapper(uses = BaseMapper.class)
    16. public interface TestMapper {
    17. @Mapping(target = "test.id", ignore = true)
    18. TestSevenBO toBOS(TestFivePO testPO);
    19. }
    20. @Component
    21. public class TestMapperImpl implements TestMapper {
    22. @Autowired
    23. private BaseMapper baseMapper;
    24. @Override
    25. public TestSevenBO toBOS(TestFivePO testPO) {
    26. if ( testPO == null ) {
    27. return null;
    28. }
    29. TestSevenBO testSevenBO = new TestSevenBO();
    30. testSevenBO.setTest( testFourPOToTestSixBO( testPO.getTest() ) );
    31. return testSevenBO;
    32. }
    33. protected TestSixBO testFourPOToTestSixBO(TestFourPO testFourPO) {
    34. if ( testFourPO == null ) {
    35. return null;
    36. }
    37. TestSixBO testSixBO = baseMapper.createSixBO();//只用在了这行。
    38. testSixBO.setName( testFourPO.getName() );
    39. testSixBO.setCreateTime( testFourPO.getCreateTime() );
    40. return testSixBO;
    41. }
    42. }

    1.2、泛型工厂@TargetType

    1. @Mapper
    2. public class BaseMapper {
    3. @ObjectFactory
    4. public extends BaseBO> T createSixBO(@TargetType Class tClass) throws IllegalAccessException, InstantiationException {
    5. T t = tClass.newInstance();
    6. t.setId(3L);
    7. return t;
    8. }
    9. }
    10. testSevenBO.setTest( testFourPOToTestSixBO( testPO.getTest() ) );

    二、高级映射选项

    2.1、默认值defaultValue

    1. //给@Mapping的属性defaultValue设置一个值,若果源字段为空,那么目标字段就为此默认值
    2. @Mapping(target = "name", source = "name", defaultValue = "noName")
    3. TestBO toBO(TestPO testPO);

    2.2、表达式expression和defaultExpression

    1. @Mapping(target = "name", expression = "java(testPO.getName() + \"BO\")")
    2. @Mapping(target = "totalPrice", expression = "java(testThreePO.getTotalPrice().toString() + \"元\")")
    3. TestBO toBO(TestPO testPO);
    4. 还可以设置@Mapping的defaultExpression设置默认表达式,在source的值为null时,调用此默认表达式代码。
    5. @Mapping(target = "name", source = "name", defaultExpression = "java(StringBOUtils.toBOString(testPO.getName()))")
    6. @Mapping(target = "state", expression = "java(net.shukun.universe.core.common.DoctorMapStructUtil.doctorId1(var1.getState()))" )
    7. //这块需要注意包装类型
    8. @Mapping(target = "state", expression = "java(DoctorMapStructUtil.getStateByName(var1.getState().getValue()).getCode())" )
    1. public class StringBOUtils {
    2. public static String toBOString(String poString) {
    3. return poString + "BO";
    4. }
    5. }
    6. //使用 imports
    7. @Mapper(uses = BaseMapper.class, imports = {StringBOUtils.class})
    8. public interface TestMapper {
    9. @Mapping(target = "name", expression = "java(StringBOUtils.toBOString(testPO.getName()))")
    10. TestBO toBO(TestPO testPO);
    11. }
    1. //还可以设置@Mapping的defaultExpression设置默认表达式,在source的值为null时,调用此默认表达式代码
    2. @Mapping(target = "name", source = "name", defaultExpression = "java(StringBOUtils.toBOString(testPO.getName()))")
    3. TestBO toBO(TestPO testPO);

    2.3、确定映射结果的具体类型resultType属性

    如果映射的结果是父类,又存在不同子类的映射方法,编译会报错,此时需要使用@Mapping或@BeanMapping的resultType指定映射结果的具体类型。

    1. @Mapper
    2. public class BaseMapper {
    3. public TestSixBO createSixBO() {
    4. return new TestSixBO();
    5. }
    6. public TestEightBO createEightBO() {
    7. return new TestEightBO();
    8. }
    9. }
    10. @Mapper(uses = {BaseMapper.class})
    11. public interface TestMapper {
    12. @BeanMapping(resultType = TestEightBO.class)
    13. BaseBO toBO(TestFourPO testFourPO);
    14. }

    2.4、NULL映射控制

    2.4.1、源对象NULL映射

    当映射的source对象为null时可以通过@BeanMapping、@IterableMapping、@MapMapping(优先级最高),@Mappe,@MappingConfig(优先级最低)的nullValueMappingStrategy策略来控制NULL值的映射结果。策略值有:

    • NullValueMappingStrategy.RETURN_NULL(默认,源为null,目标直接返回null);
    • NullValueMappingStrategy.RETURN_DEFAULT(返回一个对象,除填充的常量和表达式,其他字段属性为空;集合返回一个对象,size为0)。

    @IterableMapping:

    集合使用了NullValueMappingStrategy.RETURN_DEFAULT策略所以源为NULL时返回return new ArrayList();bean对象使用默认策略所以源为NULL时返回return null。

    1. @Mapper
    2. public interface TestMapper {
    3. @IterableMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)
    4. List<TestThreeBO> toBO(List<TestFivePO> testFivePO);
    5. }
    6. @Component
    7. public class TestMapperImpl implements TestMapper {
    8. @Override
    9. public List<TestThreeBO> toBO(List<TestFivePO> testFivePO) {
    10. if ( testFivePO == null ) {
    11. return new ArrayList<TestThreeBO>();
    12. }
    13. List<TestThreeBO> list = new ArrayList<TestThreeBO>( testFivePO.size() );
    14. for ( TestFivePO testFivePO1 : testFivePO ) {
    15. list.add( testFivePOToTestThreeBO( testFivePO1 ) );
    16. }
    17. return list;
    18. }
    19. protected TestBO testPOToTestBO(TestPO testPO) {
    20. if ( testPO == null ) {
    21. return null;
    22. }
    23. TestBO testBO = new TestBO();
    24. testBO.setId( testPO.getId() );
    25. testBO.setName( testPO.getName() );
    26. if ( testPO.getPrice() != null ) {
    27. testBO.setPrice( testPO.getPrice().toString() );
    28. }
    29. if ( testPO.getCreateTime() != null ) {
    30. testBO.setCreateTime( new SimpleDateFormat().format( testPO.getCreateTime() ) );
    31. }
    32. return testBO;
    33. }
    34. protected TestThreeBO testFivePOToTestThreeBO(TestFivePO testFivePO) {
    35. if ( testFivePO == null ) {
    36. return null;
    37. }
    38. TestThreeBO testThreeBO = new TestThreeBO();
    39. testThreeBO.setTest( testPOToTestBO( testFivePO.getTest() ) );
    40. return testThreeBO;
    41. }
    42. }

    @BeanMapping

    1. @Mapper
    2. public interface TestMapper {
    3. @BeanMapping(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)
    4. @Mapping(target = "id", constant = "0L")
    5. @Mapping(target = "name", expression = "java(testPO.getName() + \"BO\")")
    6. TestBO toBO(TestPO testPO);
    7. }
    8. @Component
    9. public class TestMapperImpl implements TestMapper {
    10. @Override
    11. public TestBO toBO(TestPO testPO) {
    12. TestBO testBO = new TestBO();
    13. if ( testPO != null ) {
    14. if ( testPO.getPrice() != null ) {
    15. testBO.setPrice( testPO.getPrice().toString() );
    16. }
    17. else {
    18. testBO.setPrice( testPO.getPrice() + "BO" );
    19. }
    20. if ( testPO.getCreateTime() != null ) {
    21. testBO.setCreateTime( new SimpleDateFormat().format( testPO.getCreateTime() ) );
    22. }
    23. }
    24. testBO.setId( (long) 0L );
    25. testBO.setName( testPO.getName() + "BO" );
    26. return testBO;
    27. }
    28. }
    2.4.2、在更新时源对象属性NULL映射

    在使用@MappingTarget更新目标时,可以设置@Mapping、@BeanMapping(优先级最高),@Mapper或@MappingConfig(优先级最底)的nullValuePropertyMappingStrategy属性值,用于设置当源对象属性为null时,如何设置目标属性的值。nullValuePropertyMappingStrategy的值有:

    • NullValuePropertyMappingStrategy.SET_TO_DEFAULT:源属性为null,目标属性会被赋予特定的默认值。List被赋予ArrayList,Map被赋予HashMap,数组就是空数组,String是“”,基本类型或包装类是0或false,对象是空的构造方法。
    • NullValuePropertyMappingStrategy.IGNORE:源属性为null,忽略目标属性的设值。
    • NullValuePropertyMappingStrategy.SET_TO_NULL:默认,源属性是null,目标属性也是null。
    1. @Mapper
    2. public interface TestMapper {
    3. @Mapping(target = "name", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
    4. @Mapping(target = "price", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
    5. void toBO(TestPO testPO, @MappingTarget TestBO testBO);
    6. }
    7. @Component
    8. public class TestMapperImpl implements TestMapper {
    9. @Override
    10. public void toBO(TestPO testPO, TestBO testBO) {
    11. if ( testPO == null ) {
    12. return;
    13. }
    14. if ( testPO.getName() != null ) {
    15. testBO.setName( testPO.getName() );
    16. }
    17. else {
    18. testBO.setName( "" );
    19. }
    20. if ( testPO.getPrice() != null ) {
    21. testBO.setPrice( testPO.getPrice().toString() );
    22. }
    23. testBO.setId( testPO.getId() );
    24. if ( testPO.getCreateTime() != null ) {
    25. testBO.setCreateTime( new SimpleDateFormat().format( testPO.getCreateTime() ) );
    26. }
    27. else {
    28. testBO.setCreateTime( null );
    29. }
    30. }
    31. }

    三、映射扩展

    3.1、装饰器映射

    在进行映射时可以通过装饰器模式,为目标对象设置一些,不能由源对象直接生成或者源对象没有的属性。spring注入策略的装饰器映射使用@DecoratedWith注解制定装饰器。装饰器中使用@Qualifier("delegate")指定注入的bean。

    1. @Mapper
    2. @DecoratedWith(TestDecotator.class)
    3. public interface TestMapper {
    4. TestBO toTestBO(TestPO testPO);
    5. }
    6. public abstract class TestDecorator implements TestMapper {
    7. @Autowired
    8. @Qualifier("delegate")
    9. private TestMapper testMapper;
    10. @Override
    11. public TestBO toTestBO(TestPO testPO) {
    12. TestBO testBO = testMapper.toTestBO(testPO);
    13. testBO.setName("1111");//这处应该是个组合关系,用来设计一些特定的不能由源对象直接映射的赋值操作
    14. return testBO;
    15. }
    16. }
    17. ================================生成的代码如下================================
    18. class TestMapperImpl extends TestDecorator implements TestMapper {
    19. private final TestMapper delegate;
    20. public TestMapperImpl() {
    21. this( new TestMapperImpl_() );
    22. }
    23. private TestMapperImpl(TestMapperImpl_ delegate) {
    24. this.delegate = delegate;
    25. }
    26. }
    27. class TestMapperImpl_ implements TestMapper {
    28. @Override
    29. public TestBO toTestBO(TestPO testPO) {
    30. if ( testPO == null ) {
    31. return null;
    32. }
    33. TestBO testBO = new TestBO();
    34. testBO.setId( testPO.getId() );
    35. testBO.setName( testPO.getName() );
    36. testBO.setPrice( testPO.getPrice() );
    37. testBO.setCreteTime( testPO.getCreteTime() );
    38. return testBO;
    39. }
    40. }

    3.2、映射前置/后置方法

    可以在抽象mapper类、Mapper#uses引入的类或被@Context注解的上下文对象类中设置映射前后的回调方法。@BeforeMapping注解的方法是前置方法,@AfterMapping注解的方法是后置方法。如果前后置方法具有参数,返回的类型能被赋予映射方法的返回类型并且参数都可以用源/目标参数获取,才会调用前后置方法。

    前后置方法中用@MappingTarget注解的参数获得的是目标实例,@TargetType获取的是目标类型,@Context可以获取上下文对象,其他的参数被赋予源参数。然后前后置方法不是void的,返回的值不为null的情况下将作为映射方法的返回值。同样,若前后置方法能匹配到多个,将会都调用,可以通过给前置方法添加@Named和映射方法上添加@BeanMapping#qualifiedByName制定要调用的前后置方法;一旦使用了@BeanMapping#qualifiedByName就必须指定自己选用调用的所有前后置方法的@Named名。不带@MappingTarget注解参数的@BeforeMapping会在源参数进行null检查并且构造新的目标bean之前调用;带@MappingTarget注解参数的@BeforeMapping会在构造新的目标bean之后调用;@AfterMapping会在return前最后调用。在使用建造者时,@BeforeMapping、@AfterMapping中要想获取目标对象,@MappingTarget注解的就必须是建造者。

    1. @Mapper
    2. @Named("baseMapper")
    3. public class BaseMapper {
    4. @BeforeMapping
    5. @Named("before")
    6. public void before(BasePO basePO, @MappingTarget BaseBO baseBO) {
    7. System.out.println(basePO);
    8. System.out.println(baseBO);
    9. }
    10. @AfterMapping
    11. public T after(@TargetType Class clazz, @Context ThreadLocalContext threadLocalContext){
    12. System.out.println(threadLocalContext);
    13. T t = null;
    14. try {
    15. t = clazz.newInstance();
    16. } catch (InstantiationException | IllegalAccessException e) {
    17. e.printStackTrace();
    18. }
    19. return t;
    20. }
    21. }
    22. @Data
    23. public class ThreadLocalContext {
    24. private ThreadLocal threadLocal;
    25. public ThreadLocalContext() {
    26. threadLocal = new ThreadLocal<>();
    27. }
    28. @BeforeMapping
    29. @Named("before2")
    30. public static void before2(BasePO basePO, @MappingTarget BaseBO baseBO) {
    31. System.out.println(basePO);
    32. System.out.println(baseBO);
    33. }
    34. }
    35. @Mapper(uses = BaseMapper.class)
    36. public interface TestMapper {
    37. @BeanMapping(qualifiedByName = { "baseMapper"})
    38. TestSixBO toTestBO(TestFourPO testPO, @Context ThreadLocalContext threadLocalContext);
    39. }
    40. @Component
    41. public class TestMapperImpl implements TestMapper {
    42. @Autowired
    43. private BaseMapper baseMapper;
    44. @Override
    45. public TestSixBO toTestBO(TestFourPO testPO, ThreadLocalContext threadLocalContext) {
    46. if ( testPO == null ) {
    47. return null;
    48. }
    49. TestSixBO testSixBO = new TestSixBO();
    50. baseMapper.before( testPO, testSixBO );
    51. testSixBO.setId( testPO.getId() );
    52. testSixBO.setName( testPO.getName() );
    53. if ( testPO.getCreateTime() != null ) {
    54. testSixBO.setCreateTime( new SimpleDateFormat().format( testPO.getCreateTime() ) );
    55. }
    56. TestSixBO target = baseMapper.after( TestSixBO.class, threadLocalContext );
    57. if ( target != null ) {
    58. return target;
    59. }
    60. return testSixBO;
    61. }
    62. }
      1. public interface LicenseModelTranslator {
      2. LicenseModelTranslator INSTANCE = Mappers.getMapper(LicenseModelTranslator.class);
      3. @Mapping(target = "activationInfo",ignore = true)
      4. @Mapping(target = "operatorUid", source = "operatorUserId")
      5. @Mapping(target = "createdAt", source = "ctime")
      6. LicenseActivationRecordBo toActivationRecordBo(ActivationRecordEntity var1);
      7. List<LicenseActivationRecordBo> toActivationRecordBos(List<ActivationRecordEntity> var1);
      8. @AfterMapping
      9. default void setLicenseActivationInfoBo(@MappingTarget LicenseActivationRecordBo bo, ActivationRecordEntity var1) {
      10. List<LicenseActivationInfoBo> activationInfo = JSONUtil.toList(var1.getActivationInfo(), LicenseActivationInfoBo.class);
      11. bo.setActivationInfo(activationInfo);
      12. }
      13. }

      3.3、父子结构映射

      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. }
      3.3.1、循环嵌套对象调用前后置方法
      1. @Data
      2. public class TestBOS {
      3. private TestBOS testS;
      4. private List list;
      5. }
      6. @Data
      7. public class TestPOS {
      8. private TestPOS testS;
      9. private List list;
      10. }
      11. @Mapper
      12. public class BaseMapper {
      13. @BeforeMapping
      14. public T before(Object source, @TargetType Class targetType) {
      15. T t;
      16. try {
      17. t = targetType.newInstance();
      18. } catch (InstantiationException | IllegalAccessException e) {
      19. return null;
      20. }
      21. return t;
      22. }
      23. }
      24. @Mapper(uses = BaseMapper.class)
      25. public interface TestMapper {
      26. TestBOS toBean(TestPOS testPOS);
      27. }

      四、高级映射属性

      4.1、映射配置继承@InheritConfiguration

      @InheritConfiguration可以继承@Mapping,@BeanMapping,@IterableMapping的映射规则。@InheritConfiguration注解的方法上,有需要映射的字段,它会搜索有相同配置的映射,找到了直接复用此映射;若找到多个方法上都有满足此映射的配置,需要制定@InheritConfiguration#name的值,制定继承方法的映射。

      1. @Data
      2. @ToString
      3. public class TestPO {
      4. private String name;
      5. }
      6. @Data
      7. @ToString
      8. public class TestBO {
      9. private String nickName;
      10. }
      11. @Data
      12. public class TestTwoBO {
      13. private String realName;
      14. }
      15. @Mapper
      16. public interface TestMapper {
      17. @Mapping(target = "nickName", source = "name", defaultValue = "nickName")
      18. TestBO toTestBO(TestPO testPO);
      19. @Mapping(target = "nickName", source = "name", defaultValue = "realName")
      20. TestBO toTestTwoBO(TestPO testPO);
      21. @InheritConfiguration(name = "toTestTwoBO")
      22. TestBO toTestThreeBO(TestPO testPO); //toTestThreeBO的实现方法在设置nickName时,继承的toTestTwoBO方法的映射配置。
      23. }

      4.2、逆映射@InheritInverseConfiguration

      当我们定义了一种对象到另一种对象的映射后,可以通过@InheritInverseConfiguration直接进行逆映射。可以看到实现的toTestBO方法中的price->priceString使用的就是toTestPO中priceString->price的逆映射,但是正映射的@Mapping#expression、#defaultExpression、#defaultValue和#constant会被逆映射忽略,就如其中的默认值“-1”在逆映射中不存在;此外某个字段的逆映射可以被ignore,expression或constant覆盖,就如name->nameString;在正映射的createTimeString->createTime上设置了ignore,若此时同时制定了source,则逆映射会继承ignore,不用再重新设置。@InheritConfiguration的优先级高于@InheritInverseConfiguration。

      1. @Data
      2. @ToString
      3. public class TestPO {
      4. private Long id;
      5. private String nameString;
      6. private BigDecimal priceString;
      7. private Date createTimeString;
      8. }
      9. //InheritInverseConfiguration 这个注解是一个相对的操作,必须要有前提此处才会有用,比如下例中必须有TestBO toTestBO(TestPO testPO)才可以,也就是为了少写
      10. //映射代码,如果有多个类似的话,可以用@InheritInverseConfiguration( name = "toTestBO" )指定一个原实现方法名
      11. @Mapper
      12. public interface TestMapper {
      13. @Mapping(target = "price", source = "priceString", defaultValue = "-1")
      14. @Mapping(target = "name", source = "nameString")
      15. @Mapping(target = "createTime", source = "createTimeString", ignore = true)
      16. TestBO toTestBO(TestPO testPO);
      17. @InheritInverseConfiguration
      18. @Mapping(target = "nameString", constant = "namePO")
      19. TestPO toTestBO(TestBO testBO);
      20. }
      21. @Component
      22. public class TestMapperImpl implements TestMapper {
      23. @Override
      24. public TestBO toTestBO(TestPO testPO) {
      25. if ( testPO == null ) {
      26. return null;
      27. }
      28. TestBO testBO = new TestBO();
      29. if ( testPO.getPriceString() != null ) {
      30. testBO.setPrice( testPO.getPriceString().toString() );
      31. }
      32. else {
      33. testBO.setPrice( "-1" );
      34. }
      35. testBO.setName( testPO.getNameString() );
      36. testBO.setId( testPO.getId() );
      37. return testBO;
      38. }
      39. @Override
      40. public TestPO toTestBO(TestBO testBO) {
      41. if ( testBO == null ) {
      42. return null;
      43. }
      44. TestPO testPO = new TestPO();
      45. if ( testBO.getPrice() != null ) {
      46. testPO.setPriceString( new BigDecimal( testBO.getPrice() ) );
      47. }
      48. testPO.setId( testBO.getId() );
      49. testPO.setNameString( "namePO" );
      50. return testPO;
      51. }
      52. }

      4.3、配置共享

      @MapperConfig注解的接口就是共享配置,可以在@Mapper#config指定共享配置,@MapperConfig中的属性和@Mapper相同,@Mapper中的属性会覆盖@MapperConfig。共享配置中可以设置原型映射,也可以是父类映射,再通过@MapperConfig、@Mapper的mappingInheritanceStrategy就可以实现原型映射的继承。mappingInheritanceStrategy的值有:

      • MappingInheritanceStrategy.EXPLICIT:默认,要想继承原型映射必须使用@InheritConfiguration或@InheritInverseConfiguration注解方法,且此方法的源类型和目标类型要能赋予原型映射类型;
      • MappingInheritanceStrategy.AUTO_INHERIT_FROM_CONFIG:不需要@InheritConfiguration注解方法,只需要满足类型条件就能继承,但只能是正映射;
      • MappingInheritanceStrategy.AUTO_INHERIT_REVERSE_FROM_CONFIG:不需要@InheritInverseConfiguration注解方法,只需要满足类型条件就能继承,但只能是逆映射;
      • MappingInheritanceStrategy.AUTO_INHERIT_ALL_FROM_CONFIG:不需要@InheritInverseConfiguration注解方法,只需要满足类型条件就能继承,正/逆映射都可以。

      以上也都要注意映射类型冲突,冲突同样需要指明name属性。

      1. @Data
      2. @ToString
      3. public class BaseBO {
      4. private Long id;
      5. private String name;
      6. private String createTimeString;
      7. }
      8. @MapperConfig
      9. public interface BaseConfig {
      10. @Mapping(target = "createTimeString", source = "createTime")
      11. BaseBO toTestBaseBO(BasePO basePO);
      12. }
      4.3.1、MappingInheritanceStrategy.EXPLICIT

      共享配置的原型映射并不会生成单独的实现方法。虽然默认继承策略支持正/逆,但是引入共享配置,且mapper中正映射能继承原型映射的情况下,再设置逆映射方法,就必须制定name属性,否则同样有冲突报错。

      1. @Mapper(config = BaseConfig.class, mappingInheritanceStrategy = MappingInheritanceStrategy.EXPLICIT)
      2. public interface TestMapper {
      3. @InheritConfiguration
      4. void updateBO(TestFourPO testFourPO, @MappingTarget TestSixBO testSixBO);
      5. @InheritInverseConfiguration(name = "toTestBaseBO")
      6. void updatePO(TestSixBO testSixBO, @MappingTarget TestFourPO testFourPO);
      7. }
      8. @Component
      9. public class TestMapperImpl implements TestMapper {
      10. @Override
      11. public void updateBO(TestFourPO testFourPO, TestSixBO testSixBO) {
      12. if ( testFourPO == null ) {
      13. return;
      14. }
      15. if ( testFourPO.getCreateTime() != null ) {
      16. testSixBO.setCreateTimeString( new SimpleDateFormat().format( testFourPO.getCreateTime() ) );
      17. }
      18. else {
      19. testSixBO.setCreateTimeString( null );
      20. }
      21. testSixBO.setId( testFourPO.getId() );
      22. testSixBO.setName( testFourPO.getName() );
      23. }
      24. @Override
      25. public void updatePO(TestSixBO testSixBO, TestFourPO testFourPO) {
      26. if ( testSixBO == null ) {
      27. return;
      28. }
      29. try {
      30. if ( testSixBO.getCreateTimeString() != null ) {
      31. testFourPO.setCreateTime( new SimpleDateFormat().parse( testSixBO.getCreateTimeString() ) );
      32. }
      33. else {
      34. testFourPO.setCreateTime( null );
      35. }
      36. }
      37. catch ( ParseException e ) {
      38. throw new RuntimeException( e );
      39. }
      40. testFourPO.setId( testSixBO.getId() );
      41. testFourPO.setName( testSixBO.getName() );
      42. }
      43. }
      4.3.2、MappingInheritanceStrategy.AUTO_INHERIT_FROM_CONFIG
      1. @Mapper(config = BaseConfig.class, mappingInheritanceStrategy = MappingInheritanceStrategy.AUTO_INHERIT_FROM_CONFIG)
      2. public interface TestMapper {
      3. void updateBO(TestFourPO testFourPO, @MappingTarget TestSixBO testSixBO);
      4. }
      5. @Component
      6. public class TestMapperImpl implements TestMapper {
      7. @Override
      8. public void updateBO(TestFourPO testFourPO, TestSixBO testSixBO) {
      9. if ( testFourPO == null ) {
      10. return;
      11. }
      12. if ( testFourPO.getCreateTime() != null ) {
      13. testSixBO.setCreateTimeString( new SimpleDateFormat().format( testFourPO.getCreateTime() ) );
      14. }
      15. else {
      16. testSixBO.setCreateTimeString( null );
      17. }
      18. testSixBO.setId( testFourPO.getId() );
      19. testSixBO.setName( testFourPO.getName() );
      20. }
      21. }
      4.3.3、MappingInheritanceStrategy.AUTO_INHERIT_REVERSE_FROM_CONFIG
      1. @Mapper(config = BaseConfig.class, mappingInheritanceStrategy = MappingInheritanceStrategy.AUTO_INHERIT_ALL_FROM_CONFIG)
      2. public interface TestMapper {
      3. void updatePO(TestSixBO testSixBO, @MappingTarget TestFourPO testFourPO);
      4. }
      5. @Component
      6. public class TestMapperImpl implements TestMapper {
      7. @Override
      8. public void updatePO(TestSixBO testSixBO, TestFourPO testFourPO) {
      9. if ( testSixBO == null ) {
      10. return;
      11. }
      12. try {
      13. if ( testSixBO.getCreateTimeString() != null ) {
      14. testFourPO.setCreateTime( new SimpleDateFormat().parse( testSixBO.getCreateTimeString() ) );
      15. }
      16. else {
      17. testFourPO.setCreateTime( null );
      18. }
      19. }
      20. catch ( ParseException e ) {
      21. throw new RuntimeException( e );
      22. }
      23. testFourPO.setId( testSixBO.getId() );
      24. testFourPO.setName( testSixBO.getName() );
      25. }
      26. }
      4.3.4、MappingInheritanceStrategy.AUTO_INHERIT_ALL_FROM_CONFIG
      1. @Mapper(config = BaseConfig.class, mappingInheritanceStrategy = MappingInheritanceStrategy.AUTO_INHERIT_ALL_FROM_CONFIG)
      2. public interface TestMapper {
      3. void updateBO(TestFourPO testFourPO, @MappingTarget TestSixBO testSixBO);
      4. void updatePO(TestSixBO testSixBO, @MappingTarget TestFourPO testFourPO);
      5. }
      6. @Component
      7. public class TestMapperImpl implements TestMapper {
      8. @Override
      9. public void updateBO(TestFourPO testFourPO, TestSixBO testSixBO) {
      10. if ( testFourPO == null ) {
      11. return;
      12. }
      13. if ( testFourPO.getCreateTime() != null ) {
      14. testSixBO.setCreateTimeString( new SimpleDateFormat().format( testFourPO.getCreateTime() ) );
      15. }
      16. else {
      17. testSixBO.setCreateTimeString( null );
      18. }
      19. testSixBO.setId( testFourPO.getId() );
      20. testSixBO.setName( testFourPO.getName() );
      21. }
      22. @Override
      23. public void updatePO(TestSixBO testSixBO, TestFourPO testFourPO) {
      24. if ( testSixBO == null ) {
      25. return;
      26. }
      27. try {
      28. if ( testSixBO.getCreateTimeString() != null ) {
      29. testFourPO.setCreateTime( new SimpleDateFormat().parse( testSixBO.getCreateTimeString() ) );
      30. }
      31. else {
      32. testFourPO.setCreateTime( null );
      33. }
      34. }
      35. catch ( ParseException e ) {
      36. throw new RuntimeException( e );
      37. }
      38. testFourPO.setId( testSixBO.getId() );
      39. testFourPO.setName( testSixBO.getName() );
      40. }
      41. }

    63. 相关阅读:
      数据结构与算法 | 第一章:概论
      LeetCode:1480.一维数组的动态和
      如何只使用TD跟踪微分器改进普通PID控制(附完整梯形图代码)
      vue3.0运行npm run dev 报错Cannot find module node:url
      【JDBC】JDBC的基本使用
      基于CUBEMX的STM32F4 Hal库,配置LVGL(无操作系统版)
      ElasticSearch详解
      C语言入门(二)运算符和表达式
      Drogon源码剖析
      openlayers多边形的绘制的撤销/回退
    64. 原文地址:https://blog.csdn.net/liudonglovehemin/article/details/132848425