给定如下定义的Source类:
class Person{
private String name;
private int age;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "peroson")
List<Phone> phones
// getters and setters
}
和Phone类定义如下:
class Phone{
private Long id;
private String phoneNumber;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "person")
private Person person;
// getters and setters
}
和DTO对象:
class PersonDTO{
private String name;
private int age;
List<PhoneDTO> phones
// getters and setters
}
class PhoneDTO{
private Long id;
private String phoneNumber;
private PersonDTO person;
// getters and setters
}
我有一个界面:
@Mapper(uses={PersonMapper.class})
interface PhoneMapper{
PhoneDTO toDto(Phone source);
Phone toEntity(PhoneDTO source);
}
@Mapper(uses={PhoneMapper.class})
interface PersonMapper{
PersonDTO toDto(Person source);
Person toEntity(PersonDTO source);
}
当我使用PeronMapper
或PhoneMapper
时会有递归调用,因为PersonMapper
使用PhoneMapper
而PersonMapper
使用PhoneMapper
。
如何解决?
答案 0 :(得分:0)
有许多方法可以避免递归。
第一个选项:
避免在你的一个地图制作者中明确忽略
第二个选项:
使用@Context
并编写自己的记忆。 mapstruct示例repo中有一个示例mapstruct-mapping-with-cycles。
我们的想法是拥有@Context
public class CycleAvoidingMappingContext {
private Map<Object, Object> knownInstances = new IdentityHashMap<Object, Object>();
@BeforeMapping
public <T> T getMappedInstance(Object source, @TargetType Class<T> targetType) {
return (T) knownInstances.get( source );
}
@BeforeMapping
public void storeMappedInstance(Object source, @MappingTarget Object target) {
knownInstances.put( source, target );
}
}
然后将此上下文的实例传递给您的映射器:
@Mapper(uses={PersonMapper.class})
interface PhoneMapper{
PhoneDTO toDto(Phone source, @Context CycleAvoidingContext context);
Phone toEntity(PhoneDTO source, @Context CycleAvoidingContext context);
}
@Mapper(uses={PhoneMapper.class})
interface PersonMapper{
PersonDTO toDto(Person source, @Context CycleAvoidingContext context);
Person toEntity(PersonDTO source, @Context CycleAvoidingContext context);
}
当然,CycleAvoidingMappingContext
可以包含更多指定的来源,而不仅仅是Object
。例如,您可以为Person
和PersonDTO
添加一个。由您决定如何实现它。