Did you ever have a build complain that you don't have a class on your classpath that you need and although you'd be delighted to comply and put the class on your classpath, you don't know what JAR it's in? Here is a way to find the needle in the haystack.
Here we'll use an example involving Glassfish, because this seems to happen on server-side projects that involve a great number of different JARs (web services requires JAXB, XJC, WSImport, JUnit, the Ant tasks that go with them, and so forth, for example). You want only the JARs that you actually need on your cp, not hundreds of modified bundled versions of things on your cp that may or may not be in use--which is what some IDEs do.
If your build doesn't work because, say, an Ant task that wraps some program such as XJC complains that it can't find a class like "com/sun/enterprise/cli/framework/InputsAndOutputs.class" you need to find that class. You can tell from the name that it's provided by Sun, and can look in the Glassfish lib directory and just use the brute-force method of opening JARs one by one and eyeballing it. But if you open the lib directory of Glassfish (or WebLogic 10 or Spring or anything these days), there are dozens of JARs in there! It can be really boring and time-consuming to determine which JAR has the class you want.
You don't know what this class does. You don't even care about this class at all. You just need your XJC Ant task to work and apparently some class in there needs some other class that needs this one.
But it's not a good practice to throw all of the JARs in there on your cp--it is slow and misleading and doesn't help learn you about what's happening under the hood. And in my view it is not good to be dependent on the IDE whatsoever. You should be able to execute ant from the command line and your build should still work. I can't tell you how many Ant scripts I've seen whose authors claim that their projects will run outside of their IDE, and they don't because they have conflated the IDEs paths with their Ant paths. That drives me nuts.
So, on a Linux system, the following command will examine all of the Jar files in the current directory and print their contents to a file called "tmp".
find . -name "*.jar" -print -exec jar -tvf {} \; > tmp
The resulting file looks like this:
./appserv-deployment-client.jar
0 Tue Apr 24 07:21:00 MST 2007 META-INF/
449 Tue Apr 24 07:20:58 MST 2007 META-INF/MANIFEST.MF
0 Tue Apr 24 06:45:36 MST 2007 com/
0 Tue Apr 24 06:45:34 MST 2007 com/sun/
0 Tue Apr 24 06:45:34 MST 2007 com/sun/enterprise/
0 Tue Apr 24 06:45:42 MST 2007 com/sun/enterprise/admin/
0 Tue Apr 24 06:45:42 MST 2007 com/sun/enterprise/admin/common/
0 Tue Apr 24 06:45:38 MST 2007 com/sun/enterprise/admin/common/exception/
645 Tue Apr 24 06:45:28 MST 2007 com/sun/enterprise/admin/common/exception/AFException.class
0 Tue Apr 24 06:45:42 MST 2007 com/sun/enterprise/admin/util/
1821 Tue Apr 24 06:45:28 MST 2007 com/sun/enterprise/admin/util/HostAndPort.class
...and so on. Each JAR will be named, followed by all of the packages and classes in it. So you can then use the "less" tool to find your guy.
Within the "less" tool, type:
> /InputsAndOutputs
to search down the contents for the "InputsAndOutputs" class. This will find and highlight that text (as long as the JAR that contains your class actually was in the directory you ran this command from).
Now all that's left is to search up the file for the first instance of ".jar" and that will be the name of the JAR file containing your class:
>?.jar
This highlights "./admin-cli.jar", which is indeed the Glassfish JAR file containing InputsAndOutputs.class. So now I can drop that on my classpath and get on with my build.
If you don't know what JAR file contains a class you're looking for, this is an easy way to deal with it on Linux. Don't forget to delete the "tmp" file if you don't want to leave it around for another time.
The following shell script will search for the provided text within all jars under the current directory. Call it something like "jargrep", add it to your path, and then run "jargrep "
#!/bin/bash
for f in `find . -name '*.jar' -print`
do
if unzip -l $f | grep -q "$*"
then ls $f
fi
done
Posted by: Patrick | May 22, 2008 at 01:40 PM
Oops, above comment ate my angle brackets. Should say run "jargrep myclass" to search for myclass.
Posted by: Patrick | May 22, 2008 at 01:41 PM