I have utility class U that depends on a library X, and must go in a package that will be used from programs with X available (where it should do its normal stuff), and places without X (where it should do nothing). Without splitting the class in two, I have found a simple pattern that solves this:
package foo;
import bar.MisteriousX;
public class U {
static private boolean isXPresent = false;
static {
try {
isXPresent = (null != U.class.getClassLoader().loadClass("bar.MisteriousX"));
} catch (Exception e) {
// loading of a sample X class failed: no X for you
}
}
public static void doSomething() {
if (isXPresent) {
new Runnable() {
public void run() {
System.err.println("X says " + MisteriousX.say());
}
}.run();
} else {
System.err.println("X is not there");
}
}
public static void main(String args[]) { doSomething(); }
}
With this pattern, U requires X present to compile, but works as expected when run with or without X present. Unless all accesses to the X library are inside internal classes, this code launches a classloader exception.
Questions: is import resolution guaranteed to work like this everywhere, or will it depend on JVM/ClassLoader implementation? Is there an established pattern for this? Is the above code-snippet too hackish to make it into production?
Generally, when a class is first loaded, then if it refers to a class which does not exist, that might lead to an error. So yes, having one class do the check and another class actually access the external package without reflection will work as intended, at least on all implementations I’ve seen so far. It doesn’t have to be an inner class.
The Linking section in the JVM specs give great freedom to implementations. If you don’t use the two-class approach, then the verification of
Uin an implementation using eager linking will cause an attempt to loadXwhich results in aLinkageError. The specs don’t require the references class to be verified as well, but neither does it forbid such early verification. It does however require thatSeems you should be safe to assume that the error is only thrown when you actually access your inner class. If you look at the history of this answer, you will find that I already changed my opinion twice, so there will be no guarantees that I read it correctly this time… :-/