具有多个参数的 MapStruct QualifiedByName
MapStruct QualifiedByName with multiple parameters
我遇到过这样一种情况,我的映射方法有 3 个参数,所有这三个参数都用于派生目标类型的一个属性。
我在接口中创建了一个默认映射方法,保留了派生 属性 的逻辑,现在为了调用此方法,我可以在 @Mapping
注释中使用 expression = "java( /*method call here*/ )"
.
有什么方法可以使用任何 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;
}
}
目前 MapStruct 不支持具有多个源属性的映射方法。
但是,在您的情况下,您可以使用 1.2.0 中的 @Context
。据我了解,projId
和 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;
}
}
另一种选择是将所有这些属性提取到单独的 class 中并传递(这将允许同一类型的多个参数)。
class 看起来像:
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));
从 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 允许将多个源参数映射到单个目标,我建议从映射器中提取 checkQualified
方法,而不是预先计算结果并使用 checkQualified 方法的结果调用映射器. Mapstruct 是一个 mapping 库,不会 excel 执行任意逻辑。这并非不可能,但就我个人而言,我看不到它在您的特定情况下增加的价值。
提取逻辑后,您的映射器可能如下所示:
@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);
您可以创建一个默认方法,它在内部调用带有附加上下文的 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;
}
}
```
如果需要根据同一源对象的多个源字段计算单个目标字段,可以将完整源对象传递给自定义映射器函数,而不是单独传递字段:
示例实体:
@Entity
@Data
public class User {
private String firstName;
private String lastName;
}
DTO 示例:
public class UserDto {
private String fullName;
}
... 和映射器... 而不是传递单个源 (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());
}
我遇到过这样一种情况,我的映射方法有 3 个参数,所有这三个参数都用于派生目标类型的一个属性。
我在接口中创建了一个默认映射方法,保留了派生 属性 的逻辑,现在为了调用此方法,我可以在 @Mapping
注释中使用 expression = "java( /*method call here*/ )"
.
有什么方法可以使用任何 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;
}
}
目前 MapStruct 不支持具有多个源属性的映射方法。
但是,在您的情况下,您可以使用 1.2.0 中的 @Context
。据我了解,projId
和 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;
}
}
另一种选择是将所有这些属性提取到单独的 class 中并传递(这将允许同一类型的多个参数)。
class 看起来像:
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));
从 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 允许将多个源参数映射到单个目标,我建议从映射器中提取 checkQualified
方法,而不是预先计算结果并使用 checkQualified 方法的结果调用映射器. Mapstruct 是一个 mapping 库,不会 excel 执行任意逻辑。这并非不可能,但就我个人而言,我看不到它在您的特定情况下增加的价值。
提取逻辑后,您的映射器可能如下所示:
@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);
您可以创建一个默认方法,它在内部调用带有附加上下文的 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;
}
}
```
如果需要根据同一源对象的多个源字段计算单个目标字段,可以将完整源对象传递给自定义映射器函数,而不是单独传递字段:
示例实体:
@Entity
@Data
public class User {
private String firstName;
private String lastName;
}
DTO 示例:
public class UserDto {
private String fullName;
}
... 和映射器... 而不是传递单个源 (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());
}