如何扫描Java标准API Javadoc的@since标签及-release实现原理
构建Java标准API与引入版本的映射方案
基于@since标签的扫描实现
你要的类、方法、枚举值和首次引入Java版本的对应关系,最直接的数据源就是各版本JDK自带src.zip源码包中Javadoc的@since标记:
- 比如
java.lang.String类的注释上标有@since 1.0,String::strip()方法注释上标有@since 11,和实际版本情况完全对应。 - 具体实现可以直接用JDK内置的Doclet API,或者引入javaparser这类源码解析库,遍历
src.zip中所有公开API(排除sun.*、jdk.internal.*这类内部包下的非公开类),提取每个类、方法、字段、枚举值的签名和对应的@since值即可。 - 注意不要只扫最新版JDK的源码:部分早期API在后续版本中会被移除,还有少量
@since标记存在错标、漏标的情况,最好从Java 1.0到最新LTS版本逐版本交叉校验——如果一个方法在JDK 10的类中不存在、JDK 11中首次出现,哪怕注释漏标,也能准确判定它的引入版本是11。
javac -release参数的实现原理(无Javadoc依赖的实现参考)
你提到的Java 9+编译器-release参数的版本校验能力,完全不依赖src.zip,也不会扫描任何Javadoc内容,性能和准确性都远高于源码扫描方案:
- JDK从9版本开始,在安装目录的
lib路径下自带了一个ct.sym文件,这是官方预先生成的版本化API签名库。这个文件本质是个压缩包,里面按Java版本分目录存储了对应版本所有公开标准API的精简字节码:只保留类、方法、字段的签名信息,去掉了方法实现、注释、调试信息等所有冗余内容。 - 当执行
javac -release N命令编译时,编译器不会直接加载当前JDK运行时的类作为编译类路径,而是从ct.sym中取出版本N对应的API签名集合作为唯一的编译期类路径。如果代码中引用了不在这个签名集合里的类、方法或者字段,就会直接抛出"找不到符号"的编译错误——你举的-release 10下调用String::strip()报错的场景,就是因为Java 10对应的签名集合里根本没有strip()方法的签名,编译器直接就能识别出来,不需要解析任何注释。 - 这套方案比扫Javadoc靠谱得多:一方面预生成的二进制签名加载校验速度极快,另一方面完全不会出现
@since错标、漏标的问题,还能准确识别不同版本中被删除的API——比如JDK9移除了sun.misc.BASE64Encoder类,-release 8时能找到这个类的签名,-release 9时就找不到,这类信息是只扫最新版JDK的@since标签根本拿不到的。
无Javadoc依赖的映射构建方式
如果你不想解析Javadoc的@since标签,完全可以直接复用ct.sym这套官方数据源:
- 直接解压读取各版本JDK自带的
ct.sym文件,遍历每个版本目录下的精简class文件,提取所有类、方法、字段的签名,就能直接得到每个API的首次出现版本、以及后续被移除的版本,准确率比扫@since高很多。 - 也可以直接调用JDK内置的jdeps模块API,批量校验指定API签名在不同Java版本下是否存在,不需要自己解析二进制格式。
内容的提问来源于stack exchange,提问作者Rostislav Krasny
相关产品推荐
相关产品推荐

