Ознакомьтесь с примером Mapstruct с циклами .
Решение вашей проблемы также продемонстрировано в документации по контекстной аннотации .
Пример
Полный пример: https://github.com/jannis-baratheon/stackoverflow--mapstruct-mapping-graph-with-cycles.
Ссылка
Mapper:
@Mapper
public interface UserMapper {
@Mapping(target = "userProfileEntity", source = "userProfile")
UserEntity mapToEntity(User user,
@Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
@InheritInverseConfiguration
User mapToDomain(UserEntity userEntity,
@Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
@Mapping(target = "userEntity", source = "user")
UserProfileEntity mapToEntity(UserProfile userProfile,
@Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
@InheritInverseConfiguration
UserProfile mapToDomain(UserProfileEntity userProfileEntity,
@Context CycleAvoidingMappingContext cycleAvoidingMappingContext);
}
, где CycleAvoidingMappingContext
отслеживает уже отображенные объекты и повторно использует их, избегая переполнения стека:
public class CycleAvoidingMappingContext {
private final Map<Object, Object> knownInstances = new IdentityHashMap<>();
@BeforeMapping
public <T> T getMappedInstance(Object source,
@TargetType Class<T> targetType) {
return targetType.cast(knownInstances.get(source));
}
@BeforeMapping
public void storeMappedInstance(Object source,
@MappingTarget Object target) {
knownInstances.put(source, target);
}
}
Использование Mapper (отображение одного объекта):
UserEntity mappedUserEntity = mapper.mapToEntity(user, new CycleAvoidingMappingContext());
Вы также можете добавить метод по умолчанию в свой картограф:
@Mapper
public interface UserMapper {
// (...)
default UserEntity mapToEntity(User user) {
return mapToEntity(user, new CycleAvoidingMappingContext());
}
// (...)
}