Issue
I have 2 entities with a relation of one-to-one between them: Customer and Cart. Customer is the owner of cart so a column of FK is the Customer table pointing to Cart PK.
This is Cart class:
@Entity
@Table(name = "testCart_cart")
public class Cart {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cart_id", unique = true, nullable = false)
private long id;
@OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY)
@JoinColumn(name = "cart_id")
private List<CartItem> listOfCartItems;
@OneToOne(mappedBy = "cart",
fetch = FetchType.LAZY)
private Customer customer;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<CartItem> getListOfCartItems() {
return listOfCartItems;
}
public void setListOfCartItems(List<CartItem> listOfCartItems) {
this.listOfCartItems = listOfCartItems;
}
public void setCustomer(Customer customer) { this.customer = customer; }
public Customer getCustomer() { return customer; }
@Override
public String toString() {
return "Cart{" +
"id=" + id +
", listOfCartItems=" + listOfCartItems +
", customer=" + customer +
'}';
}
}
and this is my Customer class:
@Entity
@Table(name = "testCart_customer")
public class Customer implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "id", unique = true, nullable = false)
private long id;
@Column(name = "username", unique = true, nullable = false)
private String username;
@OneToOne(cascade = CascadeType.ALL,
fetch = FetchType.LAZY)
@JoinColumn(name = "cart_id")
private Cart cart;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Cart getCart() {
return cart;
}
public void setCart(Cart cart) {
this.cart = cart;
}
@Override
public String toString() {
return "Costumer name: " + username;
}
}
So, instead of JPQL (for me is easier), I am doing this with Criteria API.
This is my code:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Cart> query = cb.createQuery(Cart.class);
Root<Customer> customer = query.from(Customer.class);
ParameterExpression<String> strignParameter = cb.parameter(String.class);
Join<Customer, Cart> carts = customer.join("cart");
query.select(carts).where(cb.equal(customer.get("username"),name));
Cart cart = entityManager.createQuery(query).getSingleResult();
return cart;
This is in console:
Exception in thread "main" java.lang.StackOverflowError
at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)
at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)
at org.hibernate.query.sqm.tree.domain.AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor(AbstractSqmAttributeJoin.java:71)
at org.hibernate.query.sqm.tree.domain.SqmSingularJoin.getJavaTypeDescriptor(SqmSingularJoin.java:52)
there are in total 1024 calls.
Tried different approaches from multiple sources plus tried to go with the debugger to see what is going on, bot nothing really explains. When the debugger jumps from query.select... to Cart cart... throws the error.
Solution
Why do you start with Customer when you want Cart.
Try this instead:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Cart> query = cb.createQuery(Cart.class);
Root<Cart> cart = query.from(Cart.class);
ParameterExpression<String> strignParameter = cb.parameter(String.class);
Join<Cart, Customer> customer = cart.join("customer");
query.select(cart).where(cb.equal(customer.get("username"), name));
Cart cart = entityManager.createQuery(query).getSingleResult();
Answered By - Simon Martinelli