You have classes that have static compile time dependencies on classes that can only be built on a specific platform.
Make use of the java.lang.reflect to break the static dependency.
import org.davison.data.jdbc.JDBCProvider; . . . DataProvider dp = new JDBCProvider();
try
{
DataProvider dp = (DataProvider)
Class.forName("org.davison.data.jdbc.JDBCProvider").newInstance();
}
catch (IllegalAccessException iae)
{
// Convert exception to error to preseve the interface.
//
throw new IllegalAccessError(iae.getMessage());
}
catch (InstantiationException ie)
{
// Convert exception to error to preseve the interface.
//
throw new InstantiationError(ie.getMessage());
}
catch (ClassNotFoundException cnfe)
{
// Convert exception to error to preseve the interface.
//
throw new NoClassDefFoundError(cnfe.getMessage());
}
In some cases you have to provide drivers to provide different functionality depending on the situation. You might have classes that on a given platform need to access some sun.* classes to perform a specific function. For example a class to access WinHelp needs to get the window handle via the sun.awt.windows.WWindowPeer classes.
There might also be the desire to only provide certian functionality to a given sub-set of users. This is the equivalent of being able to compile out code without having to alter the source or use pre-compilers.
This method can be used with good effect with application frameworks where you do not know which class need to be used at compile time.
java.lang.reflect package.Start with this code:
import org.davison.data.jdbc.JDBCProvider; . . . DataProvider dp = new JDBCProvider();
First we have to change the selection code to return a class name rather than an actual instance. We can safely remove the import statement that referes to this class.
Class.forName("org.davison.data.jdbc.JDBCProvider")
We can now instantiate the class, in this simple case the constructor has no parameters, so we do not have to make use of the extended java.lang.reflect package.
DataProvider dp = (DataProvider)
Class.forName("org.davison.data.jdbc.JDBCProvider").newInstance();
We now have to add the code to deal with the possible exception cases. Here I have chosen to convert them to the equivalent Java Errors in order to maintain the interface. If this is not required then simpler code is possible.
try
{
DataProvider dp = (DataProvider)
Class.forName("org.davison.data.jdbc.JDBCProvider").newInstance();
}
catch (IllegalAccessException iae)
{
// Convert exception to error to preseve the interface.
//
throw new IllegalAccessError(iae.getMessage());
}
catch (InstantiationException ie)
{
// Convert exception to error to preseve the interface.
//
throw new InstantiationError(ie.getMessage());
}
catch (ClassNotFoundException cnfe)
{
// Convert exception to error to preseve the interface.
//
throw new NoClassDefFoundError(cnfe.getMessage());
}
Compile and test at this point as we have code that is complete.
When this is finished and all dependent classes are re-tested, the refactoring is complete.