views:

93

answers:

2
java.lang.UnsupportedOperationException: This operation is not supported on Query Results
    at org.datanucleus.store.query.AbstractQueryResult.contains(AbstractQueryResult.java:250)
    at java.util.AbstractCollection.retainAll(AbstractCollection.java:369)
    at namespace.MyServlet.doGet(MyServlet.java:101)

I'm attempting to take one list I retrieved from a datastore query, and keep only the results which are also in a list I retrieved from a list of keys. Both my lists are populated as expected, but I can't seem to user retainAll on either one of them.

//           List<Data> listOne = new ArrayList(query.execute(theQuery));
//           DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
//           List<Data> listTwo = new ArrayList(ds.get(keys).values());
//           listOne.retainAll(listTwo);

EDIT

Ok, in an attempt to simplify, since this is apparently multiple problems in one, I have stopped using the low level API for datastore and instead of am just pulling one by one with a loop.

                List<MyClass> test = (List<MyClass>) query.execute();
                List<MyClass> test2 = new ArrayList<MyClass>();

                for (String key : favorites) {
                    test2.add(pm.getObjectById(MyClass.class, key));
                }

                log.info(test.toString());
                test.retainAll(test2);

The above works. It doesn't throw the exception. The below does throw the exception. The only difference is the log.info. I'm stumped.

                List<MyClass> test = (List<MyClass>) query.execute();
                List<MyClass> test2 = new ArrayList<MyClass>();

                for (String key : favorites) {
                    test2.add(pm.getObjectById(MyClass.class, key));
                }

                test.retainAll(test2);
A: 

If the type of collection you use for your "list of keys" does not support retainAll that exception will be thrown. Which type are you using?

Lars Andren
ArrayList for both lists.
Joren
A: 

It will not let me do new ArrayList() on the query result since it returns an array of objects.

You however need to put them in a new ArrayList(). The returned List implementation apparently doesn't support retainAll(). That's what the exception is telling you.

A "plain" ArrayList supports it. If passing through the ArrayList constructor is not possible due to difference in generic type, then you'll need to manually loop over it and cast each item before adding.

List<Data> listTwo = new ArrayList<Data>();
for (Object object : ds.get(keys).values()) {
    listTwo.add((Data) object);
}
listOne.retainAll(listTwo);

Update: as per your update, the entities are apparently lazily loaded/filled. Most ORM's (DataNucleus is one) may indeed do that. As I don't use DataNucleus, I can't go in detail how to fix that in a "nice" way. But you at least now know the root cause of the problem and it can be solved the same way as above. Fill the list test in a loop as well.

BalusC
Hmm the ds.get does let me create a new ArrayList. I discovered that it won't let me cast from Entity to my object type though. I can't figure out how to turn an entity into anything else.Also, very oddly, if after I cast listOne I do log.info(listOne.toString()); I don't get the UnsupportedOperationException. If I don't call the log.info, I get the error. I have no idea what's up with that.
Joren
I see, I updated the answer.
BalusC
Oy. Ok it's working finally. I'm hoping someone chimes in on a less silly fix than manually building the list, but for now it works. Thanks!
Joren
You're welcome. I would however peek around in DataNucleus' documentation using keywords "lazy loading" to see if that's somehow configureable so that you don't need to hassle with this that way.
BalusC