Good morning, nice to greet you.
I am new to Spring Boot recently, and I am working with a REST API, which is basically a playlist with songs, basically the REST API should have the following structure. A playlist can have many songs:
{
"name": "Lista 1",
"description": "Lista de reproduccion 2020 spotify",
"songs": [
{
"title": "Tan Enamorados",
"artist": "CNCO",
"album": "Tan Enamorados",
"year": 2020,
"playList": 1
},
{
"title": "Hawai",
"artist": "Maluma",
"album": "PAPI JUANCHO",
"year": 2020,
"playList": 1
}
]
}
Currently this is how I have my entities configured
Entity SONGS
@Entity
@Table(name = "SONGS")
public class Songs{
@JsonIgnore
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID")
private Long id;
@Column(name = "title")
private String title;
@Column(name = "artist")
private String artist;
@Column(name = "album")
private String album;
@Column(name = "year")
private int year;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PLAY_LIST_ID")
private PlayList playList;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return this.artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getAlbum() {
return this.album;
}
public void setAlbum(String album) {
this.album = album;
}
public int getYear() {
return this.year;
}
public void setYear(int year) {
this.year = year;
}
public PlayList getPlayList() {
return this.playList;
}
public void setPlayList(PlayList playList) {
this.playList = playList;
}
}
Entity PLAYLIST
@Entity
@Table(name = "PLAY_LIST")
public class PlayList {
@JsonIgnore
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID")
private Long id;
@Column(name="name")
private String name;
@Column(name="description")
private String description;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "playList")
private List<Songs> songs = new ArrayList<>();
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Songs> getSongs() {
return this.songs;
}
public void setSongs(List<Songs> songs) {
this.songs = songs;
}
}
Controller
@RestController
@RequestMapping("playlist")
public class PlayListController {
@Autowired
private PlayListService playListService;
//Get playlist by id with songs belongs that playlist
@GetMapping("/{id}")
public Optional<PlayList> getPlayListByID(@PathVariable(value = "id") Long id) {
Optional<PlayList> playList = playListService.getById(id);
return playList;
}
@PostMapping("/create")
public PlayList createPlayList(@RequestBody PlayList playList) {
return playListService.savePlayList(playList);
}
}
My class PlayListServiceImpl
@Service
public class PlayListServiceImpl implements PlayListService {
@Autowired
private PlayListRepository playListRepository;
public Optional <PlayList> getById(Long Id) {
Optional <PlayList> playList= playListRepository.findById(Id);
return playList;
}
@Override
public PlayList savePlayList(PlayList playList) {
return playListRepository.save(playList);
}
}
My Repository
@Repository
public interface PlayListRepository extends JpaRepository<PlayList, Long> {
Optional<PlayList> findById(Long Id);
}
However, I have infinite recursion problem when I try to get a playlist with the get method:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.example.api.songs.entity.PlayList[\"songs\"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.api.songs.entity.Songs[\"playList\"]->com.example.api.songs.entity.PlayList[\"songs\"]->org.hibernate.
This is due to the playList field found in the Songs entity, when trying to get the playlist with the songs, I get an array that becomes recursive and not the id of the playList, which is what I want to get, the reality is that I get something like this:
I can solve by applying a JsonIgnore in the field, however this affects me that when I go to save a playlist, I cannot pass the idPlayList field to each song to make sure that each song is saved with its respective idPlayList
I think the best thing would be to build a DTO here that helps me to have the relationship of the 2 tables, however, I don't know how I would do it in a way that allows me, when executing a get from the playList, to obtain only the idPlayList, and when saving power pass the idPlayList in each song that is going to be saved with a playlist, or if there is another way in which I could store a playlist with its songs and have them stored directly, since currently I have to assign by BD to each song the idPlayList