Giter Club home page Giter Club logo

Comments (7)

nonstans avatar nonstans commented on July 20, 2024

I further investigated the problem. I noticed that problem vanishes as soon as I don't fetch a collection in one of the subclasses. So I can successfully read a User (see example) but not a UserGroup containing a list of users.
See my schema example:
Schema.zip

Again I'm not sure whether my annotations are right? To provide a running testcase requires more time. I could prepare something tomorrow, if you need it.

StackTrace:

Caused by: java.lang.NullPointerException
at org.datanucleus.store.mongodb.MongoDBUtils.getClassNameForIdentity(MongoDBUtils.java:199)
at org.datanucleus.store.mongodb.MongoDBStoreManager.getClassNameForObjectID(MongoDBStoreManager.java:132)
at org.datanucleus.ExecutionContextImpl.getClassNameForObjectId(ExecutionContextImpl.java:3503)
at org.datanucleus.ExecutionContextImpl.getClassDetailsForId(ExecutionContextImpl.java:3392)
at org.datanucleus.ExecutionContextImpl.findObject(ExecutionContextImpl.java:3568)
at org.datanucleus.identity.IdentityUtils.getObjectFromIdString(IdentityUtils.java:442)
at org.datanucleus.store.mongodb.fieldmanager.FetchFieldManager.getValueForContainerRelationField(FetchFieldManager.java:970)
at org.datanucleus.store.mongodb.fieldmanager.FetchFieldManager.fetchNonEmbeddedObjectField(FetchFieldManager.java:737)
at org.datanucleus.store.mongodb.fieldmanager.FetchFieldManager.fetchObjectField(FetchFieldManager.java:685)
at org.datanucleus.state.AbstractStateManager.replacingObjectField(AbstractStateManager.java:1588)
at org.datanucleus.state.StateManagerImpl.replacingObjectField(StateManagerImpl.java:1)
at de.mpg.ipp.codac.business.schema.teamwork.UserGroup.dnReplaceField(UserGroup.java)
at de.mpg.ipp.codac.business.schema.common.W7XDbNamedObject.dnReplaceFields(W7XDbNamedObject.java)
at org.datanucleus.state.StateManagerImpl.replaceFields(StateManagerImpl.java:3115)
at org.datanucleus.state.StateManagerImpl.replaceFields(StateManagerImpl.java:3141)
at org.datanucleus.store.mongodb.MongoDBUtils$1.fetchFields(MongoDBUtils.java:761)
at org.datanucleus.state.StateManagerImpl.loadFieldValues(StateManagerImpl.java:2245)
at org.datanucleus.state.StateManagerImpl.initialiseForHollow(StateManagerImpl.java:262)
at org.datanucleus.state.ObjectProviderFactoryImpl.newForHollow(ObjectProviderFactoryImpl.java:112)
at org.datanucleus.ExecutionContextImpl.findObject(ExecutionContextImpl.java:3098)
at org.datanucleus.store.mongodb.MongoDBUtils.getObjectUsingApplicationIdForDBObject(MongoDBUtils.java:756)
at org.datanucleus.store.mongodb.MongoDBUtils.getPojoForDBObjectForCandidate(MongoDBUtils.java:718)
at org.datanucleus.store.mongodb.query.LazyLoadQueryResult.getNextObject(LazyLoadQueryResult.java:324)
at org.datanucleus.store.mongodb.query.LazyLoadQueryResult$QueryResultIterator.next(LazyLoadQueryResult.java:449)
at de.mpg.ipp.codac.persistence.DataNucleusProvider.doGetObjects(DataNucleusProvider.java:293)
... 31 more

from datanucleus-mongodb.

andyjefferson avatar andyjefferson commented on July 20, 2024

As the documentation says clearly enough, and the issue template, a valid testcase is required for ALL problems. Failure to provide will will mean the issue is closed.

from datanucleus-mongodb.

andyjefferson avatar andyjefferson commented on July 20, 2024

Closing since no testcase. Attach a testcase here and it can be reopened

from datanucleus-mongodb.

nonstans avatar nonstans commented on July 20, 2024

Please reopen this issue, because this must be a big problem for everyone working with MongoDB and an abstract root class. I don't understand enough of the concepts of the StoreManager and StoreData to fix the problem by myself.

I commented the problems in the code for you (please scroll to see all comments) :

String org.datanucleus.store.mongodb.MongoDBUtils.getClassNameForIdentity(Object id, AbstractClassMetaData rootCmd, ExecutionContext ec, ClassLoaderResolver clr)
{
        Map<String, Set<String>> classNamesByDbCollectionName = new HashMap<>();
        StoreManager storeMgr = ec.getStoreManager();
        Set rootClassNames = new HashSet<String>();
        rootClassNames.add(rootCmd.getFullClassName());
        StoreData storeData = storeMgr.getStoreDataForClass(rootCmd.getFullClassName()); //comment: since my root class is abstract there is no entry in the table storeDataMgr.storeDataByClass, so storeData is null
        Table rootTable = null;
        String rootTableName = "";
        if (storeData != null)
        {
            rootTable = storeData.getTable();
            rootTableName = rootTable.getName();
        }
        else
        {
            // how to access the rootTable via name?
            rootTableName = rootCmd.getTable(); //comment: since storeData is null, rootTable is also null
        }
        classNamesByDbCollectionName.put(rootTableName, rootClassNames);
        Collection<String> subclassNames = storeMgr.getSubClassesForClass(rootCmd.getFullClassName(), true, clr);
        if (subclassNames != null && !subclassNames.isEmpty())
        {
            for (String subclassName : subclassNames)
            {
                AbstractClassMetaData cmd =  ec.getMetaDataManager().getMetaDataForClass(subclassName, clr);
                StoreData subStoreData = storeMgr.getStoreDataForClass(cmd.getFullClassName());
                Table subTable = null;
                String subTableName = "";
                if (subStoreData != null)
                {
                    subTable = subStoreData.getTable();
                    subTableName = subTable.getName();
                }
                else
                {
                    // how to access the subTable via name?
                    subTableName = cmd.getTable();
                }
                // Table subTable = storeMgr.getStoreDataForClass(cmd.getFullClassName()).getTable();
                // String subTableName = subTable.getName();
                Set<String> classNames = classNamesByDbCollectionName.get(subTableName);
                if (classNames == null)
                {
                    classNames = new HashSet<String>();
                    classNamesByDbCollectionName.put(subTableName, classNames);
                }
                classNames.add(cmd.getFullClassName());
            }
        }

        ManagedConnection mconn = storeMgr.getConnection(ec);
        try
        {
            DB db = (DB) mconn.getConnection();

            for (Map.Entry<String, Set<String>> dbCollEntry : classNamesByDbCollectionName.entrySet())
            {
                // Check each DBCollection for the id PK field(s)
                String dbCollName = dbCollEntry.getKey();
                if (dbCollName == null) continue; //comment: I added this. For some reason this is null for some classes, so I have to continue to prevent an NPE
                Set<String> classNames = dbCollEntry.getValue();                
                DBCollection dbColl = db.getCollection(dbCollName);
                BasicDBObject query = new BasicDBObject();
                if (rootCmd.getIdentityType() == IdentityType.DATASTORE)
                {
                    Object key = IdentityUtils.getTargetKeyForDatastoreIdentity(id);
                    if (storeMgr.isStrategyDatastoreAttributed(rootCmd, -1))
                    {
                        query.put("_id", new ObjectId((String) key));
                    }
                    else
                    {
                        query.put(rootTable.getDatastoreIdColumn().getName(), key);
                    }
                }
                else if (rootCmd.getIdentityType() == IdentityType.APPLICATION)
                {
                    if (IdentityUtils.isSingleFieldIdentity(id))
                    {
                        Object key = IdentityUtils.getTargetKeyForSingleFieldIdentity(id);
                        int[] pkNums = rootCmd.getPKMemberPositions();
                        AbstractMemberMetaData pkMmd = rootCmd.getMetaDataForManagedMemberAtAbsolutePosition(pkNums[0]);
                        String pkPropName = rootTable.getMemberColumnMappingForMember(pkMmd).getColumn(0).getName(); //comment: since rootTable is null, this leads to an NPE
                        query.put(pkPropName, key);
                    }
                    else
                    {
                        int[] pkNums = rootCmd.getPKMemberPositions();
                        for (int i = 0; i < pkNums.length; i++)
                        {
                            AbstractMemberMetaData pkMmd = rootCmd.getMetaDataForManagedMemberAtAbsolutePosition(pkNums[i]);
                            String pkPropName = rootTable.getMemberColumnMappingForMember(pkMmd).getColumn(0).getName();
                            Object pkVal = IdentityUtils.getValueForMemberInId(id, pkMmd);
                            query.put(pkPropName, pkVal);
                        }
                    }
                }

from datanucleus-mongodb.

nonstans avatar nonstans commented on July 20, 2024

Added schema and unit tests (needs little modification for connection to your local MongoDB test database):
schema.zip
DN5UnitTest.zip

I'm working with MongoDB 2.4 and the master repository for DataNucleus sources.

from datanucleus-mongodb.

andyjefferson avatar andyjefferson commented on July 20, 2024

Sorry, but no the DN test suite has abstract root classes and the DN test suite is run before releases, and it works great for me. The onus is on the raiser to demonstrate the problem. Just dumping some class here isn't a demonstration. As the issue template says clearly enough, we provide you with a template for testcases to minimise how much you need to do to reproduce things, and then just type "mvn clean test" and it runs. Here it is again
https://github.com/datanucleus/test-jdo

And when I dump your classes into this template I get the attached "test.zip". I run it. It passes.

If you want something reopened you kindly take this and UPDATE it and repost it here with something that reproduces a problem. Some persistable class not being known about implies metadata is not loaded for it at the time you invoke some operation, and only you know how you create your PMF (persistence-unit?, properties file? using auto-start? etc etc).

test.zip

from datanucleus-mongodb.

nonstans avatar nonstans commented on July 20, 2024

Thank you! Your commit fixed the problem.
I didn't recognize that there is a template for testcases. Sorry! Next time I'll provide a testcase using the template.

from datanucleus-mongodb.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.