Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StackOverflowError when calling Spring Data MongoDB repository method with a page size bigger than 36

I am getting a StackOverflowError when calling a method of my MongoDB repository interface:

public interface TermRepository extends MongoRepository<Term, String>, QuerydslPredicateExecutor<Term> {
    // [...]
    @Query("{$or:[{'apis' : {$in : ?0 } }, {$text:{$search:?1}}]}")
    Page<Term> globalSearch(List<DBRef> apis, String searchKeyword, Pageable pageable);
}
  • apis is a list with just one DBRef: new DBRef("api", new ObjectId("5e3ad9faaafa595898b6a682"))

  • searchKeyword equals "accounts"

  • pageable is Page request [number: 0, size 37, sort: UNSORTED]. If size is 36, it doesn't throw the StackOverflowError!
  • The query gets translated into
{
    $or: [{
        'apis': {
            $in: [{
                '$ref': 'api',
                '$id': ObjectId('5e3ad9faaafa595898b6a682')
            }]
        }
    }, {
        $text: {
            $search: 'account'
        }
    }]
}
  • If I execute the query directly in mongo, it returns 55 elements.
  • I've tried to increase thread stack to -Xss1G (it's a lot, I know), and it just keeps filling the stack slowly and won't return. If I rerun the test with a page size of 36, it returns immediately.

Does anyone have a clue what's happening?

The Term:

public class Term {

    @Id
    private String id;

    @NotBlank
    @TextIndexed
    @JsonProperty
    private String name;

    @NotBlank
    @TextIndexed
    @JsonProperty
    private String objectType;

    @Transient
    @JsonProperty
    private String snakeCase;

    @NotEmpty
    @JsonProperty
    private List<String> functionalCategories;

    @NotNull
    @JsonProperty
    private TermTypeEnum termType;

    @NotEmpty
    @JsonProperty
    private Map<String, String> description;

    @Setter
    @NotNull
    @JsonProperty
    private TermStateEnum state;

    @NotBlank
    @TextIndexed
    @JsonProperty
    private String example;

    @DBRef
    @NotNull
    @Indexed
    @JsonProperty
    private List<Api> apis;

    @DBRef
    @NotNull
    @JsonProperty
    private User contributor;

    @NotBlank
    @TextIndexed
    @JsonProperty
    private String version;

    @DBRef
    @JsonProperty
    private Map<String, Term> attributes;
}

The stacktrace: https://pastebin.com/y0XYt7p6

Although there might be a circular reference because Term has an attribute Map<String, Term>, I think it's not a circular reference what is producing the stack overflow.

Doing some debug, I saw that the stack overflow occurs because in the end spring-data keeps instantiating this Term only (not others, so I don't see the circular reference):

Term(id=5e3ad9faaafa595898b6a7ea, name=debitCurrency, objectType=string, snakeCase=debit_currency, functionalCategories=null, termType=BODY, description={"english"=Debit Currency.}, state=PROPOSED, example=null, apis=[Api(id=5e3ad9faaafa595898b6a67f, name=Payments-1.0.1, description=null, responsible=null)], contributor=null, version=null, attributes=null)

Which in turn does not reference other terms.

Here is another Term, just for comparison:

Term(id=5e3ad9faaafa595898b6a6c8, name=displayCardNumber, objectType=string, snakeCase=display_card_number, functionalCategories=null, termType=BODY, description={"english"=Related card number to the account.}, state=PROPOSED, example=null, apis=[Api(id=5e3ad9faaafa595898b6a682, name=Accounts-1.0.2, description=null, responsible=null)], contributor=null, version=null, attributes=null)

I see no difference, but debitCurrency produces the stack overflow and displayCardNumber doesn't.

like image 644
Eduard Avatar asked Nov 06 '22 10:11

Eduard


1 Answers

I was having a circular reference (self-reference more accurately) indeed.

I've come up with a workaround that consists of making the @DBRef of attributes, lazy=true, and implementing a custom serializer of the class Term, wich has the self-reference (or circular reference). The reason of implementing the custom serializer, is that I can save a set of the objects that have already been serialized, and if I have to seralize an object again, I just don't.

like image 192
Eduard Avatar answered Nov 12 '22 17:11

Eduard