0
votes

If I have a Class ProfessorDto and a Class StudentDto how can I avoid circular issues if the ProfessorDto have a list of StudentDto and the StudentDto have a property of type ProfessorDto ? I didn't put the code of the domain class but let's say it is the same as for the Dto.

I'm new to Mapstruct, converting a domain bean to a Dto with simple properties like Long, String is working but in my exemple, the relation OneToMany is not working !

@JsonApiResource(type = "professor")
@NoArgsConstructor
@Data
public class ProfessorDto {

  @JsonApiId
  private Long id;

  private String professorName;

  @JsonApiRelation(mappedBy = "professor")
  private List<StudentDto> student;

  public ProfessorDto(Long id) {
    this.id = id;
  }
}

And a class Student

@JsonApiResource(type = "student")
@NoArgsConstructor
@Data
public class StudentDto {

  @JsonApiId
  private Long id;

  private String studentName;

  @JsonApiRelation
  private ProfessorDto professor;
}

My Mapper for Professor is

@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface ProfessorMapper {

  ProfessorDto domainToDto(Professor domain);

  Professor dtoToDomain(ProfessorDto dto);

  StudentDto studentToDto(Student student);

  Student studentDtoToDomain(StudentDto studentDto);

  List<StudentDto> studentToDto(List<Student> student);

  List<Student> studentDtoToDomain(List<StudentDto> studentDto);
}
2

2 Answers

0
votes

At first, you should decide if it is really needed to keep List<StudentDto> aggregated in ProfessorDto. You can just exclude it, if it's possible.
Otherwise, you can make either StudentDto or ProfessorDto 'flat'. For example, you can add field Long professorId instead of ProfessorDto professor to the StudentDto, or List<Long> studentIds to the ProfessorDto.

An sample approach using Mapstruct:

  1. Change a DTO class like this:

    @JsonApiResource(type = "student")
    @NoArgsConstructor
    @Data
    public class StudentDto {
    
        @JsonApiId
        private Long id;
    
        private String studentName;
    
        private Long professorId; // <-- CHANGED 
    }
    
  2. Add a Helper class, and provide custom mapping logic:

    @Component
    public class MapperHelper {
        @AfterMapping
        public void mapProfessorId(Student student, @MappingTarget StudentDto studentDto) {
            studentDto.setProfessorId(student.getProfessor().getId());
        }
    }