-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NPE when trying to find rootTable #25
Comments
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. 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 |
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. |
Closing since no testcase. Attach a testcase here and it can be reopened |
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);
}
}
} |
Added schema and unit tests (needs little modification for connection to your local MongoDB test database): I'm working with MongoDB 2.4 and the master repository for DataNucleus sources. |
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 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). |
is happening. May relate to #25 or may not, but unconfirmed since no testcase still
Thank you! Your commit fixed the problem. |
In org.datanucleus.store.mongodb.MongoDBUtils.getClassNameForIdentity(Object, AbstractClassMetaData, ExecutionContext, ClassLoaderResolver) I get a NullPointerException when it is tried to retrieve the table for an abstract superclass.
Table rootTable = storeMgr.getStoreDataForClass(rootCmd.getFullClassName()).getTable();
getStoreDataForClass comes back with NULL as result for an abstract superclass. I investigated the table of the storeDataManager and it contains only entries for concrete classes, am I doing something wrong in my annotation?
@PersistenceCapable(detachable = "true", identityType = IdentityType.APPLICATION, objectIdClass = Id.class) @Discriminator(strategy = DiscriminatorStrategy.CLASS_NAME) @Inheritance(strategy = InheritanceStrategy.COMPLETE_TABLE) public abstract class SuperClass { ..
The text was updated successfully, but these errors were encountered: