dbrewster
dbrewster

Reputation: 693

Saving an object to MongoDB causes StackOverflowError

Error:

2021-10-13 12:25:27.092 ERROR 21016 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause

Stack Trace (many repetitions of):

java.lang.StackOverflowError: null
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createCollection(MappingMongoConverter.java:731) ~[spring-data-mongodb-3.1.5.jar:3.1.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:646) ~[spring-data-mongodb-3.1.5.jar:3.1.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeProperties(MappingMongoConverter.java:620) ~[spring-data-mongodb-3.1.5.jar:3.1.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:596) ~[spring-data-mongodb-3.1.5.jar:3.1.5]

I am attempting a standard save and the exception I get is not informative. Here is the POJO that causes the crash upon save():

public class GameEntity {
     @Id
     @Indexed(unique = true)
     private long id;
     private List<Player> players;
     private List<Card> cards;
     private List<Card> riverCards;
     private boolean isBet;
     private boolean isDealDone;
     private BetManagerEntity betManagerEntity;

     private int desiredNumberOfPlayers;
     private int openSlots;
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date createdAt;
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date updatedAt;

//getters and setters
}

And here is the nested object:

public class BetManagerEntity {
     private int bigBlind;
     private int smallBlind;
     private int turnNumber;
     private int turnsLeftInRound;
     private List<Player> activeBetters;
     private int pot = 0;
     private int betAmount;
     private int bigBlindTurn = -1;
     private List<Bet> bets;
     private List<String> betMessages;
     private Integer maxBet;

//getters and setters

The only thing I could think of was that maybe BetManagerEntity also needed an @Id of its own, so I tried adding that and got a slightly different error:

OpenJDK 64-Bit Server VM warning: Potentially dangerous stack overflow in ReservedStackAccess annotated method java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryAcquireShared(I)I [1]
OpenJDK 64-Bit Server VM warning: Potentially dangerous stack overflow in ReservedStackAccess annotated method java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryReleaseShared(I)Z [1]
2021-10-13 12:42:54.845 ERROR 29272 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause

and

java.lang.StackOverflowError: null
    at java.base/java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryReleaseShared(ReentrantReadWriteLock.java:427) ~[na:na]
    at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.releaseShared(AbstractQueuedSynchronizer.java:1382) ~[na:na]
    at java.base/java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.unlock(ReentrantReadWriteLock.java:897) ~[na:na]
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:239) ~[spring-data-commons-2.4.5.jar:2.4.5]
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:201) ~[spring-data-commons-2.4.5.jar:2.4.5]
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:87) ~[spring-data-commons-2.4.5.jar:2.4.5]
    at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:73) ~[spring-data-commons-2.4.5.jar:2.4.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:568) ~[spring-data-mongodb-3.1.5.jar:3.1.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeCollectionInternal(MappingMongoConverter.java:821) ~[spring-data-mongodb-3.1.5.jar:3.1.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createCollection(MappingMongoConverter.java:736) ~[spring-data-mongodb-3.1.5.jar:3.1.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:646) ~[spring-data-mongodb-3.1.5.jar:3.1.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeProperties(MappingMongoConverter.java:620) ~[spring-data-mongodb-3.1.5.jar:3.1.5]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:596) ~[spring-data-mongodb-3.1.5.jar:3.1.5]

I then removed the @Id for BetManagerEntity so that it was back to how it originally was, but I still get the new stack trace when I attempt to save GameEntity

My repository is simple:

package com.brewster.poker.repository;

import com.brewster.poker.model.GameEntity;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface GameRepository extends MongoRepository<GameEntity, Long> {
}

Upvotes: 4

Views: 2331

Answers (1)

Oleksandr Chalyi
Oleksandr Chalyi

Reputation: 86

Make sure you don't have cyclic (loop) dependencies between your entities. (For instance entity Player has a reference to a Bet and a Bet to a Player).

Upvotes: 3

Related Questions