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

时间:2019-07-29 14:02:30

标签: 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: No property named "phones.number" exists in source parameter(s).。我知道我的代码出了点问题,但是找不到适合我需要的东西。您能帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

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

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

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

如果映射器可访问映射,则Mapstruct将选择所有映射链(嵌套的类映射器应位于同一类中,或在@Mapper(uses=类批注中声明)。


第二个原因::您的@Mapping(target = "num", source = "phones.number") <<-无法正常工作,因为它不知道phones应该从number集合中的哪个元素开始被检索。就像您要写EmployeeDto.num(single record) = Emloyee.phones(multiple records).number(single record)


IMHO块::使用mapstruct的最佳做法是使用干净的界面。这表明您在entity / dto / view / model / etc中具有清晰透明的结构和良好的关系。如果需要更具体的内容-您始终可以使用@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/

答案 1 :(得分:0)

我发现您的答案位于https://www.baeldung.com/mapstruct

我认为您的问题是您实际上并不希望将phone.number值映射到num。您希望Phone类中的值编号映射到PhoneDto类中的值num。

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