How to fix this Morphia mapping issue??? ---> W

2019-05-30 08:10发布

So here goes the problem leading to the question...

I have this javaEE application running on jBoss using MongoDB database. I use Morphia to communicate with mongo... The application has the following basic program components;

@EntityListeners(RootEntityListener.class)
public class RootEntity {
    @Id
    protected ObjectId id;
    @Indexed
    protected Long uid;
    @Indexed
    protected boolean active;
    ...
}

@Entity
public class User extends RootEntity {
    ...
}

@Entity
public class News extends RootEntity {
    ...
}

And then my Morphia config looks as follows;

//Morphia Setup
morphia = new Morphia();
morphia.map(User.class).map(News.class);
...

Then I do a query by calling the method shown below;

public List<News> findByUID(Long uId){
    Query<News> query = getNewsQuery().field("active").equal(true).field("uid").equal(uId);
    return query.asList();
}

Fine! So far... no error. But I get a weird warning for each model (User and News). See StackTrace below:

WARNING [org.mongodb.morphia.mapping.DefaultCreator] (http-localhost-127.0.0.1-8080-3) Class not found defined in dbObj: : 
java.lang.ClassNotFoundException: com.package.models.News from [Module "deployment.Wealth.war:main" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120)
at java.lang.Class.forName0(Native Method) [rt.jar:1.7.0_45]
at java.lang.Class.forName(Unknown Source) [rt.jar:1.7.0_45]
at org.mongodb.morphia.mapping.DefaultCreator.getClass(DefaultCreator.java:89) [morphia-0.109.jar:]
at org.mongodb.morphia.mapping.DefaultCreator.createInstance(DefaultCreator.java:37) [morphia-0.109.jar:]
at org.mongodb.morphia.mapping.Mapper.fromDBObject(Mapper.java:298) [morphia-0.109.jar:]
at org.mongodb.morphia.query.MorphiaIterator.convertItem(MorphiaIterator.java:79) [morphia-0.109.jar:]
at org.mongodb.morphia.query.MorphiaIterator.processItem(MorphiaIterator.java:65) [morphia-0.109.jar:]
at org.mongodb.morphia.query.MorphiaIterator.next(MorphiaIterator.java:60) [morphia-0.109.jar:]
at org.mongodb.morphia.query.QueryImpl.asList(QueryImpl.java:312) [morphia-0.109.jar:]
at ng.wealth.business.NewsBean.findByActive(NewsBean.java:99) [classes:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) [rt.jar:1.7.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) [rt.jar:1.7.0_45]
at java.lang.reflect.Method.invoke(Unknown Source) [rt.jar:1.7.0_45]
...(*the rest omitted for brevity*)...

Now, I have found that this may have something to do with Morphia's class mapping... That org.mongodb.morphia.mapping.DefaultCreator is not loading the entity classes (User and News).

So after much research... and referencing the solution (they say it works) found here https://code.google.com/p/morphia/issues/detail?id=208, I override the org.mongodb.morphia.mapping.DefaultCreator by adding the following to my morphia config;

morphia.getMapper().getOptions().objectFactory = new DefaultCreator() {
    @Override
    protected ClassLoader getClassLoaderForClass() {
        return RootEntity.class.getClassLoader();
    }
};

Note: that in the original solution, the overriden method was getClassLoaderForClass(String clazz, DBObject object) but in my case (due to my version of Morphia - 0.109 - which i believe is probably the most recent obtained from mongo official site), the method is getClassLoaderForClass(). So, I accordingly override it by returning my RootEntity class loader.

But still the WARNING keeps coming. It doesn't necessarily break code because the Classes (User and News) actually get loaded and I can still grab values normally from them. But my logs get flooded with these warnings and perhaps I'm not just comfortable knowing that some part of the application still misbehaves with these strange warnings.

So what I need is a permanent solution to this problem... and a concrete explanation of why the answer actually solves the problem. Thanks y'all!

3条回答
叼着烟拽天下
2楼-- · 2019-05-30 08:22

I think the @Id annotation is required. The easy way out would be to add it with @Id protected ObjectId id. Or you ensure that your uid is unique, then you could use @Id protected Long uid (already indexed so @Indexed is then unnecessary).

PS: Not sure if indexing a boolean is worth it, since the cardinality is so low. And for your query you'd need a compound index anyway.

查看更多
SAY GOODBYE
3楼-- · 2019-05-30 08:37

I only just saw this post this morning (coming from your other post) so first, I apologize for that. (The mongodb-users list has a bit more visibility for me but I do try to monitor and respond here when I can.) I just ran your test case on Morphia's master branch and got no weird errors. (master is just a few commits beyond 1.0.1.) If you're not too far down the path of moving to a pure driver solution, I'd recommend 1.0.1 and make sure migrating is necessary.

查看更多
forever°为你锁心
4楼-- · 2019-05-30 08:45

I had the same problem with a Play 2.4 application. For me, this worked:

// Overwrite objectFactorys ClassLoader Method to use Plays ClassLoader
// This prevents the log from beeing spammed with Warning-Messages about ClassNotFoundExceptions happening in Morphias objectFactory
morphia.getMapper().getOptions().setObjectFactory(new DefaultCreator() {
    @Override
    protected ClassLoader getClassLoaderForClass() {
        if(Play.maybeApplication().isDefined()) {
            return Play.classloader(Play.maybeApplication().get());
        } else {
            return PersistedObject.class.getClassLoader();
        }
    }
});

I don't know JavaEE very well, but they too have their own class loading paradigms which you need to take into consideration. Hope it helps.

查看更多
登录 后发表回答