You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by Øyvind Harboe <oy...@zylin.com> on 2006/08/03 22:02:36 UTC

Null pointer exceptions and database null

Is there a way to tell Cayenne to return some other value than null
when the database contains null?

E.g. for String I want an empty string instead of null, for Integer I
want 0 instead of null, etc.

Also, I want Cayenne not to modify the database unecessarily, e.g. if
Cayenne returns "" when the database contains NULL  and I write back
"" to the database, I don't want Cayenne to write an empty string to
the database, but leave the database unchanged, yet there needs to be
a way to set such database null strings to "".

My personal favourite solution to null pointer problem is
polymorphism. Create a subclass which handles the "null", "empty",
case, etc. One annoying thing about null pointers is that they are
typeless. I would have created a NullString subclass to String in some
cases, except String is final. BigDecimal is not final, so the trick
could work there. Since I'm already on my hobbyhorse: null pointers
are a plague. Much too easy to misuse. Look at the number of bug
reports in e.g. Eclipse that are NPE's(ca. 15000 out of 150000) and
the number of != null or == null checks in Eclipse is just staggering.
It vastly complicates the code. Oh well. :-)

-- 
Øyvind Harboe
http://www.zylin.com

Re: Null pointer exceptions and database null

Posted by Mike Kienenberger <mk...@gmail.com>.
This is also the piece of code you can modify to fit your definition
of "want Cayenne not to modify the database unecessarily" by skipping
setting any equivalent values.

On 8/3/06, Mike Kienenberger <mk...@gmail.com> wrote:
> For JSF, it updates values even if the values haven't changed.   So I
> check for that condition and if so, I don't actually update anything.
>
> The safety issue is that DataObjects are only equal if it's the same
> object in memory.  So assigning another seemingly identical object
> would sneak through.
>
> I eventually (last week) wrote a new equals() method for my
> BaseDataObject class that makes DataObjects equal if their ObjectId
> value is equal.   I'm hoping that will do what I want, but I'm a bit
> nervous about changing DataObject equality.
>
>
> On 8/3/06, Øyvind Harboe <oy...@zylin.com> wrote:
> > Super!
> >
> > >         // TODO: needed for JSF
> > >         Object oldValue = readProperty(propName);
> > >         if (oldValue == value)
> > >         {
> > >             // NOOP
> > >             return;
> > >         }
> > >         if (null != oldValue)
> > >         {
> > >             if (oldValue.equals(value))
> > >             {
> > >                 // NOOP
> > >                 // IMPLEMENT: not sure if this is safe!
> >
> > What does this comment mean?
> >
> >
> >
> > --
> > Øyvind Harboe
> > http://www.zylin.com
> >
>

Re: Null pointer exceptions and database null

Posted by Mike Kienenberger <mk...@gmail.com>.
For JSF, it updates values even if the values haven't changed.   So I
check for that condition and if so, I don't actually update anything.

The safety issue is that DataObjects are only equal if it's the same
object in memory.  So assigning another seemingly identical object
would sneak through.

I eventually (last week) wrote a new equals() method for my
BaseDataObject class that makes DataObjects equal if their ObjectId
value is equal.   I'm hoping that will do what I want, but I'm a bit
nervous about changing DataObject equality.


On 8/3/06, Øyvind Harboe <oy...@zylin.com> wrote:
> Super!
>
> >         // TODO: needed for JSF
> >         Object oldValue = readProperty(propName);
> >         if (oldValue == value)
> >         {
> >             // NOOP
> >             return;
> >         }
> >         if (null != oldValue)
> >         {
> >             if (oldValue.equals(value))
> >             {
> >                 // NOOP
> >                 // IMPLEMENT: not sure if this is safe!
>
> What does this comment mean?
>
>
>
> --
> Øyvind Harboe
> http://www.zylin.com
>

Re: Null pointer exceptions and database null

Posted by Øyvind Harboe <oy...@zylin.com>.
Super!

>         // TODO: needed for JSF
>         Object oldValue = readProperty(propName);
>         if (oldValue == value)
>         {
>             // NOOP
>             return;
>         }
>         if (null != oldValue)
>         {
>             if (oldValue.equals(value))
>             {
>                 // NOOP
>                 // IMPLEMENT: not sure if this is safe!

What does this comment mean?



-- 
Øyvind Harboe
http://www.zylin.com

Re: Null pointer exceptions and database null

Posted by Mike Kienenberger <mk...@gmail.com>.
On 8/4/06, Øyvind Harboe <oy...@zylin.com> wrote:
> I spoke too soon. How do I in readProperty() know the type of the null
> I'll be translating to an empty string or Integer 0? (I expect that
> not to be super hard as Cayenne has this knowledge somewhere in its
> structures)

In general, you would....

Look up the ObjEntity for the the current DataObject, find the
ObjAttribute (or ObjRelationship) for the property name, and then look
at the java type for that OA or OR.

Note that you can speed this up by changing the generated class
templates to automatically hardcode this information into each getter.

RE: Null pointer exceptions and database null

Posted by "Gentry, Michael (Contractor)" <mi...@fanniemae.com>.
I should also mention that when writing, if you encounter a NULL it should either throw an exception or ignore the write.  The null handling is most useful when reading to present data to the user (perhaps in a report from a query that isn't editable).


-----Original Message-----
From: Gentry, Michael (Contractor) [mailto:michael_gentry@fanniemae.com] 
Sent: Friday, August 04, 2006 9:34 AM
To: cayenne-user@incubator.apache.org
Subject: RE: Null pointer exceptions and database null


Fundamentally, no.  We'd have to "fix" to-many handling though, and make the rules understood.  In your previous example:

foo.bar.name

Will fail in readNestedProperty() if foo->>bar is a to-many relationship.  Cayenne only likes to-one relationships in the keypath currently.  In EOF, it will return an array of name objects for you (which can be very useful at times).  Likewise, when writing, it would assign the same value to all of the names.  More powerful, but the rules should be well understood (aka, documented).

/dev/mrg


-----Original Message-----
From: oyvindharboe@gmail.com [mailto:oyvindharboe@gmail.com] On Behalf Of Øyvind Harboe
Sent: Friday, August 04, 2006 9:23 AM
To: cayenne-user@incubator.apache.org
Subject: Re: Null pointer exceptions and database null


> PS. There isn't a writeNestedProperty() though ...

Is there a fundamental reason why Cayenne couldn't handle this?

CayenneDataObject could implement some suitable semantics when it
represented a database null object.


-- 
Øyvind Harboe
http://www.zylin.com

RE: Null pointer exceptions and database null

Posted by "Gentry, Michael (Contractor)" <mi...@fanniemae.com>.
Fundamentally, no.  We'd have to "fix" to-many handling though, and make the rules understood.  In your previous example:

foo.bar.name

Will fail in readNestedProperty() if foo->>bar is a to-many relationship.  Cayenne only likes to-one relationships in the keypath currently.  In EOF, it will return an array of name objects for you (which can be very useful at times).  Likewise, when writing, it would assign the same value to all of the names.  More powerful, but the rules should be well understood (aka, documented).

/dev/mrg


-----Original Message-----
From: oyvindharboe@gmail.com [mailto:oyvindharboe@gmail.com] On Behalf Of Øyvind Harboe
Sent: Friday, August 04, 2006 9:23 AM
To: cayenne-user@incubator.apache.org
Subject: Re: Null pointer exceptions and database null


> PS. There isn't a writeNestedProperty() though ...

Is there a fundamental reason why Cayenne couldn't handle this?

CayenneDataObject could implement some suitable semantics when it
represented a database null object.


-- 
Øyvind Harboe
http://www.zylin.com

Re: Null pointer exceptions and database null

Posted by Øyvind Harboe <oy...@zylin.com>.
> PS. There isn't a writeNestedProperty() though ...

Is there a fundamental reason why Cayenne couldn't handle this?

CayenneDataObject could implement some suitable semantics when it
represented a database null object.


-- 
Øyvind Harboe
http://www.zylin.com

RE: Null pointer exceptions and database null

Posted by "Gentry, Michael (Contractor)" <mi...@fanniemae.com>.
Ah, now I feel your pain.  :-)

I have lots of cover code in my T4 application because of this OGNL "problem".  There is no simple way, that I could find, to have OGNL handle it, either.  They do have a NULL handler you can set, but it is per-class.  Not too generic.  I might have to think about EONull again, but it would probably be harder to implement in Java.  Objective-C allows you to message any object with any message, including ones it doesn't understand, and handle it.  This allowed EONull to always return an EONull when you requested an unknown property.  In your example below, if "bar" was null, just returning a String wouldn't be enough because in Java, a String doesn't have a getName() method.

What would probably be best, and I started to look into it but didn't get far, is to create a cayenne: prefix (instead of ognl:) for T4 which uses Cayenne's readNestedProperty() method, which can handle the NULL values.

/dev/mrg

PS. There isn't a writeNestedProperty() though ...



-----Original Message-----
From: oyvindharboe@gmail.com [mailto:oyvindharboe@gmail.com] On Behalf Of Øyvind Harboe
Sent: Friday, August 04, 2006 2:21 AM
To: cayenne-user@incubator.apache.org
Subject: Re: Null pointer exceptions and database null


There is no particular reason I don't want null handling work for
relationships. Though possible, how to do this is clearly non-obvious.

Consider an OGNL statement:

foo.bar.name

Here I want this entire expression to evaluate to an empty string.


-- 
Øyvind Harboe
http://www.zylin.com

Re: Null pointer exceptions and database null

Posted by Øyvind Harboe <oy...@zylin.com>.
There is no particular reason I don't want null handling work for
relationships. Though possible, how to do this is clearly non-obvious.

Consider an OGNL statement:

foo.bar.name

Here I want this entire expression to evaluate to an empty string.


-- 
Øyvind Harboe
http://www.zylin.com

Re: Null pointer exceptions and database null

Posted by Øyvind Harboe <oy...@zylin.com>.
> You'd just want to write a matching readProperty function to reverse
> the translation to address your first concern.

I spoke too soon. How do I in readProperty() know the type of the null
I'll be translating to an empty string or Integer 0? (I expect that
not to be super hard as Cayenne has this knowledge somewhere in its
structures)


Tapestry & JSF have the same issue that you pointed out that writing
the same value should not cause an update to the database.

-- 
Øyvind Harboe
http://www.zylin.com

Re: Null pointer exceptions and database null

Posted by Mike Kienenberger <mk...@gmail.com>.
On 8/3/06, Øyvind Harboe <oy...@zylin.com> wrote:
> Is there a way to tell Cayenne to return some other value than null
> when the database contains null?
>
> E.g. for String I want an empty string instead of null, for Integer I
> want 0 instead of null, etc.
>
> Also, I want Cayenne not to modify the database unecessarily, e.g. if
> Cayenne returns "" when the database contains NULL  and I write back
> "" to the database, I don't want Cayenne to write an empty string to
> the database, but leave the database unchanged, yet there needs to be
> a way to set such database null strings to "".

This is an example of automatically translating empty strings to null
when setting Cayenne DataObject values.  It also makes sure not to
reset the value if it was already null.   It sounds like you'd want to
switch empty-string and null.  (This is your second concern).

You'd just want to write a matching readProperty function to reverse
the translation to address your first concern.    Then you just put
these methods in a base DataObject class and have all of your
DataObjects inherit from this instead of CayenneDataObject (which is
what BaseDataObject would inherit from).

    public void writeProperty(String propName, Object value)
    {
        // Oracle can't handle empty strings, and JSF generates them
instead of nulls.
        if ( (value instanceof String) && (0 == ((String)value).length()) )
        {
            value = null;
        }

        // TODO: needed for JSF
        Object oldValue = readProperty(propName);
        if (oldValue == value)
        {
            // NOOP
            return;
        }
        if (null != oldValue)
        {
            if (oldValue.equals(value))
            {
                // NOOP
                // IMPLEMENT: not sure if this is safe!
                return;
            }
        }

        super.writeProperty(propName, value);
    }

Re: Null pointer exceptions and database null

Posted by Øyvind Harboe <oy...@zylin.com>.
On 8/3/06, Gentry, Michael (Contractor) <mi...@fanniemae.com> wrote:
> I'm not 100% certain why you would want to do that

To get rid of NPE's.

>(sometimes you need to know when
>things are null).  I do agree it can complicate code (I really miss
Objective-C's handling).  One
> thing EOF did was have an EONull class to represent null objects.  You could fudge this sort
> of behavior with a custom common superclass (that all the _Classes inherit from), but it
>wouldn't be quite the same as if Cayenne had support for it.  This
might actually be
>enhancement worthy, but would probably break lots of things.

I don't want to loose the capability to detect that there is an
underlying database null, nor is this required to be able to implement
returning empty string for the null case. In fact Cayenne would have
to have some way of knowing that there was an underlying database null
to correctly handle updates.

-- 
Øyvind Harboe
http://www.zylin.com

RE: Null pointer exceptions and database null

Posted by "Gentry, Michael (Contractor)" <mi...@fanniemae.com>.
I'm not 100% certain why you would want to do that (sometimes you need to know when things are null).  I do agree it can complicate code (I really miss Objective-C's handling).  One thing EOF did was have an EONull class to represent null objects.  You could fudge this sort of behavior with a custom common superclass (that all the _Classes inherit from), but it wouldn't be quite the same as if Cayenne had support for it.  This might actually be enhancement worthy, but would probably break lots of things.

/dev/mrg



-----Original Message-----
From: oyvindharboe@gmail.com [mailto:oyvindharboe@gmail.com] On Behalf Of Øyvind Harboe
Sent: Thursday, August 03, 2006 4:03 PM
To: cayenne-user@incubator.apache.org
Subject: Null pointer exceptions and database null


Is there a way to tell Cayenne to return some other value than null
when the database contains null?

E.g. for String I want an empty string instead of null, for Integer I
want 0 instead of null, etc.

Also, I want Cayenne not to modify the database unecessarily, e.g. if
Cayenne returns "" when the database contains NULL  and I write back
"" to the database, I don't want Cayenne to write an empty string to
the database, but leave the database unchanged, yet there needs to be
a way to set such database null strings to "".

My personal favourite solution to null pointer problem is
polymorphism. Create a subclass which handles the "null", "empty",
case, etc. One annoying thing about null pointers is that they are
typeless. I would have created a NullString subclass to String in some
cases, except String is final. BigDecimal is not final, so the trick
could work there. Since I'm already on my hobbyhorse: null pointers
are a plague. Much too easy to misuse. Look at the number of bug
reports in e.g. Eclipse that are NPE's(ca. 15000 out of 150000) and
the number of != null or == null checks in Eclipse is just staggering.
It vastly complicates the code. Oh well. :-)

-- 
Øyvind Harboe
http://www.zylin.com