I got a user question on the behavior of contains, but not sure whether
the current JPOX behavior is correct.
####################
I recently ran into a problem where calling org.jpox.sco.List.contains()
gave me different results under (what I thought were) the same runtime
conditions. After stepping through the code, I now understand why I am
getting different results. I illustrate the issue below.
Basically, I have a collection (List) of persistent objects. At some
point in my code, I want to determine if that collection already
contains a particular object based on equality (Object.equals()), so I
invoke contains():
if (myList.contains(anObject)) {
The interesting bit here is that anObject is not persistent. In fact,
it's not even enhanced. It is a POJO that happens to implement the same
interface used by the persistent objects stored in the collection.
Assume that there is indeed an object in the collection for which
objectInCollection.equals(anObject) is true. Thus, I would expect
List.contains() to return true, as well.
I would expect so as well.
In the case where the above code does return true, I see that useCache
and isCacheLoaded are both true, so the delegate is used to implement
the method. Since this delegate is simply an ArrayList, I get the
behavior I expect.
When isCacheLoaded is not true, the method delegates to backingStore. As
part of the backingStore.contains() call, the method
org.jpox.store.rdbms.scostore.AbstractCollectionStore.validateElementFor
Reading() method is called (moved to ElementContainerStore in HEAD).
This method returns false if the element is not persistent AND not
detached. Since the parameter I originally passed is neither persistent
nor detached, contains() always returns false in this state.
Am I just asking for trouble by passing an object not of the PC type to
the contains() method of a persistent collection?
The way the JDO 1 Reference Implementation handled this is that for deferred collections (collections in which the elements were not yet instantiated) before any "user" methods were executed, the entire collection was instantiated.
It's not clear to me how the JPOX collections work in the case of the backingStore.
It seems that if you're using a JPOX collection, it's a member of a persistent instance, and it is a persistent collection. And should therefore only contain instances that might become persistent. Otherwise, I think you are indeed asking for trouble.
To rephrase, if you get a JPOX collection by fetching a persistent instance, and then add non-persistent instances to it in order to do a contains, and then remove the non-persistent instances in order to avoid a failure at flush time, you're certainly doing something a bit odd. If the non-persistent instance does belong in the collection and will be persistent later then it sounds like a bug. How the backingStore interacts with this scenario is still unclear to me.
I worked around the issue by explicitly iterating over the elements of
the collection and invoking equals() on each one until I find a match.
This feels like a hack to me because I know in three months someone else
will come along and make the same mistake because they are thinking in
terms of java.util.List.contains(), not JDO.
Seems like a hack to me also, FWIW. SCO List should provide more behavior compared to java.util.List, not less.