Search code examples
javareflectionjar

How to find classes when running an executable jar


I am running an executable jar and wish to find a list of classes WITHIN the jar so that I can decide at run-time which to run. It's possible that I don't know the name of the jar file so cannot unzip it


Solution

  • You can not enumerate classes from a package of jar using Reflection API. This is also made clear in the related questions how-can-i-enumerate-all-classes-in-a-package and can-i-list-the-resources-in-a-given-package. I once wrote a tool that lists all classes found in a certain classpath. It's too long to paste here, but here is the general approach:

    1. find the used classpath. This is shown nicely by eirikma in another answer.

    2. add other places where the ClassLoader might search for classes, e.g. bootclasspath, endorsed lib in JRE etc. (If you just have a simple app, then 1 + 2 are easy, just take the class path from property.)

      • readAllFromSystemClassPath("sun.boot.class.path");
      • readAllFromSystemClassPath("java.endorsed.dirs");
      • readAllFromSystemClassPath("java.ext.dirs");
      • readAllFromSystemClassPath("java.class.path");
    3. Scan the classpath and split folders from JARs.

      • StringTokenizer pathTokenizer = new StringTokenizer(pPath, File.pathSeparator);
    4. Scan the folders with File.listFiles and open the JARs with ZipFile.entries. Pay attention to inner classes and package access classes, you propably do not want them.

      • isInner = (pClassName.indexOf('$') > -1);
    5. Convert the file name or path in the JAR to a proper classname (/ -> .)

      • final int i = fullName.lastIndexOf(File.separatorChar);
      • path = fullName.substring(0, i).replace(File.separatorChar, '.');
      • name = fullName.substring(i + 1);
    6. Now you can use Reflection to load that class and have a look into it. If you just want to know stuff of about the class you can load it without resolving, or use a byte code engineering library like BCEL to open the class without loading it into the JVM.

      • ClassLoader.getSystemClassLoader().loadClass(name).getModifiers() & Modifier.PUBLIC