You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取指定JDK类的jmod文件并遍历结构?兼容JDK8及以上

兼容JDK8及更高版本的JDK类库遍历方案

在JDK8及更早版本中,我们可以通过获取类的CodeSource定位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();
        // 执行业务逻辑
    }
}

但从JDK9开始,JDK采用模块化架构(原rt.jar被拆分为多个jmod文件),上述代码会抛出空指针异常:

java.lang.NullPointerException: Cannot invoke "java.security.CodeSource.getLocation()" because the return value of "java.security.ProtectionDomain.getCodeSource()" is null

兼容JDK8与JDK9+的解决方案

以下方案会先尝试JDK8及之前的CodeSource方式,若失败则自动切换为JDK9+的模块化API实现,无需单独分支判断:

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public void traverseJdkClasses(Class<?> clazz) throws IOException {
    URL location = null;
    Module clazzModule = clazz.getModule();

    // 优先尝试JDK8及更早版本的方式
    try {
        location = clazz.getProtectionDomain().getCodeSource().getLocation();
    } catch (NullPointerException | SecurityException e) {
        // 模块化环境下,通过模块API获取资源位置
        if (clazzModule.isNamed()) {
            String classResourcePath = "/" + clazz.getName().replace('.', '/') + ".class";
            location = clazzModule.getResource(classResourcePath);
        }
    }

    if (location == null) {
        throw new IOException("无法获取类所在的JDK库位置");
    }

    String locationStr = location.toString();
    // 处理JDK9+的jrt:/协议或jmod文件
    if (locationStr.startsWith("jrt:/")) {
        String moduleName = clazzModule.getName();
        // 直接访问JRT文件系统遍历模块内容
        try (var fs = FileSystems.getFileSystem(URI.create("jrt:/"))) {
            Path moduleRoot = fs.getPath("/modules/" + moduleName);
            Files.walk(moduleRoot)
                    .filter(path -> path.toString().endsWith(".class"))
                    .forEach(this::processClassEntry);
        }
    } else {
        // 处理JDK8及之前的jar文件(如rt.jar)
        File file = new File(location.toURI());
        try (JarFile jarFile = new JarFile(file)) {
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
                    processClassEntry(entry);
                }
            }
        }
    }
}

// 示例业务逻辑方法,可根据需求修改
private void processClassEntry(Object entry) {
    if (entry instanceof JarEntry) {
        System.out.println("Jar类条目:" + ((JarEntry) entry).getName());
    } else if (entry instanceof Path) {
        System.out.println("模块类路径:" + ((Path) entry).toString());
    }
}

关键说明

  1. 自动适配:通过捕获NullPointerException和SecurityException,自动切换到模块化逻辑,无需显式判断JDK版本
  2. JRT文件系统:JDK9+提供jrt:/协议直接访问模块内容,无需手动定位jmod文件,可靠性更高
  3. 权限兼容:加入SecurityException捕获,避免因安全策略限制导致的执行失败

内容的提问来源于stack exchange,提问作者Nicolas Baumann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 04:10:32