在JDK8之前,我可以使用以下方法来迭代rt.jar类。如果只上一节课,我可以找到其他所有这样的:
final URL location = clazz.getProtectionDomain().getCodeSource().getLocation();
final File file = new File(location.toURI());
try (JarFile jarFile = new JarFile(file)) {
final Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
final JarEntry jarEntry = entries.nextElement();
// do something...
}
}在JDK8之后,使用此clazz.getProtectionDomain().getCodeSource().getLocation()不再有效:
java.lang.NullPointerException: Cannot invoke "java.security.CodeSource.getLocation()" because the return value of "java.security.ProtectionDomain.getCodeSource()" is null这个有好的替代品吗?我在考虑做这样的特例:
if (clazz.getProtectionDomain().getCodeSource() == null) {
// find URL to the jmod ...
}然而,在这两种情况下都适用的解决办法将是可取的。
发布于 2022-11-10 11:49:05
你的问题中有一个错误的假设,如classes are never loaded from a .jmod file。
您可以获得模块的位置,如
Module m = clazz.getModule();
System.out.println(m.getLayer().configuration()
.findModule(m.getName()).flatMap(rm -> rm.reference().location())
.orElse(null));这不适用于“未命名模块”,即读取通过类路径加载的类,因此如果.getProtectionDomain().getCodeSource().getLocation()是false,则必须求助于false。
但是,对于内置模块,URI始终是jrt:/module-name,因此要迭代平台类,根本不需要这样做。
例如,这个代码片段列出了java.lang包中的所有类:
try(var list = Files.list(Paths.get(URI.create("jrt:/java.base/java/lang")))) {
list.map(p -> p.getFileName().toString())
.filter(s -> s.endsWith(".class"))
.map(s -> "java.lang." + s.substring(0, s.length() - 6))
.forEach(System.out::println);
}要获取java.lang.Object的类文件字节,只需使用
byte[] objectClassFile = Files.readAllBytes(
Paths.get(URI.create("jrt:/java.base/java/lang/Object.class")));https://stackoverflow.com/questions/74388106
复制相似问题