import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.FastOutput; import com.esotericsoftware.minlog.Log; import org.junit.Test; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; /** * Created by ajvanerp on 24/08/15. */ public class ThreeLevelsDownStackOverflow { @Test public void goBananas() { BarRef barRef = new BarRef(); GenericBar genBar1 = new GenericBar<>(barRef); GenericBar genBar2 = new GenericBar<>(barRef); List> bars = new ArrayList<>(); bars.add(genBar2); bars.add(genBar1); // Now added another generics class in the mix. // During serialization there now is no direct link between genericsScope and parentScope // But rather there is a cycle. new GenericContainer<>(new BarContainer(bars)); Kryo kryo = new Kryo(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Log.set(Log.LEVEL_TRACE); kryo.writeObject(new FastOutput(outputStream), genBar1); } } class GenericContainer { BarContainer barContainer; public GenericContainer(BarContainer barContainer) { this.barContainer = barContainer; for (GenericBar foo : barContainer.foos) { foo.container = this; } } } class BarContainer { List> foos; public BarContainer(List> foos) { this.foos = foos; } } interface Bar {} class BarRef implements Bar {} class GenericBar implements Bar { private Map map = Collections.singletonMap("myself", (Object) this); B foo; GenericContainer container; public GenericBar(B foo) { this.foo = foo; } }