Search code examples
playframework-2.0abstractmorphia

Morphia InstantiationException with abstract @Embedded class


I'm using Morphia with a Play Framework 2.1 project and a MongoDB database, and I'm having a problem with retrieving some data.

I have a class A which is and @Entity stored in a collection. But that class A has an @Embedded List property, this Class B is abstract and has multiple implementations.

But this Class B has also an @Embedded ClassC property, and this Class C is abstract too and can have multiple implementations too.

I don't think this structure is usable "as is" and that Morphia can handle it. In my database, the objects are stored correctly, no error.

{
    "_id" : ObjectId("5163c9131a887c8e5aea8d5f"),
    "className" : "package.to.ClassA",
    "list" : [
        {
            "propClassB" : [
                {
                    "className" : "package.to.an.ImplementationOfClassB",
                    "propClassC" : {
                        "className" : "package.to.an.ImplementationOfClassC"
                    }
                }
            ]
        }
    ]
}

Class A is marked @Entity,
Class B is marked @Embedded (and @Polymorphic but I don't think it's used)
Class C is marked @Embedded (and @Polymorphic too)

Am I doing something wrong ? Thanks for all !


Solution

  • Ok guys, I figured out what was my problem, and I'd never expected to be this. I found the solution on Google group for Morphia.

    It was a ClassLoader problem ! I was able to save my entities into the database, but the second after, I was not able to retrieve any entity, throwing ClassNotFoundException everywhere...

    The solution was to "override", the DefaultCreator of Morphia to provide the Play application class loader, in the Global class (which allows to customize the behaviour of the application when it starts with (onStart() and onBeforeStart() methods).

    Morphia morphia = applicationContext.getBean(Morphia.class);
    
    // Configuring class loader.
    morphia.getMapper().getOptions().objectFactory = new DefaultCreator() {
        @Override
        protected ClassLoader getClassLoaderForClass(String clazz, DBObject object) {
            return app.classloader();
        }
    };
    

    Note that I'm using Spring Framework to load the Morphia instance but I saw someone doing new Morphia(), I think it works too (not an expert ;) )

    Voila ! Hope it helps someone someday !