简体   繁体   English

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

[英]Get all classes from a Jar file using Reflection

I need to get all the Classes from a Jar file that's on the ClassPath and I used this article for my solution. 我需要从ClassPath上的Jar文件中获取所有类,并且将本文用于解决方案。 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. 当我将路径设置为程序包名称时,本文中的方法有效,但如果程序包在Jar文件中,则该方法不起作用。

Under the comments people posted code which they claim will work for Jar files (they modified the articles code). 人们在评论下张贴了他们声称可以用于Jar文件的代码(他们修改了商品代码)。 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. 我查看了他们的代码,似乎它应该可以工作,并且对于不在 jar文件中的程序包也可以工作,但是他们没有指定要传递的内容,因为参数告诉了程序包来自jar文件的方法。 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, 因此,对于不在 Jar文件中的软件包,这将是使用方法的有效方法,

    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. 它应该可以与Jar文件中的包一起使用,但是我不知道该用"my.package.name"替换什么。 I've tried just giving the package name that's on the Jar file but it doesn't find anything. 我尝试仅给出Jar文件中的软件包名称,但找不到任何东西。

My idea is it's something similar to "myJarName" or "myJarName.my.package.name" but none of these are working. 我的想法是,它类似于"myJarName""myJarName.my.package.name"但是这些都不起作用。

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. 对于有效的演示,您可以将"my.package.name"更改为您在类路径中具有的某些软件包。

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

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

Classname name = new Classname();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM