【问题标题】:Loading classes from a set of files从一组文件加载类
【发布时间】:2015-07-02 08:42:07
【问题描述】:

我的任务是检查类路径中未知类集的一组条件。我想扫描它的类,加载每个类并执行我的检查。现在我有一组类文件的 url,我尝试使用 URLClassLoader。但是要加载一个类,我需要指定一个完全限定的类名,但我没有它们(我只有文件路径)。我不认为从类文件路径构建类名是可靠的,这是一种更好的方法吗?

谢谢!

【问题讨论】:

  • 为什么从类文件路径构建类名不可靠?我认为是这样。我看到的唯一问题是内部类(一个类文件中的多个类)。这就是问题所在。
  • 我的 Win 桌面上有类似 C:\Projects\my_project_trunk\module\target\classes\com\a\b\c\d\e\f\Smth.class 之类的东西 / home/user/teamcity/agent1/.../a/b/c/d/e/f/Smth.class 在构建服务器上,所以我的解析器应该找到“类”部分,构建包名称等。有趣的是为什么我们可以“ t 从类文件中获取类名,它应该在那里......
  • 我只是解析类文件的开头,寻找“包”关键字和“类”关键字的第一次出现。然后,当您将这两者结合起来时(packageName + "." + className),它应该会产生一个正确的类名。
  • @PiotrSliwa 将此作为答案(用于投票)。你是对的。

标签: java classloader urlclassloader


【解决方案1】:

我只是解析类文件的开头,寻找“包”关键字和“类”关键字的第一次出现。然后,当您将这两个 (packageName + "." + className) 结合起来时,它应该会产生一个正确的类名。

【讨论】:

  • PiotrSliwa,谢谢你的想法。最后我使用了commons-bcel库来解析.class文件,这有点简单。
【解决方案2】:

我曾经启动了一个项目,通过使用 null01-1、@987654326 等狡猾的参数反射性地调用构造函数和方法来自动测试在类路径上找到的类是否存在运行时异常@等

该项目有一个名为 Finder 的类,可以大致满足您的需求:

    static List<Class<?>> findClassesForPackage(String packagename, Report report) throws ClassNotFoundException {
            // 'classes' will hold a list of directories matching the package name.
            // There may be more than one if a package is split over multiple
            // jars/paths
            List<Class<?>> classes = new ArrayList<Class<?>>();
            List<File> directories = new ArrayList<File>();
            try {
                    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                    if (classLoader == null) {
                            throw new ClassNotFoundException("Can't get class loader.");
                    }
                    // Ask for all resources for the path
                    String path = packagename.replace('.', '/');
                    Enumeration<URL> resources = classLoader.getResources(path);
                    while (resources.hasMoreElements()) {
                            URL res = resources.nextElement();
                            if (res.getProtocol().equalsIgnoreCase("jar")) {
                                    JarURLConnection conn = (JarURLConnection) res.openConnection();
                                    JarFile jar = conn.getJarFile();
                                    for (JarEntry entry : Collections.list(jar.entries())) {
                                            if (entry.getName().startsWith(path) && entry.getName().endsWith(".class")
                                                            && !entry.getName().contains("$")) {
                                                    String className = entry.getName().replace("/", ".").substring(0,
                                                                    entry.getName().length() - 6);
                                                    LOG.debug("Adding JAR className " + className);
                                                    try {
                                                            Class<?> clazz = Class.forName(className);
                                                            classes.add(clazz);
                                                            report.addClass(className);
                                                    } catch (Throwable throwable) {
                                                            ParamSet params = new ParamSet();
                                                            params.addParamValue(new ParamValue(className, "fully qualified classname"));
                                                            report.addError(className, new Error("Class.forName()", params, throwable));
                                                    }
                                            }
                                    }
                            } else
                                    directories.add(new File(URLDecoder.decode(res.getPath(), "UTF-8")));
                    }
            } catch (NullPointerException e) {
                    throw new ClassNotFoundException(String.format("%s does not appear to be a valid package", packagename), e);
            } catch (UnsupportedEncodingException e) {
                    throw new ClassNotFoundException(String.format("%s does not appear to be a valid package", packagename), e);
            } catch (IOException e) {
                    throw new ClassNotFoundException(String.format("Could not get all resources for %s", packagename), e);
            }
            List<String> subPackages = new ArrayList<String>();
            // For every directory identified capture all the .class files
            for (File directory : directories) {
                    if (directory.exists()) {
                            // Get the list of the files contained in the package
                            File[] files = directory.listFiles();
                            for (File file : files) {
                                    // add .class files to results
                                    String fileName = file.getName();
                                    if (file.isFile() && fileName.endsWith(".class")) {
                                            // removes the .class extension
                                            String className = packagename + '.' + fileName.substring(0, fileName.length() - 6);
                                            LOG.debug("Adding FILE className " + className);
                                            try {
                                                    Class<?> clazz = Class.forName(className);
                                                    classes.add(clazz);
                                                    report.addClass(className);
                                            } catch (Throwable throwable) {
                                                    ParamSet params = new ParamSet();
                                                    params.addParamValue(new ParamValue(className, "fully qualified classname"));
                                                    report.addError(className, new Error("Class.forName()", params, throwable));
                                            }
                                    }
                                    // keep track of subdirectories
                                    if (file.isDirectory()) {
                                            subPackages.add(packagename + "." + fileName);
                                    }
                            }
                    } else {
                            throw new ClassNotFoundException(String.format("%s (%s) does not appear to be a valid package",
                                            packagename, directory.getPath()));
                    }
            }
            // check all potential subpackages
            for (String subPackage : subPackages) {
                    classes.addAll(findClassesForPackage(subPackage, report));
            }
            return classes;
    }

您可能必须剥离一些用于报告等的代码。

【讨论】:

    猜你喜欢
    • 2020-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    相关资源
    最近更新 更多