【问题标题】:MapStruct: initialize using updateMethod(), create even though source is nullMapStruct:使用 updateMethod() 进行初始化,即使源为 null 也可以创建
【发布时间】:2022-07-27 17:49:14
【问题描述】:

有人可以告诉我如何(或者是否有可能)强制更新方法创建目标(如果它为空)?

我想实现这样的目标:

    @BeforeMapping
    @Mapping(source = "inputBy", target = "tactical.inputBy")
    default BCSecuritiesTrade updateOrCreateInputBy(String inputBy, @MappingTarget BCSecuritiesTrade bcSecuritiesTrade){
        return bcSecuritiesTrade != null? bcSecuritiesTrade:new BCSecuritiesTrade();
    }

但这总是返回新实例并且不进行映射。

我想要一个方法,当它存在时更新“目标”并在输入 null 时创建新的“目标”对象。

此外,当“源”对象为空时,它不应返回空值,但“目标”对象或如果“目标”对象为空则创建新对象。当前方法在 "source" 为 null 时返回 null。

非常感谢!

【问题讨论】:

    标签: java mapstruct


    【解决方案1】:

    我还没有找到开箱即用的解决方案。 根据documentation,似乎 MapStruct 被设计为仅将updateMethod 用于现有实例。
    我通过其他自定义方法解决了问题。

    MapStruct 版本 1.4.2.Final

    @Mapper
    public interface BCSecuritiesTradeMapper {
        BCSecuritiesTradeMapper INSTANCE = Mappers.getMapper(BCSecuritiesTradeMapper.class);
    
        @Mapping(source = "inputBy", target = "tactical.inputBy")
        BCSecuritiesTrade updateInputBy(String inputBy, @MappingTarget BCSecuritiesTrade bcSecuritiesTrade);
    
        default BCSecuritiesTrade updateOrCreateInputBy(String inputBy, BCSecuritiesTrade bcSecuritiesTrade) {
            if (bcSecuritiesTrade == null) {
                bcSecuritiesTrade = new BCSecuritiesTrade();
            }
            if (inputBy == null) {
                return bcSecuritiesTrade;
            }
            return updateInputBy(inputBy, bcSecuritiesTrade);
        }
    }
    

    生成的代码:

    public class BCSecuritiesTradeMapperImpl implements BCSecuritiesTradeMapper {
        @Override
        public BCSecuritiesTrade updateInputBy(String inputBy, BCSecuritiesTrade bcSecuritiesTrade) {
            if ( inputBy == null ) {
                return null;
            }
            if ( bcSecuritiesTrade.tactical == null ) {
                bcSecuritiesTrade.tactical = new Tactical();
            }
            stringToTactical( inputBy, bcSecuritiesTrade.tactical );
    
            return bcSecuritiesTrade;
        }
    
        protected void stringToTactical(String string, Tactical mappingTarget) {
            if ( string == null ) {
                return;
            }
            mappingTarget.inputBy = string;
        }
    }
    

    MapStruct 版本 1.5.0.RC1
    新版本有更好的实现。如果sourcenull,则返回target,但在传递null 的情况下仍然无法创建target 对象的实例。
    自定义方法被简化但没有消除。

    @Mapper
    public interface BCSecuritiesTradeMapper {
        BCSecuritiesTradeMapper INSTANCE = Mappers.getMapper(BCSecuritiesTradeMapper.class);
    
        @Mapping(source = "inputBy", target = "tactical.inputBy")
        BCSecuritiesTrade updateInputBy(String inputBy, @MappingTarget BCSecuritiesTrade bcSecuritiesTrade);
    
        default BCSecuritiesTrade updateOrCreateInputBy(String inputBy, BCSecuritiesTrade bcSecuritiesTrade) {
            if (bcSecuritiesTrade == null) {
                bcSecuritiesTrade = new BCSecuritiesTrade();
            }
            return updateInputBy(inputBy, bcSecuritiesTrade);
        }
    }
    

    生成的代码:

    public class BCSecuritiesTradeMapperImpl implements BCSecuritiesTradeMapper {
    
        @Override
        public BCSecuritiesTrade updateInputBy(String inputBy, BCSecuritiesTrade bcSecuritiesTrade) {
            if ( inputBy == null ) {
                return bcSecuritiesTrade;
            }
            if ( bcSecuritiesTrade.tactical == null ) {
                bcSecuritiesTrade.tactical = new Tactical();
            }
            stringToTactical( inputBy, bcSecuritiesTrade.tactical );
            return bcSecuritiesTrade;
        }
    
        protected void stringToTactical(String string, Tactical mappingTarget) {
            if ( string == null ) {
                return;
            }
            mappingTarget.inputBy = string;
        }
    }
    

    单元测试:

    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.JUnit4;
    
    @RunWith(JUnit4.class)
    public class MapperTest {
        @Test
        public void test() {
            BCSecuritiesTrade bcSecuritiesTrade = BCSecuritiesTradeMapper.INSTANCE.updateOrCreateInputBy(null, null);
            Assert.assertNotNull(bcSecuritiesTrade);
            Assert.assertNull(bcSecuritiesTrade.tactical);
    
            BCSecuritiesTrade bcSecuritiesTradeUpdate = BCSecuritiesTradeMapper.INSTANCE.updateOrCreateInputBy(null, bcSecuritiesTrade);
            Assert.assertNotNull(bcSecuritiesTradeUpdate);
            Assert.assertNull(bcSecuritiesTradeUpdate.tactical);
            Assert.assertEquals(bcSecuritiesTrade, bcSecuritiesTradeUpdate);
    
            bcSecuritiesTrade = BCSecuritiesTradeMapper.INSTANCE.updateOrCreateInputBy("123", null);
            Assert.assertNotNull(bcSecuritiesTrade);
            Assert.assertEquals(bcSecuritiesTrade.tactical.inputBy, "123");
    
            bcSecuritiesTradeUpdate = BCSecuritiesTradeMapper.INSTANCE.updateOrCreateInputBy("124", bcSecuritiesTrade);
            Assert.assertNotNull(bcSecuritiesTradeUpdate);
            Assert.assertEquals(bcSecuritiesTradeUpdate.tactical.inputBy, "124");
            Assert.assertEquals(bcSecuritiesTrade, bcSecuritiesTradeUpdate);
    
        }
    }
    

    使用的实体:

    public class BCSecuritiesTrade {
        public Tactical tactical;
    }
    
    public class Tactical {
        public String inputBy;
    }
    

    替代解决方案:
    CreateUpdate 创建两个单独的方法。

    @Mapper(nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)
    public interface BCSecuritiesTradeMapper {
        BCSecuritiesTradeMapper INSTANCE = Mappers.getMapper(BCSecuritiesTradeMapper.class);
    
        @Mapping(source = "inputBy", target = "tactical.inputBy")
        BCSecuritiesTrade updateInputBy(String inputBy, @MappingTarget BCSecuritiesTrade bcSecuritiesTrade);
    
        @Mapping(source = "inputBy", target = "tactical.inputBy")
        BCSecuritiesTrade createInputBy(String inputBy);
    }
    

    【讨论】:

    • 非常感谢尤金,你的回答太棒了。它解释了我遇到的很多问题。谢谢!!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-18
    • 1970-01-01
    • 2021-02-22
    • 2019-02-17
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多