Reputation: 325
I have the following entities:
@Data
@Entity
@Table(name = "artist")
public class Artist {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="artist_id")
private int id;
@Column(name="artist_name", length = 2000)
private String name;
private String country;
@OneToMany(mappedBy = "artist", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Song> songs = new ArrayList<>();
public Artist(String name, String country){
this.name=name;
this.country=country;
}
}
@Data
@Entity
@Table(name = "songs")
public class Song {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int songId;
@Column(name = "text", length = 65600)
private String text;
private Double rating;
private String songName;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "artist_id", nullable = false)
public Artist artist;
public Song(String text, Double rating, String songName, Artist artist) {
this.text = text;
this.rating = rating;
this.songName = songName;
this.artist = artist;
}
}
I try to get all songs by artist name pattern:
@Query("SELECT s FROM Song s WHERE s.artist.name LIKE CONCAT('%',:name,'%')")
List findByArtistsName(@Param("name") String name);
and all artists by songs name patern:
@Query("SELECT a FROM Artist a JOIN FETCH a.songs s WHERE s.songName LIKE CONCAT('%',:pattern,'%')")
List<Artist> findBySong(@Param("pattern") String songName);
For this I am using that JPQL queries respectively. But both get me the same StackOverflowError.
>
>
> Caused by: java.lang.StackOverflowError: null
> at sun.misc.FloatingDecimal$BinaryToASCIIBuffer.dtoa(FloatingDecimal.java:431)
> ~[na:1.8.0_151]
> at sun.misc.FloatingDecimal$BinaryToASCIIBuffer.access$100(FloatingDecimal.java:259)
> ~[na:1.8.0_151]
> at sun.misc.FloatingDecimal.getBinaryToASCIIConverter(FloatingDecimal.java:1785)
> ~[na:1.8.0_151]
> at sun.misc.FloatingDecimal.getBinaryToASCIIConverter(FloatingDecimal.java:1738)
> ~[na:1.8.0_151]
> at sun.misc.FloatingDecimal.toJavaFormatString(FloatingDecimal.java:70)
> ~[na:1.8.0_151]
> at java.lang.Double.toString(Double.java:204) ~[na:1.8.0_151]
> at java.lang.Double.toString(Double.java:644) ~[na:1.8.0_151]
> at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
> at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
> at com.music.entity.Song.toString(Song.java:8) ~[classes/:na]
> at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
> at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
> at java.util.AbstractCollection.toString(AbstractCollection.java:462)
> ~[na:1.8.0_151]
> at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
> ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
> at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
> at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
> at com.music.entity.Artist.toString(Artist.java:9) ~[classes/:na]
> at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
> at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
> at com.music.entity.Song.toString(Song.java:8) ~[classes/:na]
> at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
> at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
> at java.util.AbstractCollection.toString(AbstractCollection.java:462)
> ~[na:1.8.0_151]
What is the correct way to solve this issue?
Upvotes: 0
Views: 950
Reputation: 8354
This is almost certainly being caused by your use of Lombok and the @Data
annotation which is a shortcut for these other Lombok annotations:
@ToString, @EqualsAndHashCode, @Getter on all fields, and @Setter on all non-final fields, and @RequiredArgsConstructor
The @ToString
annotation is automatically generating a toString
method which includes all of your fields. The bottom of the stack trace points to a toString
method call on a collection, if you follow the stack up you can spot the cycle which is causing the stack overflow:
AbstractCollection.toString
-> Song.toString
-> Artist.toString
-> AbstractCollection.toString
-> Song.toString
...
Your Artist
entity holds a collection of Song
entities which holds a reference to the Artist
entity and so on. You can see how it gets caught in a loop when calling the toString
method and eventually exhausts the stack frames / hits the limit.
Either remove the @Data
annotation and only apply a subset or define your own toString
method that avoids the loop.
Upvotes: 2