3
votes

I am using hibernate 5 as a JPA implementation and I have an issue with a @OneToMany bidirectinal relationship.

These are my entities:

@Entity(name = "product_item")
public class ProductItem {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "receptacle")
    private Receptacle receptacle;

...

}

@Entity(name = "receptacle")
public class Receptacle {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @OneToMany(mappedBy = "receptacle", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Set<ProductItem> productItems = new HashSet<>();

...

}

I would like this relationship to be lazy in both directions as I want to manually fetch the data through FETCH JOIN like the query below:

String query = "SELECT " 
            + " DISTINCT r" 
            + " FROM" 
            + " receptacle r"
            + " JOIN FETCH product_item pi ON r.id = pi.receptacle.id"
            + " JOIN ereturn er ON er.id = pi.ereturn.id"
            + " WHERE"
            + " r.masterCrossDock IS NULL"; 

But my problem is that hibernate is ignoring the @ManyToOne(fetch = FetchType.LAZY) hence Jackson breaks due to Infinite recursion (StackOverflowError) through reference chain as shown below:

org.glassfish.jersey.server.internal.process.MappableException: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: returnitRest.Receptacle["productItems"]->org.hibernate.collection.internal.PersistentSet[0]->returnitRest.ProductItem["receptacle"]->returnitRest.Receptacle["productItems"]->org.hibernate.collection.internal.PersistentSet[0]->returnitRest.ProductItem["receptacle"]- ...

QUESTION 1: How could I tell hibernate not to fetch the @ManyToOne relationship direction?

QUESTION 2: If what I am trying to do is not possible, why?

QUESTION 3: What would be the best way of doing what I am trying to do?

thank you very much

1
I doubt the problem may not be due to ManyToOne being Lazy or Eager. You may need to break that cycle for jackson and I believe you may need to place @JsonIgnore on one side of the association.Madhusudana Reddy Sunnapu
@MadhusudanaReddySunnapu why do you think lazy fetching won't help me?masber
Once you specify ManyToOne as Lazy, hibernate honours that and doesn't fectch the ManyToOne. But, what I think is happening is, subsequently during the jackson deserialization it tries to deserialize the ManyToOne assocation as well, unless we tell jackson to ignore it, and thus it causes the ManyToOne to be fetched at that point and subsequently this goes into a deserialization cycle.Madhusudana Reddy Sunnapu
I have not tried it but to rule out hibernate, you may want to manually create a ProductItem and Receptacle object and manually associate them in OneToMany and ManyToOne setters and try jackson deserialization on this object.Madhusudana Reddy Sunnapu
I close the entityManager before jackson kicks in... I wonder whether hibernate knows that the parent object is already in cache hence it creates the cycle automatically hence lazy fetching means do not go to database to get the object but build it if already in cache. Does it makes sense?masber

1 Answers

0
votes

According to the JPA specs, LAZY loading is a hint that the provider can totally ignore , It's totally up to the provider (hibernate here) to either consider it or ignore it (given also that single-valued associations -OneToOne and ManyToOne - are eagerly loaded by default).... So you can't rely on it.

Concerning the recursive problem, check my post here , I had a similar issue with gson and this is how I solved it