localObject(), Java null pointers and database NULL

From: Øyvind Harboe (oyvind.harbo..ylin.com)
Date: Sun Oct 22 2006 - 14:26:39 EDT

  • Next message: edward pedersson: "a few qestions if you don't mind"

    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
    



    This archive was generated by hypermail 2.0.0 : Mon Oct 23 2006 - 14:12:17 EDT