Home > front end >  Java: casting primitive wrappers classes
Java: casting primitive wrappers classes

Time:04-29

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.

  • Related