具有多个参数的 Map 结构限定名称

2022-09-02 09:15:22

我遇到过这样的情况:我的映射方法有 3 个参数,并且所有这三个参数都用于派生目标类型的一个属性。

我已经在接口中创建了一个默认的映射方法,保留了用于派生属性的逻辑,现在为了调用此方法,我可以在注释中使用。expression = "java( /*method call here*/ )"@Mapping

有没有办法用任何映射结构注释来做到这一点,比如,我尝试用表达式属性注释注释注释并使用qualifiedByName,但它不起作用:@qualifiedByName

@Mapper
public interface OneMapper {

    @Mapping(target="id", source="one.id")
    //@Mapping(target="qualified",expression = "java( checkQualified (one, projId, code) )")
    @Mapping(target="qualified",qualifiedByName="checkQualifiedNamed")
    OneDto createOne (One one, Integer projId, Integer val, String code);

    @Named("checkQualifiedNamed")
    default Boolean checkQualified (One one, Integer projId, Integer val, String code) {
        if(one.getProjectId() == projId && one.getVal() == val && one.getCode().equalsIgnoreCase(code)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;                   
    }
}

答案 1

目前,MapStruct 不支持具有多个源属性的映射方法。

但是,在您的情况下,您可以使用 from 1.2.0。据我所知,它们只是作为映射的帮助者,并且它们不用于映射目标属性。@ContextprojIdcode

所以你可以做这样的事情(理论上应该有效):

@Mapper
public interface OneMapper {

    @Mapping(target="id", source="one.id")
    @Mapping(target="qualified", qualifiedByName="checkQualifiedNamed")
    OneDto createOne (One one, @Context Integer projId, @Context String code);

    @Named("checkQualifiedNamed")
    default Boolean checkQualified (One one, @Context Integer projId, @Context String code) {
        if(one.getProjectId() == projId && one.getCode().equalsIgnoreCase(code)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;                   
    }
}

另一种替代方法是将所有这些属性提取到一个单独的类中,并将其传递(这将允许同一类型的多个参数)。

该类将如下所示:

public class Filter {

    private final Integer projId;
    private final Integer val;
    private final String code;

    public Filter (Integer projId, Integer val, String code) {
        this.projId = projId;
        this.val = val;
        this.code = code;
    }

    //getters
}

然后,您的映射器将如下所示:

@Mapper
public interface OneMapper {

    @Mapping(target="id", source="one.id")
    @Mapping(target="qualified", qualifiedByName="checkQualifiedNamed")
    OneDto createOne (One one, @Context Filter filter);

    @Named("checkQualifiedNamed")
    default Boolean checkQualified (One one, @Context Filter filter) {
        if(one.getProjectId() == filter.getProjId() && one.getVal() == filter.getVal() && one.getCode().equalsIgnoreCase(filter.getCode())) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;                   
    }
}

然后,您可以像这样调用映射器:mapper.createOne(one, new Filter(projId, val, code));


答案 2

从版本1.2开始,它受到支持:http://mapstruct.org/documentation/stable/reference/html/#mappings-with-several-source-parameters

例如:

@Mapping(source = "person.description", target = "description")
@Mapping(source = "address.houseNo", target = "houseNumber")
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);

更新

由于Mapstruct允许将多个源参数映射到单个目标中,因此我建议从映射器中提取方法,而不是事先计算结果,并使用check合格方法的结果调用映射器。Mapstruct 是一个映射库,在执行任意逻辑方面并不出色。这并非不可能,但就我个人而言,我不认为它在你的特定情况下增加了价值。checkQualified

提取逻辑后,您的映射器可能如下所示:

@Mapper
public interface OneMapper {
    OneDto toOneDto(One one, Boolean qualified);
}

映射器可以像这样使用:

One one = new One(1, 10, 100, "one");
boolean qualified = checkQualified(one, 10, 100, "one");
boolean notQualified = checkQualified(one, 10, 100, "two");
OneDto oneDto = mapper.toOneDto(one, isQualified);

有关完整示例,请参阅:https://github.com/phazebroek/so-mapstruct/blob/master/src/main/java/nl/phazebroek/so/MapStructDemo.java


推荐