Magic Cast Method in Java

Since Java introduced generics the type declarations got at lot longer. This is especially annoying when an API forces you to cast objects, like the reflection-API, the JDO-API , etc. There are plenty of APIs which requires such casts. Those casts force you to write the (obvious) type twice, for the type-declaration and the cast.

PersistenceManager persistenceManager = // get persistence 
Collection<Book> allBooks = (Collection<Book>) persistenceManager.newQuery(Book.class).execute();

Magic Java Casts

Magic Java Casts

Generic Trickery

We know that for methods the generic arguments can be inferred. I already demonstrated that this can be used to rethrow checked exceptions without wrapping it, which has become one of my favorite Java utility methods. So maybe we can create something similar for casts? Well yes, it’s possible. In order to do so we just define a static cast-method. The return type and the argument type are generic. Since both are inferred by the compiler, we just introduced a ‘cast’ which automatically casts to the expected type.

public class JavaLangUtils {
    private JavaLangUtils(){
    }

    public static <TSource,TTarget> TTarget cast(TSource toCast){
        return (TTarget) toCast;
    }
}

A few examples of the usage

Note that this also allows impossible casts, which are usually detected by the Java compiler. Let’s take a look at an example:

 // works with our cast-method
 List<String> listOfStrings = cast(number);

 // compile error
 List<String> listOfStrings = (String) number;

Furthermore this only works for type declarations. If you immediately pass it to another method it doesn’t work =(

 // Just works
 List<String> listOfString = cast(list);

// Doesn't work
printAll(cast(list));

Restrict Casting

Additionally we can restrict our cast method usage. We can use the co- and contra-variance declaration for generics. Even cooler we can define relations between the generic arguments. For example we can define that the cast-target has to be a sub-type in order to be casted.

public static <TSource,TTarget extends TSource> TTarget cast(TSource toCast){
    return (TTarget) toCast;
}

Here’s a example where the restrictions apply

Compiler Differences

With such generic trickery you might hit edge cases where the compilers disagree with each other. With this cast-method there’s a edge case when you combine the inference with auto boxing. The Java-6 javac-compiler will give a compiler error when cast something to a primitive-type. The Eclipse compiler is fine with that and works as expected. With the boxed type Integer it works just fine with both compiler.

// Works with Javac and Eclipse compiler
Integer aInt = cast(number);

// Doesn't work with the Javac compiler
// Works fine with the Eclipse compiler
int aInt = cast(number);

Conclusion

I’ve demonstrated that you can define a cast-method which infers the cast target type from its usage. However this only works in some cases, loses some compiler checks and also brings some compiler edge cases differences to the surface. So it’s not really a good idea for production code.

Tagged on: , ,

One thought on “Magic Cast Method in Java