Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring-data-mongodb @DBRef causing infinite recursion? I can't work out why

Ok, so I have a very simple set of Java POJOs in my spring application.

Here is my person class :

@Document(collection="people")
public class Person {    

    // Data.
    @Id
    private ObjectId Id;    

    @DBRef
    private List<Entity> entities;    


    /* Getters and setters removed to keep this question simple. */
}    

And, here is my entity class.

@Document(collection = "entities")
public class Entity {    

    @Id
    private ObjectId Id;    

    @DBRef
    private List<Person> people;    

    /* Getters and setters removed to keep question simple. */
}    

Now, in my spec, "Person" and "Entity" have a Many-Many relationship. A Person can be registered to lots of Entities, and the reverse is true, too.

Now, for some reason, when I try and persist these two, into each other's lists, I get this weird error I have never seen :

2017-05-17 23:37:51.966 ERROR 29918 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError) (through reference chain: restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"] 

... This continues until the stack overflows. Sorry it is all on one line, wasn't sure how to fix that on this site... it is cut straight from my terminal. 

What did I do wrong? I have been doing pretty well so far at learning this stack, but I just can't see what is wrong here.

like image 235
IWishIWasABarista Avatar asked Oct 27 '25 04:10

IWishIWasABarista


1 Answers

Yes this case can occur! Consider you have:

person1 = {"entities" : ["entity1", "entity2"]}
entity1 = {"persons" : ["person1", "person2"]}

So using your above configuration, when spring tries to load "person1", it will load its related "entities(entity1 & entity2)" as well. Now when spring tries to load "entity1", it will again have to load "person1" and so, which definitely leads to Circular dependency/ recursion!

restServer.dto.Person["entity"]->restServer.dto.Entity["people"]->java.util.ArrayList[0]->restServer.dto.Person["entity"]->restServer.dto.Entity["people"]...

So you can handle this by many ways:

1. Annotating your lists as lazy:

@Document(collection="people")
public class Person {    

    // Data.
    @Id
    private ObjectId Id;    

    @DBRef(lazy = true)
    private List<Entity> entities;    


    /* Getters and setters removed to keep this question simple. */
} 

@Document(collection = "entities")
public class Entity {    

    @Id
    private ObjectId Id;    

    @DBRef(lazy = true)
    private List<Person> people;    

    /* Getters and setters removed to keep question simple. */
}

lazy = true will prevent Spring from loading un-necessary entities unless you need it(which you can load it by making an explicit call)

2. Making list entities as Embedded documents:

@Document(collection="people")
public class Person {    

    // Data.
    @Id
    private ObjectId Id;    
    private List<Entity> entities;    


    /* Getters and setters removed to keep this question simple. */
} 

@Document(collection = "entities")
public class Entity {    

    @Id
    private ObjectId Id;    
    private List<Person> people;    

    /* Getters and setters removed to keep question simple. */
}

But it totally depends on your requirements.

like image 188
Afridi Avatar answered Oct 29 '25 20:10

Afridi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!