intellij-idea 具有多个参数的MapStruct QualifiedByName

yqhsw0fo  于 2022-11-01  发布在  其他
关注(0)|答案(4)|浏览(480)

我遇到过这样一种情况:我的Map方法有3个参数,并且所有这三个参数都被用于派生目标类型的一个属性。
我已经在接口中创建了一个默认的Map方法,保存了用于派生属性的逻辑,现在为了调用这个方法,我可以在@Mapping注解中使用expression = "java( /*method call here*/ )"
有什么方法可以对@qualifiedByName这样的mapstruct注解执行此操作吗?我尝试注解具有expression属性的注解,并使用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;                   
    }
}
vx6bjr1n

vx6bjr1n1#

目前,MapStruct不支持具有多个源属性的Map方法。
然而,在您的情况下,您可以使用1.2.0中的@Context。据我所知,projIdcode只是作为Map的助手,它们不用于Map中的目标属性。
所以你可以这样做(理论上应该可以):

@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
}

Map器将如下所示:

@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;                   
    }
}

然后,您可以调用Map器,如下所示:mapper.createOne(one, new Filter(projId, val, code));

n53p2ov0

n53p2ov02#

自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允许将多个源参数Map到一个目标,我建议从Map器中提取checkQualified方法,并预先计算结果,然后用checkQualified方法的结果调用Map器。Mapstruct是一个 mapping 库,在执行任意逻辑方面并不出色。这不是不可能的,但就个人而言,我看不出这对你的案子有什么帮助。
使用提取的逻辑,Map器可能如下所示:

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

Map器的使用方式如下:

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

xiozqbni

xiozqbni3#

如果需要根据同一源对象的多个源字段计算单个目标字段,则可以将完整源对象而不是单个字段传递给自定义Map器函数:
示例实体:

@Entity
@Data
public class User {
    private String firstName;
    private String lastName;
}

示例DTO:

public class UserDto {
    private String fullName;
}

...和Map器...不传递单个源(firstName):

@Mapper
public abstract class UserMapper {

    @Mapping(source = "firstName", target = "fullName", qualifiedByName = "nameTofullName")
    public abstract UserDto userEntityToUserDto(UserEntity userEntity);

    @Named("nameToFullName")
    public String nameToFullName(String firstName) {
        return String.format("%s HOW DO I GET THE LAST NAME HERE?", firstName);
    }

...将完整的实体对象(userEntity)作为源进行传递:

@Mapper
public abstract class UserMapper {

    @Mapping(source = "userEntity", target = "fullName", qualifiedByName = "nameToFullName")
    public abstract UserDto userEntityToUserDto(UserEntity userEntity);

    @Named("nameToFullName")
    public String nameToOwner(UserEntity userEntity) {
        return String.format("%s %s", userEntity.getFirstName(), userEntity.getLastName());
    }
jv4diomz

jv4diomz4#

您可以创建一个默认方法,该方法使用附加上下文www.example.com在内部调用mapstruct方法params.in这种方式,您可以获取“qualifiedByName”部分中的所有参数

@Mapper
public interface OneMapper {

    default OneDto createOne(One one, Integer projId, Integer val, String code) {
        return createOneWithContext(one,porjId,val,code
                                    one,porjId,val,code //as context params
        );
    }

    @Mapping(target="id", source="one.id")
    @Mapping(target="qualified",source="one",qualifiedByName="checkQualifiedNamed")
    OneDto createOneWithContext (One one, Integer projId, Integer val, String code
                     @Context One oneAsContext, 
                     @Context Integer projIdAsContext, 
                     @Context Integer valAsContext, 
                     @Context String codeAsContext

);

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

相关问题