1

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).

2 Answers 2

1

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");
}
Sign up to request clarification or add additional context in comments.

1 Comment

Actually this is almost exactly what I have arrived at independently - I'm just calling getValueAs(1L, Number.class).doubleValue().
1

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, null);
}

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.

2 Comments

I think in the first method you forgot to add a null as 3rd parameter.
Thx @ernest_k for good hint with Number and doubleValue!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.