User Tools

Site Tools


technology:java:compiler_warnings

Handling Compiler Warnings

Unchecked Cast using Class.forName

I have a codebase that uses the the Proxy Pattern to allow dynamic lookups of delegate classnames at runtime. Typically, I use a utility method to retrieve the delegate class name from my database using a key, and then use the Class.forName method to retrieve the class object. Here's a very simple example, without the utility function:

class ForNameTest
{
    public static void main(String[] args) {
        try{
            String classname = getValueFromDB(...);
            Object obj =  Class.forName(classname);
        Class<MyClass>  myclass = (Class<MyClass> ) obj;
            MyClass myobject = myclass.newInstance();
        ....(code that uses myobject here)....
        }catch ...
    }
}

The problem with this approach is: the forName() method returns an object of type Object, so I'm required to downcast the Object reference to the datatype I expect it to be. Unfortunately, the compiler can't know if that value I pass at runtime is valid, so it produces an unchecked cast warning at compile time:

ForNameTest.java:6: warning: [unchecked] unchecked cast
found   : java.lang.Object
required: java.lang.Class<MyClass>
            Class<MyClass>  myclass = (Class<MyClass> ) obj;

The warning makes sense. The compiler is basically throwing up its hands and saying “this might not work…its your problem now”. And I agree it should be my problem.

The normal way of resolving the warning is to add the @SuppressWarnings(“unchecked”) annotation to the method name. It eliminates the warning, but it doesn't really solve the problem. Bad user data will still result in a runtime exception. And that's unacceptable in an app that runs 24×7.

Recently I discovered the Class.asSubclass() method. It allows me to downcast an object in code, and it throws a ClassCastException if the cast is improper…which is something I can code for. Here's an example:

class ForNameTest
{
    public static void main(String[] args) {
        try{
            String classname = getValueFromDB("LengthCalcDelegate"); //my utility function
            Class<?> c =  Class.forName(classname);
            Class<? extends LengthInterface> ntrface = c.asSubclass(LengthInterface.class);
            LengthInterface length = ntrface.newInstance();
            ...(code that uses length here)....
        }catch(ClassNotFoundException cnfe){
            //deal with cnfe
        }catch(InstantiationException ie){
            //deal with ie
        }catch(IllegalAccessException iae){
            //deal with iae
        }
    }
}

Lots of subtleties here. First, the references to Class<?> are generic. They eliminate warnings about the use of raw types. Second, the references to Class<? extends LengthInterface> allow me to cast objects directly to the LengthInterface and yet still allow me to invoke the newInstance method on the class object. And third, all human-related errors at runtime are dealt with explicitly in code.

So now I have type safety, proper exception handling, and no compiler warnings. Perfect!

/home/cfreyer/public_html/data/pages/technology/java/compiler_warnings.txt · Last modified: 2010/01/20 11:58 by Chris Freyer