Issue
I have 3 entities -
Course
Module
Timeline Course is an independent entity with following attributes: Course - (id Integer Primary Key, course_name)
@Id @Column(name = "id") Integer courseId; @Column(name = "course_name") String course_name;
Next up is another entity Module, Every row in module is related to one course, and hence there is a one to one relationship between Module and Course. Module - (module_id, module_name, module_type, duration)
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "module_id")
Integer module_id;
@Column(name = "module_name")
String module_name;
@Column(name = "duration")
Integer duration;
@ManyToOne
@JoinColumn(name="timeline_id", nullable=false)
private Timeline timeline;
Now, next is a timeline entity, which is also related to course i.e every timeline id belongs to one course id, but one timeline id can belong to multiple module_ids, and hence below code:
@Id
@Column(name = "timeline_id")
Integer timelineId;
@OneToMany( mappedBy = "timeline" )
private List<Module> module;
@OneToOne( cascade = CascadeType.ALL)
private Course course;
Can you please tell me what is the error over here. ModuleRepository:
@Repository
public interface ModuleRepository extends JpaRepository<Module, Integer>{
public List<Module> findAllByTimelineTimelineId(Integer timelineId);
}
IModuleService
public interface IModuleService {
public List<Module> findByTimelineId(Integer timelineId);
}
ModuleServiceImpl
public List<Module> findByTimelineId(Integer timelineId) {
// TODO Auto-generated method stub
return moduleRepo.findAllByTimelineTimelineId(timelineId);
}
Controller
@RequestMapping("/gettimeline/{timeline_id}")
public List<Module> findByTimelineId(@PathVariable Integer timeline_id){
return moduleService.findByTimelineId(timeline_id);
}
Now when I run this url in Postman: http://localhost:8083/gettimeline/1
I get an infinite loop, I am unable to decode the error, also is there any problem with OneToMany mapping, I am new to JPA:
[{"module_id":1,"module_name":"Sleep","duration":10,"timeline":{"timelineId":1,"module":[{"module_id":1,"module_name":"Sleep","duration":10,"timeline":{"timelineId":1,"module":[{"module_id":1,"module_name":"Sleep","duration":10,"timeline":{"timelineId":1,"module":[{"module_id":1,"module_name":"Sleep","duration":10,"timeline":{"timelineId":1,"module":[{"module_id":1,"module_name":"Sleep","duration":10,"timeline":{"timelineId":1,"module":[
Please help, thank you in advance :)
Solution
The infinite loop issue is caused by the one-to-many relation. There are several ways of fixing this, but I find view model classes like shown below as the cleanest approach.
Please note that the owning side of the one-to-many relation is not included in the code below, only the many-to-one. This can be done the other way around, but from your code, I guess this is what you want.
TimelineVM class
package no.mycompany.myapp.misc;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class TimelineVM {
private Integer timelineId;
public TimelineVM(Timeline timeline) {
this.timelineId = timeline.getTimelineId();
}
}
ModuleVM class
package no.mycompany.myapp.misc;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class ModuleVM {
private Integer module_id;
private String module_name;
private Integer duration;
private TimelineVM timeline;
public ModuleVM(Module module) {
this.module_id = module.getModule_id();
this.module_name = module.getModule_name();
this.duration = module.getDuration();
this.timeline = new TimelineVM(module.getTimeline());
}
}
Controller method
@RequestMapping("/gettimeline/{timeline_id}")
public List<ModuleVM> findByTimelineId(@PathVariable Integer timeline_id){
return moduleService.findByTimelineId(timeline_id).stream().map(ModuleVM::new).collect(Collectors.toList());
}
Answered By - Roar S.