具有多个参数的MapStruct QualifiedByName

Viv*_*pta 3 java intellij-idea java-8 mapstruct

我遇到了一种情况,我的映射方法有3个参数,而这三个参数都用于派生目标类型的属性之一。

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

有什么办法可以对任何mapstruct注释执行此操作,例如@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;                   
    }
}
Run Code Online (Sandbox Code Playgroud)

Wes*_*ant 12

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

示例实体:

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

Run Code Online (Sandbox Code Playgroud)

示例 DTO:


public class UserDto {
    private String fullName;
}
Run Code Online (Sandbox Code Playgroud)

...和映射器...而不是传递单个源(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);
    }
Run Code Online (Sandbox Code Playgroud)

...传递完整的实体对象(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());
    }
Run Code Online (Sandbox Code Playgroud)

  • 与mapstruct v1.5.3完美配合 (3认同)

Pim*_*oek 6

从 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);
Run Code Online (Sandbox Code Playgroud)

更新

由于 Mapstruct 允许将多个源参数映射到单个目标,我建议checkQualified从映射器中提取该方法,而不是预先计算结果并使用 checkQualified 方法的结果调用映射器。Mapstruct 是一个映射库,并不擅长执行任意逻辑。这并非不可能,但就我个人而言,我看不到它在您的特定情况下增加的价值。

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

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

映射器可以这样使用:

@Mapper
public interface OneMapper {
    OneDto toOneDto(One one, Boolean qualified);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 你还没有告诉任何关于 `qualifiedByName` 的事情 (( (5认同)

Fil*_*lip 5

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

但是,您可以使用@Context1.2.0版中的。据我了解,the projId和the code只是作为映射的帮助者,它们并不用于映射目标属性。

因此,您可以做类似的事情(理论上应该起作用):

@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;                   
    }
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是将所有这些属性提取到一个单独的类中,然后传递该类(这将允许使用同一类型的多个参数)。

该类如下所示:

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
}
Run Code Online (Sandbox Code Playgroud)

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

@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;                   
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 非常感谢,它帮助我部分解决了我的问题。然而它对我来说不起作用。我必须在`@Mapping(target =“qualified”,qualifiedByName =“checkQualifiedNamed”)`中指定来源。那么如何将这 2 个参数传递给 `checkQualified` 呢?(在我的例子中,第二个参数不是@Context) (2认同)