返回

MapStruct映射器内映射器的注入:解决单元测试无法访问默认方法

java

MapStruct映射器内的映射器注入

问题

当你使用MapStruct将实体对象映射到领域对象时,你可能会遇到一个场景,其中实体对象包含一个包含另一类型列表的字段。为了映射此列表,你需要在主映射器内部使用另一个映射器。但是,在单元测试期间,你可能会发现无法访问默认映射器方法,因为它们不在实现类中。

解决方案

要解决此问题,你可以使用以下步骤:

  1. 创建自定义映射器接口

    首先,创建一个自定义映射器接口,它将定义你的默认映射方法。此接口将由主映射器实现。

    public interface CustomMapper {
    
        List<DomainB> mapList(List<EntityB> entityB);
    
    }
    
  2. 在主映射器中实现自定义映射器

    在你的主映射器中,使用@Named注释将你的默认映射方法与自定义映射器接口中的方法连接起来。

    @Mapping(target = "listOfDomainB", source = "entityA.list", qualifiedByName = "mapList")
    DomainA map(EntityA entityA);
    
    @Override
    default List<DomainB> mapList(List<EntityB> entityB) {
        return entityB.stream()
                .map(EntityB -> new EntityB()
                        .name(EntityB.getName()))
                .collect(Collectors.toList());
    }
    
  3. 使用代理创建自定义映射器的实例

    在你的服务类中,使用代理创建自定义映射器接口的实例。这将允许你在单元测试中模拟映射器的方法。

    private final CustomMapper customMapper = Mapper.withContext(Collections.singletonMap(DestinationType.class, type))
                                          .getMapper(CustomMapper.class);
    

常见问题解答

1. 为什么在实现类中调用默认方法时,映射器模拟的.toCallRealMethod()不会调用mapList

这是因为代理会在实现类中创建一个接口的动态实现,该实现类调用默认方法。当执行.toCallRealMethod()时,它不会调用实现类,而是调用代理类,该类不包含默认方法。

2. 是否可以使用其他方法来解决此问题?

除了使用自定义映射器接口,你还可以考虑使用@Context@Qualifier注释来注入映射器。但是,这些方法可能更复杂或更难维护。

3. 我在哪里可以找到更多关于MapStruct映射器注入的信息?

有关MapStruct映射器注入的更多信息,你可以参考MapStruct文档:

MapStruct 映射器注入文档

结论

通过使用自定义映射器接口和代理,你可以轻松地解决MapStruct映射器内映射器的注入问题。这将使你能够模拟映射器方法并编写更可靠的单元测试。