2

I need to get all the Classes from a Jar file that's on the ClassPath and I used this article for my solution. The methods from the article work when I set the path to a package name but does not work if the package is in a Jar file.

Under the comments people posted code which they claim will work for Jar files (they modified the articles code). I've looked over their code and it seems like it should work, and it does work for packages that are not in jar files, but they did not specify what to pass in as the argument telling the methods the package is from a jar file. I've tried every combination I could think of but nothing will work.

So, with a package that's not in a Jar file, this would be the working way to use the methods,

    Class[] myClasses = getClassesInPackage("my.package.name", null);

And it's supposed to work with a package in a Jar file but I don't know what to replace "my.package.name" with. I've tried just giving the package name that's on the Jar file but it doesn't find anything.

My idea is it's something similar to "myJarName" or "myJarName.my.package.name" but none of these are working.

Here is the full code,

    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.Member;
    import java.net.URL;
    import java.net.URLDecoder;
    import java.util.ArrayList;
    import java.util.Enumeration;
    import java.util.List;
    import java.util.TreeSet;
    import java.util.regex.Pattern;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipInputStream;
    import static java.lang.System.out;

    public class ClassSpy {

        public static void main(String... args) {


        try {

            Class[] myClasses = getClassesInPackage("you.package.name.here", null);

            for(Class index: myClasses)
                out.format("Class:%n  %s%n%n", index.getCanonicalName());

        }
        catch (ArrayIndexOutOfBoundsException e) {

            e.printStackTrace();
        }

       /** 
       * Scans all classes accessible from the context
       * class loader which belong to the given package
       * and subpackages. Adapted from 
       * http://snippets.dzone.com/posts/show/4831
       * and extended to support use of JAR files
       * @param packageName The base package
       * @param regexFilter an optional class name pattern.
       * @return The classes
       */ 
       public static Class[] getClassesInPackage(String packageName, String regexFilter) {

            Pattern regex = null;

            if (regexFilter != null) 
                regex = Pattern.compile(regexFilter);

            try {

                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                assert classLoader != null;
                String path = packageName.replace('.', '/');
                Enumeration<URL> resources = classLoader.getResources(path);
                List<String> dirs = new ArrayList<String>();

                while (resources.hasMoreElements()) {

                    URL resource = resources.nextElement();
                    dirs.add(resource.getFile());
                }

                TreeSet<String> classes = new TreeSet<String>();
                for (String directory : dirs) {

                    classes.addAll(findClasses(directory, packageName, regex));
                }

                ArrayList classList = new ArrayList();

                for (String clazz : classes) {

                    classList.add(Class.forName(clazz));
                }

                return (Class[]) classList.toArray(new Class[classes.size()]);
            }
            catch (Exception e) {

                e.printStackTrace();
                return null;
            }

        }

        /** 
        * Recursive method used to find all classes in a given path 
        * (directory or zip file url). Directories are searched recursively. 
        * (zip files are Adapted from http://snippets.dzone.com/posts/show/4831 
        * and extended to support use of JAR files @param path The base 
        * directory or url from which to search. @param packageName The package
        * name for classes found inside the base directory @param regex an
        * optional class name pattern. e.g. .*Test* 
        * @return The classes
        */ 
        private static TreeSet findClasses(String path, String packageName, Pattern regex) throws Exception {

            TreeSet classes = new TreeSet();

            if (path.startsWith("file:") && path.contains("!")) {

                String[] split = path.split("!");
                URL jar = new URL(split[0]);

                ZipInputStream zip = new ZipInputStream(jar.openStream());
                ZipEntry entry;

                while ((entry = zip.getNextEntry()) != null) {

                    System.out.println("Here 1");

                    if (entry.getName().endsWith(".class")) {

                        System.out.println("Here 2");

                        String className = entry.getName()
                            .replaceAll("[$].*", "")
                            .replaceAll("[.]class", "")
                            .replace('/', '.');

                        if (className.startsWith(packageName) && (regex == null 
                            || regex.matcher(className).matches())) 

                                classes.add(className);
                    }

                }

            }

            File dir = new File(path);

            if (!dir.exists()) {

                return classes;
            }

            File[] files = dir.listFiles();

            for (File file : files) {

                if (file.isDirectory()) {

                    assert !file.getName().contains(".");
                    classes.addAll(findClasses(file.getAbsolutePath()
                                        , packageName + "." + file.getName()
                                        , regex));
                }
                else if (file.getName().endsWith(".class")) {

                    String className = packageName + '.' + file
                                                .getName()
                                                .substring(0, file.getName().length() - 6);

                    if (regex == null || regex.matcher(className).matches()) 
                classes.add(className);
                }

            }

         return classes;
        }

    }

You should be able to copy all of the code and compile it (some imports won't be used because I'm only showing the parts related to the problem and not the whole program).

For a working demonstration you can change "my.package.name" to some package you have that's on the classpath.

Kyle Bridenstine
  • 6,055
  • 11
  • 62
  • 100

1 Answers1

-3
Class[] myClasses = getClassesInPackage("my.package.name", null);

Ive never used this method before if i would need to do what you're trying to do i would just use

Classname name = new Classname();
Ilya
  • 29,135
  • 19
  • 110
  • 158
  • I just realised what you're trying to say...You're telling me how to create an instance of a class which is already being done several times in the code I posted above. I'm not instantiating a class I'm getting the class information by reflection. – Kyle Bridenstine Jul 23 '14 at 12:54
  • add more explanation to answer. – Pramod S. Nikam Jul 24 '14 at 05:40