I have following method that I use when traversing values in JSON document:
protected static <T> T getValueAs(Object untypedValue, Class<T> expectedType) {
if (expectedType.isAssignableFrom(untypedValue.getClass())) {
return (T) untypedValue;
}
throw new RuntimeException("Failed");
}
In most of the cases it works just fine, but it fails (throws exception) when called like:
getValueAs((Long) 1L, Double.class);
I know that this is due to incompatibility of Long
and Double
:
Double d = (Long) 1L;
results in error: incompatible types: Long cannot be converted to Double
.
I wonder if somehow I can make my method work even in such case - Long
value gets converted into Double
?
I have seen isAssignable() from Apache Commons but I think it will only make condition work pass and things will fail on casting - I have expected type Double
and value is of type Long
(not primitives).
CodePudding user response:
Would this overloaded method be acceptable?
Double n = getValueAs(1L, Number.class, Number::doubleValue);
protected static <P,T> T getValueAs(Object untypedValue, Class<P> expectedType, Function<P, T> f) {
if (expectedType.isAssignableFrom(untypedValue.getClass())) {
return f.apply((P)untypedValue);
}
throw new RuntimeException("Failed");
}
CodePudding user response:
You probably have no choice but to perform a conversion. But since your method won't know how to convert values of unknown classes, you can leave that as the responsibility of the caller:
protected static <T> T getValueAs(Object untypedValue, Class<T> expectedType) {
return getValueAs(untypedValue, expectedType);
}
protected static <T> T getValueAs(Object untypedValue, Class<T> expectedType,
Function<Object, T> converter) {
if (expectedType.isAssignableFrom(untypedValue.getClass())) {
//use Class.cast to skip unchecked cast warning
return expectedType.cast(untypedValue);
} else if (null != converter) {
return converter.apply(untypedValue);
}
throw new RuntimeException("Failed");
}
And the invocation may be something like this:
getValueAs(1L, Double.class, v -> ((Number) v).doubleValue());
Of course, you can add to getValueAs()
a few conversions that your method supports, particularly for the most common scenarios; so your callers don't have to write converters for those.