Object convertedValue = value;
if (unit != null) {
final Unit<?> def = descriptor.getUnit();
if (def == null) {
final String name = getName(descriptor);
throw new InvalidParameterValueException(Errors.format(Errors.Keys.UnitlessParameter_1, name), name, unit);
}
if (!unit.equals(def)) {
final short expectedID = getUnitMessageID(def);
if (getUnitMessageID(unit) != expectedID) {
throw new IllegalArgumentException(Errors.format(expectedID, unit));
}
/*
* Verify the type of the user's value before to perform the unit conversion,
* because the conversion will create a new object not necessarily of the same type.
*/
if (value != null) {
if (!valueClass.isInstance(value)) {
final String name = getName(descriptor);
throw new InvalidParameterValueException(
Errors.format(Errors.Keys.IllegalParameterValueClass_3,
name, valueClass, value.getClass()), name, value);
}
/*
* From this point we will perform the actual unit conversion. The value may be either
* a Number instance, or an array of numbers (typically an array of type double[]). In
* the array case, we will store the converted values in a new array of the same type.
*/
try {
converter = unit.getConverterToAny(def);
} catch (ConversionException e) {
throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleUnits_2, unit, def), e);
}
Class<?> componentType = valueClass.getComponentType();
if (componentType == null) {
/*
* Usual case where the value is not an array. Convert the value directly.
* Note that the value can only be a number because the unit is associated
* to MeasurementRange, which accepts only numbers.
*/
Number n = converter.convert(((Number) value).doubleValue());
try {
convertedValue = Numbers.cast(n, (Class<? extends Number>) valueClass);
} catch (IllegalArgumentException e) {
throw new InvalidParameterValueException(e.getLocalizedMessage(), getName(descriptor), value);
}
} else {
/*
* The value is an array. Creates a new array and store the converted values
* using Array reflection.
*/
final int length = Array.getLength(value);
convertedValue = Array.newInstance(componentType, length);
componentType = Numbers.primitiveToWrapper(componentType);
for (int i=0; i<length; i++) {
Number n = (Number) Array.get(value, i);
n = converter.convert(n.doubleValue()); // Value in units that we can compare.
try {
n = Numbers.cast(n, (Class<? extends Number>) componentType);
} catch (IllegalArgumentException e) {
throw new InvalidParameterValueException(e.getLocalizedMessage(),
getName(descriptor) + '[' + i + ']', value);
}
Array.set(convertedValue, i, n);
}
}
}
}
}
/*
* At this point the user's value has been fully converted to the unit of measurement specified
* by the ParameterDescriptor. Now compares the converted value to the restricting given by the
* descriptor (set of valid values and range of value domain).
*/
if (convertedValue != null) {
final Verifier error;
final Set<T> validValues = descriptor.getValidValues();
if (descriptor instanceof DefaultParameterDescriptor<?>) {
error = ensureValidValue(valueClass, validValues,
((DefaultParameterDescriptor<?>) descriptor).getValueDomain(), convertedValue);
} else {
error = ensureValidValue(valueClass, validValues,
descriptor.getMinimumValue(), descriptor.getMaximumValue(), convertedValue);
}
if (error != null) {
error.convertRange(converter);
final String name = getName(descriptor);
throw new InvalidParameterValueException(error.message(null, name, value), name, value);
}
}
return (T) convertedValue;
}