【问题标题】:MapStruct issue while recursive mapping递归映射时的 MapStruct 问题
【发布时间】:2020-03-05 16:49:15
【问题描述】:

我正在尝试实现 MapStruct 映射库。我已经制作了样本并且对于简单的映射它工作正常,但我陷入了 1 个问题。 我有 2 个 jpa 实体类,它们有两种方式的关系。一个在另一个里面,另一个在一个里面。它会创建循环映射问题,因此 MapStruct 会引发 StackOverflow 错误。 我创建了最少的代码来重现github 上的案例。 示例代码:

public class A {
    private Long id;
    private String name;
    private B bData;
    //getter-setter
}

public class B {
    private Long id;
    private String name;
    private Set<A> aData;
    //getter-setter
}

数据生成器

public class DataGenerator {
    public static A generateData(){
        A a = new A();
        a.setId(1L);
        a.setName("foo");
        B b = new B();
        b.setId(2L);
        b.setName("bar");

        A a2 = new A();
        a2.setId(3L);
        a2.setName("john");
        a2.setbData(b);
        A a3 = new A();
        a3.setId(4L);
        a3.setName("doe");
        a3.setbData(b);

        Set<A> aData = new HashSet<A>();
        aData.add(a2);
        aData.add(a3);
        b.setaData(aData);

        a.setbData(b);
        return a;
    }
}

映射器

@Mapper
public interface CustomMapper {
    CustomMapper INSTANCE = Mappers.getMapper(CustomMapper.class);
    ADto atoADto(A a);
}

应用

public class AppMain {
    public static void main(String[] args) {
        A a = DataGenerator.generateData();
        ADto aDto = CustomMapper.INSTANCE.atoADto(a);
        System.out.println(aDto.getId());
    }
}

Dto/Destination 类与原始源类相同。 主要是导致stackoverflow错误的循环/递归映射问题。

使用 spring BeanUtils.copyProperties 也是一样,但我想实现 MapStruct。目前我正在考虑用 MapStruct 替换 spring BeanUtils

有什么建议吗?

【问题讨论】:

  • 我已经尝试了最小的代码来重现,它工作正常。 (它打印1
  • @i.bondarenko master 分支的代码工作正常,我创建了单独的分支来重现该问题。

标签: java mapping mapstruct


【解决方案1】:

请参阅此mapstruct github issue 以获取解决方案,即忽略导致递归的字段。我引用:

“您可以使用@Qualifier 来实现它。您可以使用@Named 和qualifiedByName,或者您可以使用您自己的自定义@CountryWithoutCities 限定符和qualifiedBy。

Class country{

     String id;
     String name;
     List<City> cities;
}

Class City{

     String id;
     String name;
     Country country;
}

@Mapper(uses = CityMapper.class)
interface CountryMapper {

    @Mapping( target = "cities", qualifiedByName = "noCountry")
    CountryDto toDto(Country country);

    @CountryWithoutCities
    @Mapping( target = "cities", ignore = true)
    CountryDto toDtoWithoutCities(Country country);
}

@Mapper(uses = CountryMapper.class)
interface CityMapper {

    @Named( "noCountry" )
    @Mapping( target = "country", ignore = true)
    CityDto toDtoWithoutCountry(City city);

    @Mapping( target = "country", qualifiedBy= CountryWithoutCities.class)
    CityDto toDto(City city);
}

【讨论】:

    【解决方案2】:

    在 MapStruct 存储库中有一个示例 here 如何处理循环和递归。基本上你需要跟踪状态。该示例使用上下文对象来执行此操作。

    【讨论】:

    • 这在一定程度上会有所帮助,提到的情况与预期的不同。
    • 是一个解决方向。在示例中查看所有使用场景是很棘手的。如果您对some extend 说,解决方案方向在哪方面失败了?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-12
    • 2020-09-04
    • 2022-09-23
    • 2011-07-24
    • 1970-01-01
    相关资源
    最近更新 更多