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



我需要从ClassPath上的Jar文件中获取所有类,我使用了这篇文章作为我的解决方案。当我将路径设置为包名时,本文中的方法可以工作,但如果包位于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"更改为类路径上的某个包。

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

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

Classname name = new Classname();

相关内容

  • 没有找到相关文章

最新更新