Tuesday, 21 August 2007

Finding all property files on the classpath

Property files are widely used in java applications for internationalization. This usually means several files have to have their keys kept in sync. There are other pitfalls with property files as well: duplicate keys within the same file, trailing white space after the line continuation character and other wonderful things that I am sure will come up at some point.

I've got a test class that will take a directory on the classpath and look for all property files there and do comparisons and checks on them. The very first version of this tool used hard coded, absolute paths to the file, but that was close to 4 years ago. In recent version I pumped up logging on it and noticed that it ran fine in eclipse, but when you run it in maven it wasn't finding any of the files if the same directory existed in the src/test/resources as in src/main/resources (or if you just were looking at the "root" of src/main/resources). Like most PITA things in java, it was a classpath issue.

Maven's pretty smart. The path of the classloader (for surefire) is src/test first, then anything in src/main, then the dependencies. That makes sense. After running mvn eclipse:eclipse, the .classpath it's src/main first. Wonderful. :-(

The way the code ran before asked the testing class for the resource like this:
URL url = getClass().getResource(resource);
That worked great in eclipse... not so great in maven.

Then I thought "oh course! The classpath is a system variable!" and tried code like this:
String classpath = System.getProperty("java.class.path");
String[] paths = classpath.split(File.pathSeparator);

No luck either. When surefire runs it does not include any of the project's folder in the classpath. Only the .jar files of the dependencies.

Then after much fruitless digging on forums (where this question seems to have been asked many different ways and times), I found the solution. You have use the classloader of the testing class in order to get the proper paths:
Enumeration<URL> enumeration = getClass().getClassLoader().getResources(resource);
In my testing so far that works both in eclipse and maven and will give you the target/test-classes/ and target/classes/ folders.

The thing that frustrated me was that there are many different ways to get the classloader, and only this one seemed to work the way that I was expecting. I'm just glad that I can move on from this issue that's been hanging on far longer than it needed to.

No comments:

Post a Comment