All,

the discussion of automatically setting fields in the component
based on a component to configuration mapping caused me to think
about the alternatives to reaching into a class and setting
private fields.

For example, we will use a class that has two fields - a minimum
and a maximum range.

    public class Radar {

        private int minRange;

        private int maxRange;

        // ...

    }

There's one invariant though - the minimum range is always less than
or equal to the maximum range: minRange <= maxRange

Additionally, I'll completely ignore the case of a negative range 
value. Focus on the invariant above.

OK, so how are we going to configure this thing?

Attempt 1: Standard Avalon Configuration

    public class Radar {

        private int minRange;

        private int maxRange;

        public void configure (Configuration config) 
            throws ConfigurationException {

            minRange = config.getAttributeAsInteger ("min-range");
            maxRange = config.getAttributeAsInteger ("max-range");

            if (minRange > maxRange) {
                throw new ConfigurationException ("min-range >
max-range");
            }
        }

        // ...

    }

OK, fine, but not very magic. Not magic enough, in fact, due to the
amount of 
boilerplate code.


Attempt 2: Deserialization from XML or similar

    public class Radar {

        private int minRange;

        private int maxRange;

        // ...

    }

Here we use XStream or similar. So we create an XML file:

    <radar>
        <minRange>1000</minRange>
        <maxRange>2000</maxRange>
    </radar>

And we're done. Or? Well, how about:

    <radar>
        <minRange>2000</minRange>
        <maxRange>1000</maxRange>
    </radar>

Oops. Broken invariant. No way to detect that unless we do some serious 
hackery. 


Attempt 3: Use Setters to Validate Values

    public class Radar {

        private int minRange;

        private int maxRange;

        public void setMaxRange (int _maxRange) {
            if (_maxRange < minRange) {
                throw new IllegalArgumentException ("maxRange <
minRange");
            }
            
            maxRange = _maxRange;
        }

        public void setMinRange (int _minRange) {
            if (_minRange > maxRange) {
                throw new IllegalArgumentException ("minRange >
maxRange");
            }
            
            minRange = _minRange;
        }

        // ...

    }

Here the problem is that we can't guarantee in what order the setters
will be
called. Unless they are called in the order setMaxRange, setMinRange,
we're
guaranteed to get an IllegalArgumentException. This is the problem of
constructing 
and object with setters - even though they are supposed to provide
validation 
of the parameters, due to them being called in sequence, none can
validate the
complete state of the instance before the object is fully constructed.

Anyway, that's why JavaBeans are Evil. Mmmkay?


Attempt 4: Auto-Configuration

    public class Radar {

        /**
         * @@ConfigurableField ("@min-range")
         */
        private int minRange;

        /**
         * @@ConfigurableField ("@max-range")
         */
        private int maxRange;

        // ...

    }

Fails for the same reasons as attempt 2: no validation.



Attempt 5: Auto-Configuration or Deserialization With
           Separate configure() Step

    public class Radar {

        /**
         * @@ConfigurableField ("@min-range")
         */
        private int minRange;

        /**
         * @@ConfigurableField ("@max-range")
         */
        private int maxRange;

        public void configure (Configuration config) 
            throws ConfigurationException {

            if (minRange > maxRange) {
                throw new ConfigurationException ("min-range >
max-range");
            }
        }

        // ...

    }

Well, *I* think this one is a winner. (Whether it is realized via
XStream
or attributes is not that relevant.)

/LS


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to