morphia icon indicating copy to clipboard operation
morphia copied to clipboard

StackOverflowError when saving entity with recursive type

Open itdv opened this issue 1 year ago • 0 comments

Describe the bug When attempting to save a recursive type entity or entity that includes a recursive type (i.e., a field of its own type) in Morphia 2.4.14, a StackOverflowError occurs. The issue can be reproduced with the following code.

import com.mongodb.client.MongoClients;
import dev.morphia.Datastore;
import dev.morphia.Morphia;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import org.bson.types.ObjectId;

public class Main {

    @Entity
    public static class A {
        @Id
        private ObjectId id;
        B b;

        public A(ObjectId id, B b) {
            this.id = id;
            this.b = b;
        }

        public A() {
        }
    }

    @Entity
    public static class B {
        B innerB;
        public B(){
        }

        public B(B innerB) {
            this.innerB = innerB;
        }
    }


    public static void main(String[] args) {
        try (var mongoClient = MongoClients.create()) {
            // Create Datastore using Morphia
            Datastore ds = Morphia.createDatastore(mongoClient, "morphia-2-4-4-test");
            ds.getMapper().map(Main.A.class);  // map the entity class
            ds.getMapper().map(B.class);  // map the entity class

            B b = new B(null);
            A a = new A(new ObjectId(), b);

            ds.save(a);

        }
    }
}

(The same if A itself is a recursive type.) The above code is running correctly with morphia 2.3.4, but in later versions, from 2.3.5 up to 2.4.14 StackOverflowError is thrown:

Exception in thread "main" java.lang.StackOverflowError
	at java.base/java.util.concurrent.ConcurrentHashMap.containsKey(ConcurrentHashMap.java:964)
	at dev.morphia.mapping.Mapper.isMapped(Mapper.java:416)
	at dev.morphia.mapping.codec.MorphiaCodecProvider.get(MorphiaCodecProvider.java:74)
	at org.bson.codecs.configuration.CodecProvider.get(CodecProvider.java:70)
	at org.bson.internal.ProvidersCodecRegistry.getFromCodecProvider(ProvidersCodecRegistry.java:95)
	at org.bson.internal.ProvidersCodecRegistry.lambda$get$0(ProvidersCodecRegistry.java:82)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:80)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:50)
	at dev.morphia.mapping.codec.pojo.PropertyModel.configureCodec(PropertyModel.java:389)
	at dev.morphia.mapping.codec.pojo.PropertyModel.specializeCodec(PropertyModel.java:289)
	at dev.morphia.mapping.codec.pojo.MorphiaCodec.specializePropertyCodecs(MorphiaCodec.java:199)
	at dev.morphia.mapping.codec.pojo.MorphiaCodec.<init>(MorphiaCodec.java:71)
	at dev.morphia.mapping.codec.MorphiaCodecProvider.get(MorphiaCodecProvider.java:76)
	at org.bson.codecs.configuration.CodecProvider.get(CodecProvider.java:70)
	at org.bson.internal.ProvidersCodecRegistry.getFromCodecProvider(ProvidersCodecRegistry.java:95)
	at org.bson.internal.ProvidersCodecRegistry.lambda$get$0(ProvidersCodecRegistry.java:82)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:80)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:50)
	at dev.morphia.mapping.codec.pojo.PropertyModel.configureCodec(PropertyModel.java:389)
	at dev.morphia.mapping.codec.pojo.PropertyModel.specializeCodec(PropertyModel.java:289)
	at dev.morphia.mapping.codec.pojo.MorphiaCodec.specializePropertyCodecs(MorphiaCodec.java:199)
	at dev.morphia.mapping.codec.pojo.MorphiaCodec.<init>(MorphiaCodec.java:71)
	at dev.morphia.mapping.codec.MorphiaCodecProvider.get(MorphiaCodecProvider.java:76)
	at org.bson.codecs.configuration.CodecProvider.get(CodecProvider.java:70)
	at org.bson.internal.ProvidersCodecRegistry.getFromCodecProvider(ProvidersCodecRegistry.java:95)
	at org.bson.internal.ProvidersCodecRegistry.lambda$get$0(ProvidersCodecRegistry.java:82)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:80)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:50)
	at dev.morphia.mapping.codec.pojo.PropertyModel.configureCodec(PropertyModel.java:389)
	at dev.morphia.mapping.codec.pojo.PropertyModel.specializeCodec(PropertyModel.java:289)
	at dev.morphia.mapping.codec.pojo.MorphiaCodec.specializePropertyCodecs(MorphiaCodec.java:199)
	at dev.morphia.mapping.codec.pojo.MorphiaCodec.<init>(MorphiaCodec.java:71)
	at dev.morphia.mapping.codec.MorphiaCodecProvider.get(MorphiaCodecProvider.java:76)
	at org.bson.codecs.configuration.CodecProvider.get(CodecProvider.java:70)
	at org.bson.internal.ProvidersCodecRegistry.getFromCodecProvider(ProvidersCodecRegistry.java:95)
	at org.bson.internal.ProvidersCodecRegistry.lambda$get$0(ProvidersCodecRegistry.java:82)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)

itdv avatar Sep 10 '24 15:09 itdv