Sunday, September 25, 2005

Private: The Enemy of Extensibility

I was shocked to find out tonight that junit.runner.ClassPathTestCollector didn't account for tests in jars. OK, easy enough. I look through the class and find a methood called gatherFiles(File,String,result). It takes a file and determines if it is a test class. Well, a simple check to see if the file is a jar, add the class names of the entries which are tests to the result, and we were in business, right? Well, that's what I thought! So, I overrode gatherFiles, added super to let it do its job, and then, added my jar functionality. Simple right?! It didn't compile. It seems gatherFiles is a private method and I didn't have any visibility for the super. OK, I then just copied the original gatherFiles in place of the super and a little gentle refactoring. Everything compiled, but it worked like the old one. It then struck me. You can't override private methods. GRRRRRR! So, I wound up copying the remaining methods that I needed and removed ClassPathTestCollector as my superclass. It shocked me to know what should have been a simple refactoring, turned into a lot more, and it forced me to commit the worst of all sins: Duplicate code. Oh, did you want to see the jar code? Here you go:

protected void gatherFilesInJar(File jarFile, Hashtable result) {
try {
JarFile jar = new JarFile(jarFile);
try {
Enumeration enumeration = jar.entries();
while (enumeration.hasMoreElements()) {
JarEntry next = (JarEntry) enumeration.nextElement();
if (next.getName().endsWith(".class") && next.getName().indexOf('$') == -1) {
addToResultsIfTest(next.getName(), result);
} finally {
} catch (IOException ex) {

Nothing to it! Anyway, it was a fun bit of functionality to add, so that I can find and add all of my tests in my project now. I ran into these issues with private in Swing as well. I just think as designers we should not close our classes. The reason is because you never know what someone might need to do with your code eventually. Sealing means you know best. Just like I wanted to be able to handle jars in ClassPathTestCollector. If the original designer had thought of that, then he/she would have added that capability. Instead, they sealed off the class and forced me to sin. Don't make the same mistake.

No comments: