Mapstruct двунаправленное отношение один к одному: java .lang.StackOverflowError: null - PullRequest
0 голосов
/ 07 мая 2020

У меня есть двунаправленное сопоставление.

Когда я пытаюсь получить все категории из БД, все работает нормально. и когда я пытаюсь сопоставить то же самое с DTO для объекта с помощью mapstruct, я получаю ошибку ниже. Я пытался использовать CycleAvoidingMappingContext, но мне это не помогло. Я не хочу использовать атрибут игнорирования.

UserEntity

@Entity
@Table(name = "users")
@Getter
@Setter
@NoArgsConstructor
public class User extends BaseEntity {

    private String username;

    private String password;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "customer_id", referencedColumnName = "id")
    private Customer customer;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "employee_id", referencedColumnName = "id")
    private Employee employee;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "venue_id", referencedColumnName = "id")
    private Venue venue;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}

Employee Entity

@Entity
@Table(name = "employee")
@Getter
@Setter
@NoArgsConstructor
public class Employee extends BaseEntity {

    private String name;

    private LocalDateTime closeHour;

    private LocalDateTime openHour;

    private Long phoneNumber;

    @ManyToOne
    private Venue venue;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "employee_sherbime",
            joinColumns = @JoinColumn(name = "employee_id"),
            inverseJoinColumns = @JoinColumn(name = "sherbime_id"))
    private Set<Sherbime> employeeSherbime = new HashSet<>();

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "user_id", referencedColumnName = "id")
    private User user;

    public void setUser(User user) {

        if (user != null) {
            user.setEmployee(this);
        }

        this.user = user;
    }
}

EmployeMapper

@Mapper(componentModel = "spring", uses = {VenueMapper.class, SherbimeMapper.class, UserMapper.class})
public interface EmployeeMapper extends EntityMapper<EmployeeDTO, Employee> {

    @Mapping(source = "venue", target = "venue")
    @Mapping(source = "employeeSherbime", target = "employeeSherbime")
    @Mapping(source = "user", target = "user")
    EmployeeDTO toDto(Employee employee, @Context CycleAvoidingMappingContext context);

    @Mapping(source = "venue", target = "venue")
    @Mapping(source = "employeeSherbime", target = "employeeSherbime")
    @Mapping(source = "user", target = "user")
    Employee toEntity(EmployeeDTO employeeDTO, @Context CycleAvoidingMappingContext context);
}

CycleAvoidingMappingContext

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 );
    }
}

EmployeeServiceImpl

@Service
public class EmployeeServiceImpl implements EmployeeService {
    private final Logger logger = LogManager.getLogger(EmployeeServiceImpl.class);

    private final EmployeeRepository employeeRepository;

    private final EmployeeMapper employeeMapper;

    public EmployeeServiceImpl(EmployeeRepository employeeRepository, EmployeeMapper employeeMapper) {
        this.employeeRepository = employeeRepository;
        this.employeeMapper = employeeMapper;
    }

    @Override
    public EmployeeDTO save(EmployeeDTO employeeDTO) {
        logger.info("Request to save Employee : {}", employeeDTO);
        Employee employee = employeeMapper.toEntity(employeeDTO, new CycleAvoidingMappingContext());
        employee = employeeRepository.save(employee);
        return employeeMapper.toDto(employee, new CycleAvoidingMappingContext());
    }

Ошибка

java.lang.StackOverflowError: null
    at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:168) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
    at com.pimp.service.mapper.EmployeeMapperImpl.sherbimeSetToSherbimeDTOSet(EmployeeMapperImpl.java:182) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:70) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:15) ~[classes/:na]
    at com.pimp.service.mapper.UserMapperImpl.toDto(UserMapperImpl.java:63) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:71) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:15) ~[classes/:na]
    at com.pimp.service.mapper.UserMapperImpl.toDto(UserMapperImpl.java:63) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:71) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:15) ~[classes/:na]
    at com.pimp.service.mapper.UserMapperImpl.toDto(UserMapperImpl.java:63) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:71) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:15) ~[classes/:na]
    at com.pimp.service.mapper.UserMapperImpl.toDto(UserMapperImpl.java:63) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:71) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:15) ~[classes/:na]
    at com.pimp.service.mapper.UserMapperImpl.toDto(UserMapperImpl.java:63) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:71) ~[classes/:na]
    at com.pimp.service.mapper.EmployeeMapperImpl.toDto(EmployeeMapperImpl.java:15) ~[classes/:na]
...