Generic PropertyDescriptor puzzler
Consider the implementation of a validator, to do a range check.
Since I have a sneaky suspicion we gonna need to communicate with the user
when the validation fails, lets prepare those messages in a resource-injectible bundle
of bytes as follows. The problem with IT is all these darn users! They keep getting
in the way of real progress, wanting silly features, finding silly bugs...
<font color=#000099><b>class</b></font> ValidatorResource {
@ResourceAnnotation()<font color=#666666></font>
String property = <font color=#99006b>"The property '%s'"</font>;
@ResourceAnnotation()<font color=#666666></font>
String isNull = <font color=#99006b>"is null"</font>;
@ResourceAnnotation()<font color=#666666></font>
String lessThanMinimum = <font color=#99006b>"is less than %s"</font> ;
@ResourceAnnotation()<font color=#666666></font>
String equalsMinimum = <font color=#99006b>"is equal to, not greater than %s"</font>;
@ResourceAnnotation()<font color=#666666></font>
String greaterThanMaximum = <font color=#99006b>"is greater than %s"</font>;
@ResourceAnnotation()<font color=#666666></font>
String equalsMaximum = <font color=#99006b>"is equal to, not less than %s"</font>;
<font color=#000099><b>public</b></font> ValidatorResource() {
configurator.<b>configure</b>(<font color=#000099><b>this</b></font>);
}
}
Now because we got so many types of numbers and dates and what-not, let's implement
a generic range validator as follows, where our value type is Comparable.
<font color=#000099><b>abstract</b></font> <font color=#000099><b>class</b></font> ComparableRangeValidator<Value <font color=#000099><b>extends</b></font> Comparable> {
<font color=#000099><b>public</b></font> <font color=#000099><b>static</b></font> <font color=#000099><b>final</b></font> ValidatorResource resource = <font color=#000099><b>new</b></font> ValidatorResource();
Value minimum;
Value maximum;
<font color=#000099><b>boolean</b></font> nullable;
<font color=#000099><b>boolean</b></font> exclusive;
<font color=#000099><b>public</b></font> ComparableRangeValidator() {
}
<font color=#000099><b>private</b></font> String <b>format</b>(NBeanProperty property, String format, Object ... args) {
<font color=#000099><b>return</b></font> formatter.<b>format</b>(resource.property, property.<b>getPropertyLabel</b>()) +
formatter.<b>format</b>(format, args);
}
<font color=#000099><b>public</b></font> String <b>validate</b>(NBeanProperty property, Value value) {
<font color=#000099><b>if</b></font> (value == <font color=#000099><b>null</b></font>) {
<font color=#000099><b>if</b></font> (!nullable) {
<font color=#000099><b>return</b></font> <b>format</b>(property, resource.isNull);
}
<font color=#000099><b>return</b></font> <font color=#000099><b>null</b></font>;
}
<font color=#000099><b>if</b></font> (value.<b>compareTo</b>(minimum) < 0) {
<font color=#000099><b>return</b></font> <b>format</b>(property, resource.lessThanMinimum, minimum);
}
<font color=#000099><b>if</b></font> (value.<b>compareTo</b>(minimum) == 0 && exclusive) {
<font color=#000099><b>return</b></font> <b>format</b>(property, resource.equalsMinimum, minimum);
}
<font color=#000099><b>if</b></font> (value.<b>compareTo</b>(maximum) > 0) {
<font color=#000099><b>return</b></font> <b>format</b>(property, resource.greaterThanMaximum, maximum);
}
<font color=#000099><b>if</b></font> (value.<b>compareTo</b>(maximum) == 0 && exclusive) {
<font color=#000099><b>return</b></font> <b>format</b>(property, resource.equalsMaximum, maximum);
}
<font color=#000099><b>return</b></font> <font color=#000099><b>null</b></font>;
}
<font color=#000099><b>public</b></font> <font color=#000099><b>void</b></font> <b>setExclusive</b>(<font color=#000099><b>boolean</b></font> exclusive) {
<font color=#000099><b>this</b></font>.exclusive = exclusive;
}
<font color=#000099><b>public</b></font> <font color=#000099><b>boolean</b></font> <b>isExclusive</b>() {
<font color=#000099><b>return</b></font> exclusive;
}
<font color=#000099><b>public</b></font> <font color=#000099><b>void</b></font> <b>setNullable</b>(<font color=#000099><b>boolean</b></font> nullable) {
<font color=#000099><b>this</b></font>.nullable = nullable;
}
<font color=#000099><b>public</b></font> <font color=#000099><b>boolean</b></font> <b>isNullable</b>() {
<font color=#000099><b>return</b></font> nullable;
}
<font color=#000099><b>public</b></font> <font color=#000099><b>void</b></font> <b>setMinimum</b>(Value minimum) {
<font color=#000099><b>this</b></font>.minimum = minimum;
}
<font color=#000099><b>public</b></font> Value <b>getMinimum</b>() {
<font color=#000099><b>return</b></font> minimum;
}
<font color=#000099><b>public</b></font> <font color=#000099><b>void</b></font> <b>setMaximum</b>(Value maximum) {
<font color=#000099><b>this</b></font>.maximum = maximum;
}
<font color=#000099><b>public</b></font> Value <b>getMaximum</b>() {
<font color=#000099><b>return</b></font> maximum;
}
}
Now we can very easily create validators for specific types, which are effectively
type aliases, as follows.
<font color=#000099><b>class</b></font> IntegerRangeValidator <font color=#000099><b>extends</b></font> ComparableRangeValidator<Integer> {
}
Supoib!
Now let's check the PropertyDescriptor's of our minty IntegerRangeValidator.
<font color=#000099><b>public</b></font> <font color=#000099><b>class</b></font> IntegerRangeValidatorInsanityCheck {
<font color=#000099><b>public</b></font> <font color=#000099><b>static</b></font> <font color=#000099><b>void</b></font> <b>main</b>(String[] args) <font color=#000099><b>throws</b></font> Exception {
BeanInfo beanInfo = Introspector.<b>getBeanInfo</b>(IntegerRangeValidator.<font color=#000099><b>class</b></font>);
<font color=#000099><b>for</b></font> (PropertyDescriptor property : beanInfo.<b>getPropertyDescriptors</b>()) {
logger.<b>info</b>(property.<b>getName</b>(), property.<b>getPropertyType</b>());
}
}
}INFO:logger:IntegerRangeValidator:main:123: (String) class :: (Class) Class
INFO:logger:IntegerRangeValidator:main:123: (String) exclusive :: (Class) boolean
INFO:logger:IntegerRangeValidator:main:123: (String) maximum :: (Class) Comparable
INFO:logger:IntegerRangeValidator:main:123: (String) minimum :: (Class) Comparable
INFO:logger:IntegerRangeValidator:main:123: (String) nullable :: (Class) boolean
Darn, the type of minimum and maximum is Comparable, as
in the generic ComparableRangeValidator superclass. Houston, why can't it just be Integer like i want?! Cos i wanna coerce (integer) values in there from string resources, so i'm stumped!
- Login or register to post comments
- Printer-friendly version
- evanx's blog
- 574 reads





