java mapstruct - 映射相关集合中的字段

标签 java mapstruct

我想在我的 Spring 应用程序中使用 mapstruct 库将模型列表映射到 dto 列表。假设我有两个这样的模型:

public class Employee {
    private Integer id;
    private String name;
    private Set<Phone> phones;
}

public class Phone {
    private Integer id;
    private String number;
}

这是我的两个 dto:

public class EmployeeDto {
    private Integer id;
    private String name;
    private Set<PhoneDto> phones;
}

public class PhoneDto {
    private Integer id;
    private String num;
}

最后我在我的映射类中使用这个方法:

@Mappings({
        @Mapping(target = "num", source = "phones.number")
})
public abstract List<EmployeeDto> toEmployeeDtoList(List<Employee> employeeList);

但是当我想编译时,这会返回java:源参数中不存在名为“phones.number”的属性。。我知道我的代码有问题,但我找不到对我的需要有用的东西。你能帮我解决这个问题吗?

最佳答案

第一个原因:您应该指定object -> object映射之前您可以指定 collection -> collection映射(PhoneDto -> Phone, EmployeeDto -> Employee) 作为mapstruct 嵌套表示法不会扩展到集合中。从我的角度来看,您不需要在映射器中保存基本的集合映射。你总是可以做到:

employees.stream()
        .map(mapper::toDto)
        .collect(Collectors.toList());

注意:但是如果您需要一些特定的collection -> collection映射到嵌套集合,您应该指定它。 (在您的情况下,Set 可能使用下面的 LinkedHashSet 进行排序,如果您不指定集合 -> 集合映射,您将失去排序,因为 mapstruct 将使用 HashSet 作为 Set<Phones> -> Set<PhonesDto> 转换的默认实现)。

如果映射器可以访问映射,Mapstruct 将选择所有映射链(嵌套类映射器应位于同一类中,或者在 @Mapper(uses= 类注释中进行说明)。

<小时/>

第二个原因:您的 @Mapping(target = "num", source = "phones.number") <<-- 不起作用,因为它不知道 phones 中的哪个元素 Collection number应该被检索。就像你试图写 EmployeeDto.num(single record) = Emloyee.phones(multiple records).number(single record) .

<小时/>

恕我直言:使用mapstruct的最佳实践是使用干净的接口(interface)。这表明您在实体/dto/ View /模型/等中拥有清晰透明的结构和良好的关系。如果需要更具体的东西 - 您始终可以使用 @AfterMapping 指定默认方法或@BeforeMapping注解。或者转到抽象类实现/装饰器(@DecoratedWith映射)。

对于这种情况有一些肮脏的黑客 - @Mapping(target = "num", expression = "java(your_java_code_as_string_in_here)") 但要注意:该表达式是一个字符串,并且会失败仅适用于映射器创建,不适用于所有类型的重构。

<小时/>

这是模型的示例映射(两种方式):

@Mapper
public interface EmployeeMapper {

  Employee toEmployee(EmployeeDto employeeDto);

  EmployeeDto toEmployeeDto(Employee employee);

  @Mapping(target="number", source="num")
  Phone toPhone(PhoneDto phoneDto);

  @InheritInverseConfiguration
  PhoneDto toPhoneDto(Phone phone);

  List<EmployeeDto> toEmployeeDtoList(List<Employee> employeeList);
}
<小时/>

也是值得考虑的好习惯 - 每个逻辑对象对使用不同的映射器。

@Mapper(uses = {PhoneMapper.class, OtherMapper.class}) // this is class level annotation.

这里收集了很棒的例子:https://github.com/mapstruct/mapstruct-examples/

关于java mapstruct - 映射相关集合中的字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57255504/

相关文章:

java - IlleagalMonitorStateException 当我试图运行这个程序时

java.lang.ClassCastException : java. lang.String 无法转换为 [Ljava.lang.Object

java - hibernate 相当于 javax.persistence.* 注释

Mapstruct:忽略MapperConfig

java - 映射器没有使用另一个映射器,如何使用另一个映射器的映射器?

java - 为什么Java构造函数不能同步?

java - 在 Java 集合和类型转换中实现简单的类似函数式的范例

java - 如何使用 Mapstruct 克服命名冲突

java - 如何更改 MapStruct 生成的 *.java 文件的位置?

java - MapStruct:如何将所有属性映射到列表的第一个元素?