0

I am trying to query for a list of ids of type Long in GAE/JDO. And I'm getting the following exception when I call detachCopyAll() on the result set.

org.datanucleus.jdo.exceptions.ClassNotPersistenceCapableException: The class "The class "java.lang.Long" is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found." is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data for the class is not found.
at org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:241)
at org.datanucleus.jdo.JDOPersistenceManager.jdoDetachCopy(JDOPersistenceManager.java:1110)
at org.datanucleus.jdo.JDOPersistenceManager.detachCopyAll(JDOPersistenceManager.java:1183)
...

I can query for a list of User objects and detach them just fine. I expected all primitive wrapper classes like Long to be persistable. What am I doing wrong? Below is the code I'm working with.

@PersistenceCapable(identityType=IdentityType.APPLICATION, detachable="true")
public class User
{
    @PrimaryKey
    @Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY) 
    private Long id;

    private String email;
}

@SuppressWarnings("unchecked")
public static List<Long> getUserKeys(String email)
{
    assert email != null;
    List<Long> keyList = null;
    PersistenceManager pm = null;
    Query query = null;
    try {
        pm = PMF.get().getPersistenceManager();    
        query = pm.newQuery("select id from " + User.class.getName());
        query.declareParameters("String emailParam");
        query.setFilter("email == emailParam");
        List<Long> resultList = (List<Long>) query.execute(email);          

        // next line causes the ClassNotPersistenceCapableException
        keyList = (List<Long>) pm.detachCopyAll(resultList);
    }
    finally {
        if (query != null) query.closeAll();
        if (pm != null) pm.close();
    }

    return keyList;
}
KenSV
  • 21
  • 4

1 Answers1

1
    List<Long> resultList = (List<Long>) query.execute(email);          

    // next line causes the ClassNotPersistenceCapableException
    keyList = (List<Long>) pm.detachCopyAll(resultList);

I don't understand what you are doing here. A List<Long> does not have to be detached. You'd want to detach instances of your User entity class, but a Long is a Long, and you can just do whatever you need to do with the resultList.

The error message is confusing, but just caused by Long not being an entity class.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • Longs actually do have to be detached. Otherwise if you try to use any data from the query after the PersistenceManager is closed, you'll get the following exception. Try it. `org.datanucleus.exceptions.NucleusUserException: Object Manager has been closed` But since I can't detach a List, I have to copy its elements out manually in a loop. This seems like an oversight by DataNucleus. – KenSV Dec 04 '11 at 07:11
  • No you do *not* detach a Long. The object passed in to detachCopyAll should be a persistable type as per the JDO spec and DataNucleus docs, and the reply by Thilo. – DataNucleus Dec 04 '11 at 07:17
  • If I don't need to detach a `List`, then why am I getting the Object Manager has been closed exception when I try to use it? – KenSV Dec 04 '11 at 07:20
  • @DataNucleus This is the workaround I am using now instead of detachCopyAll() `keyList = new ArrayList(resultList.size()); for (Long uid : resultList) { keyList.add(uid); }` – KenSV Dec 04 '11 at 07:27
  • You get "ObjectManager has not been closed" because Google didn't bother adding logic to their plugin to read all of the results before the connection is closed. i.e NOTHING TO DO WITH DETACHMENT. As already said, you only detach persistable objects – DataNucleus Dec 04 '11 at 07:50
  • Hmm. Maybe the List itself is lazy-loaded (so that you need the Object Manager around when you access it)? What do you get as the class for the List? Your workaround seems good though, a shorter one would be `keyList = new ArrayList(resultList)`. – Thilo Dec 04 '11 at 07:53
  • @Thilo and @DataNucleus, thanks, the lazy loading was the cause of the problem. I am working around that issue with the following line. `for (@SuppressWarnings("unused") Long uid : resultList) ;` It uses less memory. – KenSV Dec 04 '11 at 22:45