使用Reflection从Jar文件中获取所有类

时间:2014-07-23 02:33:41

标签: java reflection jar

我需要从ClassPath上的Jar文件中获取所有类,并使用 this article 作为我的解决方案。当我将路径设置为包名称时,本文中的方法起作用,但如果包位于Jar文件中,则该方法不起作用。

根据评论,人们发布了他们声称将用于Jar文件的代码(他们修改了文章代码)。我查看了他们的代码,它似乎应该可以工作,它确实适用于jar文件中的包,但它们没有指定传入的内容作为告诉方法的参数包来自jar文件。我已经尝试了我能想到的每一种组合,但没有任何效果。

因此,在Jar文件中使用的包,这将是使用这些方法的工作方式,

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

它应该与Jar文件中的包一起使用,但我不知道用"my.package.name"替换什么。我试过给Jar文件上的包名,但是找不到任何东西。

我的想法是类似于"myJarName""myJarName.my.package.name",但这些都不起作用。

这是完整的代码,

    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;
        }

    }

您应该能够复制所有代码并进行编译(不会使用某些导入,因为我只显示与问题相关的部分而不是整个程序)。

对于工作演示,您可以将"my.package.name"更改为您在类路径上的某个包。

1 个答案:

答案 0 :(得分:-3)

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

我以前从未使用过这种方法,如果我需要做你想做的事我会用

Classname name = new Classname();