【问题标题】:Map null values to default using builder with MapStruct使用带有 MapStruct 的构建器将空值映射到默认值
【发布时间】:2020-07-08 03:00:24
【问题描述】:

我想将字段从Source映射到Target类,如果源值为null,我想根据数据类型将其转换为默认值(“”表示字符串,0表示数字类型等)。对于设置值,我不是使用常规设置器,而是生成器(使用protobuf,因此方法的名称是newBuilder()build())。

class Source {
    private final String value; // getter
}

class Target {
    private final String value;

    public static Builder newBuilder() {return new Builder()}

    public static class Builder {
        public static setValue() {/*Set the field*/}
        public static Target build() {/*Return the constructed instance*/}
}

我的映射器如下所示:

@Mapper(
    nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT,
    nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT
)
public interface TargetMapper {
    Target map(Source source);
}

使用此代码生成的映射器实现调用target.setValue(source.getValue()),而不是执行空检查并在源返回null 时设置默认值。有趣的是,当我在map 方法中添加以下注释时,实现中存在空值检查。

@Mapping(source="value", target="value", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)

这是 MapStruct 中带有构建器的错误,还是我缺少一些配置以便能够将空映射设置为默认策略,而不是在所有字段映射上复制它?

编辑:出于某种原因,将nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS 添加到类级别@Mapper 注释会添加空检查,但不会显式设置值,只是跳过对setValue 的调用。对于 protobuf,这没关系,因为此功能在库中,但对于其他实现,该字段将保持为空。

【问题讨论】:

    标签: java protocol-buffers mapstruct protobuf-java


    【解决方案1】:

    @Mapping(source="value", target="value", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)

    适用于更新方法(因此具有 @MappingTarget 注释参数的方法

    常规方法没有真正的对应物: 1. NullValueMappingStragegy 适用于 bean 参数本身。 2. NullValueCheckStragegy 确实对 bean 属性进行检查,但不返回默认值。

    命名并不是很出色,它有很长的历史。我们仍然打算在某一天调整这一点。

    一种解决方案是使用对象工厂创建构建器目标对象并使用默认值预填充它,然后让 MapStuct 有一天覆盖这些值。

    也许你可以这样做:

    @Mapper(
        // to perform a null check
        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS
    )
    public interface TargetMapper {
        Target map(Source source);
    }
    
    // to create a pre-defined object (defaults set a-priori). Not sure
    // whether this works with builders.. just try
    @ObjectFactory
    default Target.Builder create() {
    
       Target.Builder builder = Target.newBuilder();
       builder.setValueX( "someDefaultValue" );
       return builder;
    
    }
    

    【讨论】:

    • 谢谢你的解释,我现在清楚了!使用 ObjectFactory 的解决方案对我来说非常冗长,所以我将坚持使用 nullValueCheckStrategy,在这种情况下这对我来说就足够了,因为如果不调用 setter,protobuf 构建器总是设置默认值。
    猜你喜欢
    • 2018-01-03
    • 2018-12-21
    • 2019-08-17
    • 2020-03-22
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 2019-07-03
    相关资源
    最近更新 更多