Bidirectional relationships in JPA, where two entities each hold a reference to the other, need to be configured carefully with an owning side and a mappedBy side, and handled deliberately during JSON serialization to avoid infinite recursion between the two entities calling each other's getters endlessly.
Key Points: • One side owns the relationship and controls the foreign key; the other side uses mappedBy to point back to the owning field, avoiding duplicate join columns or tables. • Both sides of the in-memory relationship must be kept in sync manually, typically with a helper method that updates both collections/references together. • @JsonManagedReference (on the owning/forward side) and @JsonBackReference (on the back-reference side) tell Jackson to serialize one direction and skip the other, preventing infinite recursion. • A cleaner, more scalable alternative to reference annotations is to use dedicated DTOs for API responses instead of serializing entities directly, giving full control over what's exposed. • Lazy loading (the default for collections) also needs care here, since accessing the back-reference outside a transaction can trigger a LazyInitializationException.
Example: An Order entity has a List<OrderItem> and each OrderItem has a back-reference to its Order; without @JsonManagedReference/@JsonBackReference (or a DTO), serializing an Order to JSON would serialize its items, each of which would try to serialize its parent Order again, recursing forever.
Code Example:
@Entity
public class Order {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
@JsonManagedReference
private List<OrderItem> items = new ArrayList<>();
}
@Entity
public class OrderItem {
@Id @GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "order_id")
@JsonBackReference
private Order order;
}Interview Tip: A concise interview answer is:
"I set up the relationship with a clear owning side that holds the foreign key and a mappedBy side on the other entity, and I keep both sides in sync in code with a helper method. For serialization, I either use @JsonManagedReference and @JsonBackReference to break the recursive cycle, or, more often in real projects, I just expose DTOs from the API instead of serializing entities directly, which sidesteps the whole problem."