TypeConversionException.java
package org.klojang.convert;
import org.klojang.check.Check;
import java.io.File;
import java.time.temporal.Temporal;
import static java.lang.String.format;
import static org.klojang.util.ClassMethods.className;
import static org.klojang.util.ClassMethods.simpleClassName;
import static org.klojang.util.StringMethods.ellipsis;
/**
* Indicates that a value could not be converted to the desired type.
*
* @author Ayco Holleman
*/
public final class TypeConversionException extends RuntimeException {
/**
* Returns a {@code TypeConversionException} informing the user that a type
* conversion failed because the conversion function does not support the type of
* the input value.
*
* @param inputValue the input value (may be {@code null}, indicating that
* {@code null} could not be converted to the target type)
* @param targetType the target type
* @return a {@code TypeConversionException} informing the user that a type
* conversion failed because the conversion function does not support the type
* of the input value
*/
static TypeConversionException inputTypeNotSupported(Object inputValue,
Class<?> targetType) {
return new TypeConversionException(inputValue,
targetType, "input type not supported");
}
/**
* Returns a {@code TypeConversionException} informing the user that a type
* conversion failed because the input value did not "fit into" the target type
*
* @param inputValue the input value (may be {@code null}, indicating that
* {@code null} could not be converted to the target type)
* @param targetType the target type
* @return a {@code TypeConversionException} informing the user that a type
* conversion failed because the input value did not "fit into" the target
* type
*/
static final TypeConversionException targetTypeTooNarrow(Object inputValue,
Class<?> targetType) {
return new TypeConversionException(inputValue,
targetType,
"target type too narrow");
}
private final Object inputValue;
private final Class<?> targetType;
/**
* Creates a new {@code TypeConversionException} for the specified input value and
* target type. A standard message is generated from the two arguments
*
* @param inputValue the input value (may be {@code null}, indicating that
* {@code null} could not be converted to the target type)
* @param targetType the target type
*/
TypeConversionException(Object inputValue, Class<?> targetType) {
super(defaultMessage(inputValue, targetType));
this.inputValue = inputValue;
this.targetType = targetType;
}
/**
* Creates a new {@code TypeConversionException} for the specified input value and
* target type.
*
* @param inputValue the input value (may be {@code null}, indicating that
* {@code null} could not be converted to the target type)
* @param targetType the target type
* @param msg a custom message or {@code String.format} message pattern
* @param msgArgs zero or more message arguments
*/
public TypeConversionException(Object inputValue,
Class<?> targetType,
String msg,
Object... msgArgs) {
super(defaultMessage(inputValue, targetType) + " *** " + format(msg, msgArgs));
this.inputValue = inputValue;
this.targetType = targetType;
}
/**
* Returns the value for which the type conversion failed.
*
* @return the value for which the type conversion failed
*/
public Object getInputValue() {
return inputValue;
}
/**
* Returns the target type of the type conversion.
*
* @return the target type of the type conversion
*/
public Class<?> getTargetType() {
return targetType;
}
private static String defaultMessage(Object obj, Class<?> type) {
Check.notNull(type, "target type");
if (obj == null) {
return format("cannot convert null to %s", className(type));
} else if (obj instanceof String s) {
return format("cannot convert \"%s\" to %s",
ellipsis(obj, 30),
className(type));
} else if (hasDecentToString(obj)) {
return format("cannot convert (%s) %s to %s",
simpleClassName(obj),
ellipsis(obj, 30), className(type));
}
return format("cannot convert (%s) to %s", className(obj), className(type));
}
private static boolean hasDecentToString(Object obj) {
return obj instanceof CharSequence
|| obj instanceof Number
|| obj instanceof Enum<?>
|| obj instanceof Temporal
|| obj instanceof File
// add to taste ...
;
}
}