Java Reference
In-Depth Information
try {
Class auditClazz = Class.forName(auditorName);
Method method = auditClazz.getDeclaredMethod(
"audit", Spoke.class, Message.class);
Calls auditor
method
method.invoke(null, this, message);
return true;
} catch (Throwable e) {
e.printStackTrace();
return false;
}
}
return false;
}
}
This spoke assumes each
Message
implementation has an accompanying
Auditor
class
in the same package and uses reflection to access it and log receipt of the message. The
reason behind this design isn't important; you can imagine that the team wants to sup-
port both audited and non-audited messages without breaking the simple message
API
.
What's important is that by using
Class.forName()
, the spoke bundle assumes it can
see the
Auditor
class. But you don't export your implementation packages, so when
you run the example, we hope you aren't too surprised to see an exception:
$
./chapter08/classloading/PICK_EXAMPLE 6
java.lang.ClassNotFoundException: org.foo.hub.test.Auditor
You know the
Auditor
sits alongside the
Message
implementation in the same pack-
age, so they share the same class loader (you don't have any split packages). You need
to access the
Message
implementation class loader and ask it to load the class like so:
Class auditClazz = msgClazz.getClassLoader().loadClass(auditorName);
Remove the
Class.forName()
line from the spoke implementation in listing 8.3, and
replace it with the previous line. You can now run the example without any problem:
$
./chapter08/classloading/PICK_EXAMPLE 6
Fri Sep 18 00:13:52 SGT 2009 - org.foo.spoke.SpokeImpl@186d4c1
RECEIVED Testing Testing 1, 2, 3...
Class.forName()
considered harmful!
You may wonder why we don't use the longer form of
Class.forName()
—the
method that accepts a user-given class loader instead of using the caller's class
loader. We don't use it because there's a subtle but important difference between
these statements:
Class<?> a = initiatingClassLoader.loadClass(name);
Class<?> b = Class.forName(name, true, initiatingClassLoader);