We're trying to finish up an application and we're taking a hammering from Java null pointers and database NULL.
The trick with our application is that we need to be bug-by-bug database compatible with an old .asp + vbscript application until such time that we can delete the old application, so are hands are pretty tied w.r.t. solving problems at a database/application design level. Handling null pointers in a more robust and universal fashion, is one of my hobby horses. http://www.objectstyle.org/cayenne/lists/cayenne-user/2006/08/0010.html. While I'm on the soapbox: a Java null pointer is a VERY different beast from a database NULL and trying to simulate one with the other, while at first it sounds like a good idea, turns out to be hairy to say the least. I wish Cayenne would stop using Java null pointers pretty much across the board to represent anything but unitialized member variables. Uninitialized member variables should never be read by correctly written code per my personal definition. I'll step down from my soapboax now. One of the exceptions we're looking into are below. I'm trying to see where things go haywire, but here are some of the clues that I've managed to find: - readProperty() for a property that returns a CayenneDataObject will either return a Java null pointer or a CayenneDataObject. "instanceof" will always return false for a Java null pointer. - I don't believe there is such a thing as an ObjectId for a Java null pointer returned by readProperty()(which in this case represents a database NULL). - writeProperty(null) is legal and is Cayenne speak for asking the underlying engine to write a database NULL. - DataContext.localObject() does not allow null pointer's for an ObjectId. There is no way to distinguish between two Java null pointers that "belong" to two different CayenneDataContext's, so some conditional code on the outside of localObject() can be used/is required in *all places* where a database null might appear. The net result is the need for a raft of if() statements to somehow handle the null pointer case in each instance localObject() is invoked. - Here is an ArcOperation. I'm not sure what this *should* have looked like in the writeProproty(null) case, given that there is no such thing as an ObjectId representing database null. [1]= ObjectDiff$ArcOperation (id=7192) arcId= "toTreatCustomspec" delete= false diffId= 2 nodeId= ObjectId (id=7221) targetNodeId= null Caused by: java.lang.IllegalArgumentException: Null ObjectId at org.objectstyle.cayenne.access.DataContext.localObject(DataContext.java:1903) at org.objectstyle.cayenne.access.DataContextMergeHandler.arcCreated(DataContextMergeHandler.java:203) at org.objectstyle.cayenne.access.ObjectDiff$ArcOperation.apply(ObjectDiff.java:408) at org.objectstyle.cayenne.graph.CompoundDiff.apply(CompoundDiff.java:133) at org.objectstyle.cayenne.access.ObjectStoreGraphDiff.apply(ObjectStoreGraphDiff.java:155) at org.objectstyle.cayenne.access.DataContextMergeHandler.graphChanged(DataContextMergeHandler.java:135) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.objectstyle.cayenne.util.Invocation.fire(Invocation.java:240) at org.objectstyle.cayenne.event.EventManager$Dispatch.fire(EventManager.java:433) at org.objectstyle.cayenne.event.DispatchQueue.dispatchEvent(DispatchQueue.java:182) at org.objectstyle.cayenne.event.DispatchQueue.dispatchEvent(DispatchQueue.java:94) at org.objectstyle.cayenne.event.EventManager.dispatchEvent(EventManager.java:372) at org.objectstyle.cayenne.event.EventManager.postEvent(EventManager.java:343) at org.objectstyle.cayenne.access.DataContext.fireDataChannelChanged(DataContext.java:1731) at org.objectstyle.cayenne.access.DataContext.onContextFlush(DataContext.java:1216) at org.objectstyle.cayenne.access.DataContext.onSync(DataContext.java:1194) at org.objectstyle.cayenne.access.DataContext.flushToParent(DataContext.java:1261) at org.objectstyle.cayenne.access.DataContext.commitChanges(DataContext.java:1165) -- Øyvind Harboe http://www.zylin.com
