如何从classloader获取classpath?

Mar*_*kis 47 java classloader contextclassloader

我正在使用一些第三方代码,当给出'-classpath'命令行参数时,不设置java.class.path,而只是创建一个类加载器,将命令行指定类路径上的项的所有url添加到类加载器,然后将其设置为上下文类加载器.在我编写的这段代码的插件类中,我得到了这个类加载器的一个实例,并且不知何故需要使用它来获取底层的类路径,以便我可以在JavaCompiler.getTask的调用中使用它(... )并动态编译其他代码.但是,似乎没有从ClassLoader获取ClassPath,并且由于java.class.path未设置,我似乎无法访问最初调用应用程序的基础类路径...任何想法?

Ade*_*ros 56

如果类加载器使用URL,则必须是a URLClassloader.您可以访问的是URL,它定义了与其父级一起的类路径ClassLoader.

要获取URL,只需执行以下操作:

((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案在Java 9上不再起作用,因为类加载器无法转换为URLClassLoader (5认同)
  • ClassCastException:无法将“jdk.internal.loader.ClassLoaders$AppClassLoader”转换为“java.net.URLClassLoader” (2认同)

Luk*_*son 18

更新:我的原始答案严重不足,现在我已经花了三年时间开发FastClasspathScanner,并且已经有大量关于某些不使用此库的类路径环境的错误报告.FastClasspathScanner现在处理许多复杂的类路径规范机制.即使只是找到类路径也可能在一般情况下非常复杂(更不用说扫描它),因为有很多方法可以将jar和目录添加到类路径中.

首先,我在下面给出的代码只处理java.class.path,并且许多主要的运行时环境和容器都不扩展它,它们从头开始实现自己的类加载器.但是在Java 9+的情况下它变得比这复杂得多,因为即使传统的类路径仍然存在,未来的一切都将朝着使用模块路径而不是类路径的方向发展.模块有URL,但它们是((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()URL,而不是java.class.pathURL,模块URL实际上并不包含文件路径,只包含模块名称 - 因此您通常无法在磁盘上找到模块.您唯一的选择是使用(重度封装的)模块系统来处理模块.我在这里写了关于如何扫描模块路径的文章.

FastClasspathScanner处理许多复杂的类路径规范机制,因此您无需重新发明轮子.您可以从FastClasspathScanner中获取类路径条目列表 - 这将为您省去尝试使用您在野外找到的所有不同类路径规范机制的麻烦.(如果最后一个链接中断,请道歉 - FCS的API和文档很快就会改变.)

-

[旧答案 - 过时了:]

其他答案在大多数情况下是正确的,但它比某些设置更复杂:例如,Maven,Tomcat和JUnit都有自己的类路径支持,并且它们不使用系统类路径.

到目前为止,这是我设法提供的最完整的系统(此代码来自我的Fast Classpath Scanner项目):

List<URI> classpath = new ClassGraph().getClasspathURIs();
Run Code Online (Sandbox Code Playgroud)

  • 如果您关注该项目,这绝对是最完整的答案并且正在积极发展。 (2认同)
  • @luke-hutchison 你的图书馆是救命稻草!对于任何想要为各种运行时环境获取类路径的解决方案的人来说,这是最好的。 (2认同)

BJ *_*ruz 7

为了将来参考,如果您需要将类路径传递给ProcessBuilder:

StringBuffer buffer = new StringBuffer();
for (URL url :
    ((URLClassLoader) (Thread.currentThread()
        .getContextClassLoader())).getURLs()) {
  buffer.append(new File(url.getPath()));
  buffer.append(System.getProperty("path.separator"));
}
String classpath = buffer.toString();
int toIndex = classpath
    .lastIndexOf(System.getProperty("path.separator"));
classpath = classpath.substring(0, toIndex);
ProcessBuilder builder = new ProcessBuilder("java",
    "-classpath", classpath, "com.a.b.c.TestProgram");
Run Code Online (Sandbox Code Playgroud)


Yav*_*in5 5

如果其他答案不起作用,请尝试以下方法:

ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url: urls) {
    System.out.println(url.getFile());
}
Run Code Online (Sandbox Code Playgroud)