dbh
dbh

Reputation: 13

save entity with oneToOne mapping not working

I'm new to spring boot. I searched a lot but I coudn't figure out what I'm missing here

I have three entities

Student

@Getter
@Setter
@Entity
@Table(name = "student")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "STUDENT_PK_SEQ")
    @SequenceGenerator(name = "STUDENT_PK_SEQ", sequenceName = "STUDENT_PK_SEQ", allocationSize = 1)
    private Long id;

    private String title;

    @OneToOne(cascade = CascadeType.ALL)
    private ClassInstance classInstance;

}

Class

@Getter
@Setter
@Entity
@Table(name = "class")
public class Class {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CLASS_PK_SEQ")
    @SequenceGenerator(name = "CLASS_PK_SEQ", sequenceName = "CLASS_PK_SEQ", allocationSize = 1)
    private Long id;

    private String title;

    @OneToMany(mappedBy = "class")
    @JsonIgnoreProperties(value = {"class"}, allowSetters = true)
    private Collection<ClassInstance> classInstances;

}

ClassInstance

    @Getter
    @Setter
    @Entity
    @Table(name = "class_instance")
    public class ClassInstance {
        
            @Id
            @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CLASS_INSTANCE_PK_SEQ")
            @SequenceGenerator(name = "CLASS_INSTANCE_PK_SEQ", sequenceName = "CLASS_INSTANCE_PK_SEQ", allocationSize = 1)
            private Long id;
        
            private String title;
            @ManyToOne
            private Class class;
    
            @OneToOne(cascade = CascadeType.ALL)
            private Student student;
        
        }

The problem occurs when I would like to assign an existing Student to ClassIntance

   @Transactional
        @Override
        public ClassInstanceDto createClassInstance(Long idClass, Long idStudent) {
            if(idClass == null || idStudent == null){
                throw new ApiRequestException(Constants.INVALID_ID, HttpStatus.PRECONDITION_FAILED);
            }   
            Optional<Class> class = classRepository.findById(idClass);
            if(class.isPresent()) {
                Student student = studentRepository.getById(idStudent);
                student.setTitle("X");
                studentRepository.save(student);
    
                ClassInstance classInstance = new ClassInstance();
                classInstance.setClass(class.get());
                classInstance.setStudent(student);
    
                ClassInstance result = classInstanceRepository.save(classInstance);
  //start  //if I remove this part, it works 
                student.setClassInstance(result);
                studentRepository.save(student);
   //end 
                return classInstanceMapper.toClassInstanceDto(result);
            } else {
                throw new ApiRequestException(Constants.CLASS_NOT_FOUND, HttpStatus.NOT_FOUND);
            }
        }

I can't even understand what's the error message all I got is that

ma.company.app.mapper.ClassInstanceMapperImpl.toClassInstanceDto(ClassInstanceMapperImpl.java:37) ~[classes/:na]
    at ma.company.app.mapper.ClassInstanceMapperImpl.studentToStudentDto(ClassInstanceMapperImpl.java:162) ~[classes/:na]
ma.company.app.mapper.ClassInstanceMapperImpl.toClassInstanceDto(ClassInstanceMapperImpl.java:37) ~[classes/:na]
    at ma.company.app.mapper.ClassInstanceMapperImpl.studentToStudentDto(ClassInstanceMapperImpl.java:162) ~[classes/:na]
ma.company.app.mapper.ClassInstanceMapperImpl.toClassInstanceDto(ClassInstanceMapperImpl.java:37) ~[classes/:na]
    at ma.company.app.mapper.ClassInstanceMapperImpl.studentToStudentDto(ClassInstanceMapperImpl.java:162) ~[classes/:na]
ma.company.app.mapper.ClassInstanceMapperImpl.toClassInstanceDto(ClassInstanceMapperImpl.java:37) ~[classes/:na]
    at ma.company.app.mapper.ClassInstanceMapperImpl.studentToStudentDto(ClassInstanceMapperImpl.java:162) ~[classes/:na]
ma.company.app.mapper.ClassInstanceMapperImpl.toClassInstanceDto(ClassInstanceMapperImpl.java:37) ~[classes/:na]
    at ma.company.app.mapper.ClassInstanceMapperImpl.studentToStudentDto(ClassInstanceMapperImpl.java:162) ~[classes/:na]

UPDATE here is my mapper

import org.mapstruct.Mapper;

import java.util.List;

@Mapper(componentModel = "spring")
public interface ClassInstanceMapper {
    ClassInstanceDto toClassInstanceDto(ClassInstance classInstance);
    ClassInstance toClassInstance(ClassInstanceDto classInstanceDto);
    List<ClassInstanceDto> toClassInstanceDtos(List<ClassInstance> classInstances);
    List<ClassInstance> toClassInstances(List<ClassInstanceDto> classInstanceDtos);
}

ClassInstanceDto

    @Getter
    @Setter
    public class ClassInstanceDto {
        private Long id;
        private StudentDto student;
        private ClassDto class;
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            ClassInstanceDto that = (ClassInstanceDto) o;
    
            return id.equals(that.id);
        }
    
        @Override
        public int hashCode() {
            return id.hashCode();
        }
}

StudentDto

@Getter
@Setter
public class StudentDto {
    private Long id;
    private String title;
    private ClassInstanceDto ClassInstance;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        StudentDto that = (StudentDto) o;

        return id.equals(that.id);
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }
}

Thanks in advance!

Upvotes: 0

Views: 800

Answers (1)

lane.maxwell
lane.maxwell

Reputation: 5872

You have a recursive loop happening during the mapping. I'm not certain about the inner workings of MapStruct, but if it's using ObjectMapper, it would probably honor JsonManageReference and JsonBackReference annotations.

Assuming that ClassInstance is the parent,

@JsonManagedReference
@OneToOne(cascade = CascadeType.ALL)
private Student student;

One the "child" side

@JsonBackReference
@OneToOne(cascade = CascadeType.ALL)
private ClassInstance classInstance;

Do this also for your OneToMany/ManyToOne mappings. Also, I would strongly encourage you not to name your class, Class.

Upvotes: 2

Related Questions