Q:

infinite recursion when querying sql using repository in jpa hibernate

I have two entity, Promotion which contains information about a promotion and Promotion Details which contains list of products in a Promotion. Below is my code.
Promotion Entity:
@Entity
@Data
public class Promotion {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToMany(mappedBy = "promotion")
    private List<PromotionDetails> details;

    @Column(name = "start_date")
    private Date startDate;

    @Column(name = "end_date")
    private Date endDate;
}

PromotionDetails Entity:
@Entity
@IdClass(PromotionDetailsPK.class)
@Data
public class PromotionDetails {

    @Id
    @ManyToOne(optional = false)
    @JoinColumn(name = "promotion_id", referencedColumnName = "promotion_id")
    private Promotion promotion;

    @Id
    @ManyToOne(optional = false)
    @JoinColumn(name="product_id", referencedColumnName="product_id")
    private Product product;

    @Column()
    private double discount;

}

I want to retrieve one Promotion which is available for a product using JPA.
PromotionRepository:
@Repository
public interface PromotionRepository extends JpaRepository<Promotion, Long> {

    @Query("SELECT promotion "
            + "FROM Promotion promotion "
            + "INNER JOIN promotion.details details "
            + "WHERE details.product.id = :productId "
            + "AND CURRENT_DATE BETWEEN promotion.startDate AND promotion.endDate")
    Promotion findOneByProductId(@Param("productId") Long productId);

}

But this error occured:
Stacktrace:
Caused by: java.lang.StackOverflowError: null
    at java.lang.StringBuilder.append(Unknown Source)
    at java.lang.StringBuilder.<init>(Unknown Source)
    at com.example.entity.PromotionDetails.toString(PromotionDetails.java:18)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at java.util.AbstractCollection.toString(Unknown Source)
    at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:527)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at com.example.entity.Promotion.toString(Promotion.java:18)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at com.example.entity.PromotionDetails.toString(PromotionDetails.java:18)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at java.util.AbstractCollection.toString(Unknown Source)
    at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:527)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at com.example.entity.Promotion.toString(Promotion.java:18)
    ...
    ...
    ...
    ...
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at jp.co.worksap.stm.entity.sales.PromotionDetails.toString(PromotionDetails.java:18)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at java.util.AbstractCollection.toString(Unknown Source)
    at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:527)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at jp.co.worksap.stm.entity.sales.Promotion.toString(Promotion.java:18)

I know it seems like Promotion is calling PromotionDetails and PromotionDetails is calling Promotion and so on. But, how do I fix this?
--EDIT--
I would like to add something. I am using Lombok to generate Getter, Setter, and toString

A:

You can exclude fields from the ToString generation in Lombok. For that, you have to add the @ToString annotation to your class and add the fields, which you want to exclude. In your case, i would exclude the field details in the Promotion class:
@ToString(exclude="details")
public class Promotion {}

A:

com.example.entity.PromotionDetails.toString(PromotionDetails.java:18)
.
.
.
jp.co.worksap.stm.entity.sales.Promotion.toString(Promotion.java:18)

You have a recursive call on the toString() of both entities I guess, 
PromotionDetails is trying to print Promotion while Promotion is trying to print all its PromotionsDetails
A solution would be :
 Remove either Promotion value from the PromotionDetails toString() method or remove PromotionDetails from the toString() of Promotion.
Becareful with toString() presentation of entities it can cause you trouble.

