Find where a Java class comes from, recursively
There are 3 notes for this topic, click above title to see all notes.
January 14, 2010 00:28:27 Last update: May 26, 2010 04:01:23
A task that a Java developer does so frequently is to find out where a certain class can be found - to resolve compilation errors, classpath issues, or version conflicts of the same class introduced by multiple class loaders. A long while back I wrote a simple Perl script to perform the task. Later I was informed that there are Swing based Jar Browser and Jars Browser.
Then, there are a couple of shell one-liners:
But all of them share the same problem: if a class is in a jar nested in another jar, it cannot be found. Such is the case for a class inside a jar under the
Then, there are a couple of shell one-liners:
# one liner 1 find -name "*.jar" -print0 | xargs -0 grep -i SomeClassName # one liner 2 for i in $(find . -iname \*.*ar) ; do echo $i ;jar tf $i | grep $1; done
But all of them share the same problem: if a class is in a jar nested in another jar, it cannot be found. Such is the case for a class inside a jar under the
WEB-INF/lib directory of a war file packaged in an ear. This is a simple Java program that solves the problem. It also demonstrates how to read a jar nested inside another jar without using a temporary file.
import java.io.*; import java.util.zip.*; public class FindClass { private static final int BUFFER_SIZE = 4096; private static final String[] JAR_EXTENSIONS = { ".zip", ".jar", ".war", ".ear", ".rar", }; public static void findClass(String path, String classToLookFor, boolean recursive) throws Exception { if (path == null) { return; } // normalize class name if (!classToLookFor.contains("/")) { classToLookFor = classToLookFor.replace('.', '/'); } // normalize path, change \ to / path = path.replace(File.separatorChar, '/'); File f = new File(path); if (f.isDirectory()) { findClassInDirectory(path, classToLookFor, recursive); } else if (f.isFile() && hasJarExtension(path)) { ZipInputStream in = new ZipInputStream(new FileInputStream(path)); findClassInJar(in, classToLookFor, path, recursive); in.close(); } else if (f.isFile() && path.contains(classToLookFor)) { showPath(path); } } private static void findClassInJar(ZipInputStream in, String classToLookFor, String path, boolean recursive) throws Exception { ZipEntry next = in.getNextEntry(); while (next != null) { if (!next.isDirectory()) { if (next.getName().contains(classToLookFor)) { showPath(path + ": " + next.getName()); } else if (recursive && hasJarExtension(next.getName())) { ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buffer = new byte[BUFFER_SIZE]; int n = in.read(buffer, 0, BUFFER_SIZE); while (n >= 0) { // read returns -1 if end of current entry is reached. out.write(buffer, 0, n); n = in.read(buffer, 0, BUFFER_SIZE); } ZipInputStream in2 = new ZipInputStream( new ByteArrayInputStream( out.toByteArray() ) ); findClassInJar(in2, classToLookFor, path + "/" + next.getName(), recursive); in2.close(); } } next = in.getNextEntry(); } } private static void findClassInDirectory(String dir, String classToLookFor, boolean recursive) throws Exception { File d = new File(dir); String[] files = d.list(); for (int i = 0; i < files.length; i++) { String filePath = dir + "/" + files[i]; File file = new File(filePath); if (file.isFile() && filePath.contains(classToLookFor)) { int idx = filePath.indexOf(classToLookFor); showPath(filePath.substring(0, idx) + ": " + filePath.substring(idx)); } else if (recursive) { if (file.isDirectory()) { findClassInDirectory(filePath, classToLookFor, recursive); } else if (hasJarExtension(filePath)) { ZipInputStream in = new ZipInputStream(new FileInputStream(file)); findClassInJar(in, classToLookFor, filePath, recursive); in.close(); } } } } private static boolean hasJarExtension(String fileName) { fileName = fileName.toLowerCase(); for (int i = 0; i < JAR_EXTENSIONS.length; i++) { if (fileName.endsWith(JAR_EXTENSIONS[i])) { return true; } } return false; } private static void showPath(String p) { System.out.println(p); } public static void main(String[] args) throws Exception { if (args.length < 2) { System.out.println("Usage: java FindClass <jarFileName> <classToLookFor>"); System.exit(1); } String path = args[0]; String classToLookFor = args[1]; findClass(path, classToLookFor, true); } }
3 comments 
Easy email testing with http://www.ximailstop.com