When is an object not an object?...



  • ... When it's a null, of course!

    At work, I have to deal a fair amount with Oracle Content Management SDK (CM SDK). It's not a bad framework as such, but the API (all in Java) sometimes doesn't make much sense. One of my favourite examples is the "AttributeValue" class. This is a class which (surprisingly enough) is used to store and retrieve attributes on items in the repository such as documents, folders, categories etc.

    The constructor is private, you have to use a factory method to create one. Except that, there isn't one factory method, there are about twenty of them. I give you a sample from the API:

    <font size="-1"> static AttributeValue</font> newAttributeValue(int value)
              Constructs a new integer AttributeValue.
    <font size="-1"> static AttributeValue</font> newAttributeValue(int[] values)
              Constructs a new array-type integer AttributeValue.
    <font size="-1"> static AttributeValue</font> newAttributeValue(java.lang.Integer value)
              Constructs a new integer AttributeValue.
    <font size="-1"> static AttributeValue</font> newAttributeValue(java.lang.Integer[] values)
              Constructs a new array-type integer AttributeValue.
    <font size="-1"> static AttributeValue</font> newAttributeValue(long value)
              Constructs a new long AttributeValue.
    <font size="-1"> static AttributeValue</font> newAttributeValue(java.lang.Long value)
              Constructs a new long AttributeValue.
    <font size="-1"> static AttributeValue</font> newAttributeValue(long[] values)
              Constructs a new array-type long AttributeValue.

    So, as well as having constructors for all your primitive types, you also have a constructor for every Object type you want to store. Why they couldn't do a simple: newAttributeValue(Object value) I don't know. Particularly given the fact that there is a corresponding getObject() method!

     My favourite is this, though: If you have a null object, you cannot pass it into newAttributeValue -- you have to call a special method:

    <font size="-1"> static AttributeValue</font> newNullAttributeValue(int attributeDataType)
              Constructs a null AttributeValue of the specified data type.
     

    WTF?!!! 



  • Well, it would be tricky/messy (at least before Java 5) to have a single factory method create AttibuteValue instances for primitives and object types. (Although you could argue that the factory method should take care of that for you, of course)

    As for the null one, I suspect that's an implementation of the null object pattern, although without looking at what you actually get I obviously can't tell for sure.



  • [quote user="Cloaked User"]Well, it would be tricky/messy (at least before Java 5) to have a single factory method create AttibuteValue instances for primitives and object types. (Although you could argue that the factory method should take care of that for you, of course)[/quote]

     Well I wasn't really talking about primitives as such, it was more the fact that they had different methods for different Object types where they could have just had Object instead. In fact, particularly with databases where you can have null values, I wouldn't provide any factory methods for primitive types and make people wrap the values in the corresponding object type (unless they're using Java 5, of course).

    As for the null one, I suspect that's an implementation of the null object pattern, although without looking at what you actually get I obviously can't tell for sure.

    I don't think so - the AttributeValue class seems to be like a wrapper around a database value. There's no reason I know of why they would have to represent the value internally as a 'null object', as opposed to just null.



  • The API seems to care about the data type of a null attribute. How would you specify the null attribute's type if you called newAttributeValue(null)?



  •  [quote user="Anonononymous"]The API seems to care about the data type of a null attribute. How would you specify the null attribute's type if you called newAttributeValue(null)?[/quote]

     The attribute value isn't an attribute value in a vacuum, it has to match up to a pre-existing attribute. I.e., if I had a column "STATUS_CODE" of type VARCHAR, then I would have to set the name of the AttributeValue to be "STATUS_CODE" (something like that). The API should be able to extract the data type from the column (or attribute).
     



  • [quote user="Anonononymous"]The API seems to care about the data type of a null attribute. How would you specify the null attribute's type if you called newAttributeValue(null)?[/quote]

     Simply by writing newAttributeValue((Type) null) where Type is the type of the object you are inserting. That way, the corresponding method is called with a null parameter value.
     



  • Is AttributeValue an abstract class or interface, with a different subclass for every type of value?  Then this allows very small objects:

      class LongAttributeValue extends AttributeValue {

         private Long value;

         public Long getLongValue() { return value; }

         public Object getObject() { return value; } }

      class PrimitiveLongAttributeValue extends Attribute Value {

        private long value;

        public long getLongValue() { return value; }

        public Object getObject() { return new Long(value); } }

      class NullAttributeValue extends Attribute Value {

        public Object getObject() { return null; } }

    In C++ you would do this with templates.  (Perhaps this was designed by a C++ programmer worried about memory constraints.)   

    Java 5 has generics that look something like the C++ templates you would use, but it wasn't available until recently.

    A more "Java 2" way of doing this would be to make it like Java containers:  AttributeValue holds one object of any type, and you do the boxing and casting yourself.

     



  • I suppose they want you to use null with special attention so they make sure that you are aware that the point of execution in which you specify null is reached and so on. That would make sense together with trowing an NPException whenever null argument is passed to one of newAttributeValue.

    [btw.Quick Reply isn't quick]



  • [quote user="qbolec"]

    I suppose they want you to use null with special attention so they make sure that you are aware that the point of execution in which you specify null is reached and so on. That would make sense together with trowing an NPException whenever null argument is passed to one of newAttributeValue.[/quote]

    If you pass in 'null' to newAttributeValue(...) it will actually throw some other cryptic exception. I just find the whole thing a bit odd, given that there isn't any special reason why you wouldn't need to distinguish between null values and non-null values.

    I guess it's not really a WTF, just a rather unusual way of doing things!
     



  • [quote user="PhillS"]There's no reason I know of why they would have to represent the value internally as a 'null object', as opposed to just null.
    [/quote]

    Of course there is: primitive types (int, float, double, etc.) cannot have a null value. Their wrapper classes can, but do you really want to box/unbox all the time when you're iterating through the cursor? No, you don't.

     

    IMO, C# 2.0 solved this problem very elegantly with their nullable types construct.



  • [quote user="Whiskey Tango Foxtrot? Over."]

    [quote user="PhillS"]There's no reason I know of why they would have to represent the value internally as a 'null object', as opposed to just null.
    [/quote]

    Of course there is: primitive types (int, float, double, etc.) cannot have a null value. Their wrapper classes can, but do you really want to box/unbox all the time when you're iterating through the cursor? No, you don't.

     

    IMO, C# 2.0 solved this problem very elegantly with their nullable types construct.

    [/quote]

    How is that any different than using Java's object oriented number classes?  The following works perfectly in Java:

    Integer num = null;

    if (num != null) {
        System.out.println(num);
    }

    Autoboxing makes this work, so it only works in Java 1.5.  In Java 1.4 or earlier, it'd have to be:

    Integer num = null;

    if (num != null) {
        System.out.println(num.intValue());
    }


Log in to reply