java:通过javadoc API读取java源码中的注释信息(comment)

如何从java源码中读取注释信息?(注意不是指通过反射读取annotation类,是comment,就是程序员在源码中加的注释)
比如:

	/**
	 * 使用当前类的class loader加载工具对象
	 * @param classname
	 * @return
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */

大概很少会有人需要用到这个,不过最近的项目中需要对自动生成的代码中加入原始代码的注释,就需要从原始代码中获取注释。所以需要在程序实现读取源码中的注释信息,网上找了很多文章都想通过分析源码文件(正则表达式)来把注释提取出来,差点被这些文章带到坑里,休息的时候突然想如果javadoc有API可以调用,应该就能通过javadoc来获取完整的注释,而不用自己费力去搞。
google一查,果然javadoc有API的,就在$JAVA_HOME/lib/tools.jar中,官网也提供了完整的文档告诉你如何定制自己的javadoc输出。最关键的一点就是提供一个Doclet 类,利用-doclet参数去替换掉javadoc默认的Doclet,然后你的Doclet类就能获得一个包含完整丰富的结构化信息的注释对象RootDoc.然后你想怎么玩就随你啦。

关于如何在maven中将$JAVA_HOME/lib/tools.jar添加到dependency,参见 参考资料2

package gu.doc;

import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.RootDoc;

public class JavaDocReader {
	private static RootDoc root;
	// 一个简单Doclet,收到 RootDoc对象保存起来供后续使用
	// 参见参考资料6
	public static  class Doclet {
		
		public Doclet() {
		}
	    public static boolean start(RootDoc root) {
	    	JavaDocReader.root = root;
	        return true;
	    }
	}
	// 显示DocRoot中的基本信息
	public static void show(){
        ClassDoc[] classes = root.classes();
        for (int i = 0; i < classes.length; ++i) {
            System.out.println(classes[i]);
            System.out.println(classes[i].commentText());
            for(MethodDoc method:classes[i].methods()){
            	System.out.printf("\t%s\n", method.commentText());
            }
        }
	}
	public static RootDoc getRoot() {
		return root;
	}
	public JavaDocReader() {
		
	}
	public static void main(final String ... args) throws Exception{
		// 调用com.sun.tools.javadoc.Main执行javadoc,参见 参考资料3
		// javadoc的调用参数,参见 参考资料1
		// -doclet 指定自己的docLet类名
		// -classpath 参数指定 源码文件及依赖库的class位置,不提供也可以执行,但无法获取到完整的注释信息(比如annotation)
		// -encoding 指定源码文件的编码格式
		com.sun.tools.javadoc.Main.execute(new String[] {"-doclet", 
				Doclet.class.getName(), 
// 因为自定义的Doclet类并不在外部jar中,就在当前类中,所以这里不需要指定-docletpath 参数,
//				"-docletpath", 
//				Doclet.class.getResource("/").getPath(),
				"-encoding","utf-8""-classpath",
				"D:/j/facelog/facelog-main/target/classes;D:/j/facelog/db/target/classes;D:/j/facelog/db/sql2java/lib/swift-annotations-0.14.2.jar",
// 获取单个代码文件FaceLogDefinition.java的javadoc
				"J:/facelog/facelog-main/src/main/java/net/gdface/facelog/FaceLogDefinition.java"});
		show();
	}
}

完整代码参见码云GIT仓库 https://gitee.com/l0km/javadocreader.git

参考资料

1:《javadoc OPTIONS》
2:《JDK tools.jar as maven dependency》
3:《Running the Standard Doclet Programmatically》
4:《Doclet Overview》
5:《stackoverflow:Running the Standard Doclet Programmatically》
6:《A Simple Example Doclet》

<think>我们被要求使用Java进行代码解析或处理相关解析任务。根据用户提供的引用,特别是引用[1]提到了QDox,这是一个Java解析器,可以解析Java源代码并提取类、方法、字段等信息。此外,引用[2]提到Java代码解析作为初学者的编程入门指南,引用[3]提到Java处理延迟任务,引用[4]提到使用Java解析Excel。但用户的问题集中在代码解析上,因此我们将重点放在QDox上。 ### 使用QDox解析Java代码 QDox是一个轻量级的库,用于解析Java源代码并生成一个对象模型,该模型表示被解析的代码的结构。我们可以使用它来提取类、方法、字段、注释信息。 #### 步骤1:添加QDox依赖 首先,我们需要在项目中添加QDox的依赖。如果使用Maven,可以在pom.xml中添加: ```xml <dependency> <groupId>com.thoughtworks.qdox</groupId> <artifactId>qdox</artifactId> <version>2.0.3</version> <!-- 请检查最新版本 --> </dependency> ``` #### 步骤2:创建QDox解析器 然后,我们可以使用QDox的`JavaDocBuilder`来解析Java源文件。 ```java import com.thoughtworks.qdox.JavaDocBuilder; import com.thoughtworks.qdox.model.JavaClass; import com.thoughtworks.qdox.model.JavaMethod; import com.thoughtworks.qdox.model.JavaSource; import java.io.File; import java.io.FileReader; import java.util.List; public class JavaCodeParser { public static void main(String[] args) throws Exception { // 创建一个JavaDocBuilder对象 JavaDocBuilder builder = new JavaDocBuilder(); // 添加源文件(可以是文件、目录或输入流) builder.addSource(new FileReader(new File("path/to/YourClass.java"))); // 获取解析后的JavaSource对象 JavaSource source = builder.getSources()[0]; // 获取源文件中的所有类 List<JavaClass> classes = source.getClasses(); for (JavaClass cls : classes) { System.out.println("类名: " + cls.getFullyQualifiedName()); // 获取类的方法 List<JavaMethod> methods = cls.getMethods(); for (JavaMethod method : methods) { System.out.println(" 方法名: " + method.getName()); System.out.println(" 返回类型: " + method.getReturnType().getValue()); System.out.println(" 参数: "); for (int i = 0; i < method.getParameters().size(); i++) { System.out.println(" " + method.getParameter(i).getType() + " " + method.getParameter(i).getName()); } // 获取方法的注释 String comment = method.getComment(); if (comment != null) { System.out.println(" 注释: " + comment); } } } } } ``` #### 步骤3:运行解析器 将上述代码中的`path/to/YourClass.java`替换为你要解析的Java源文件路径,运行程序即可看到解析结果。 ### 其他Java解析任务 除了使用QDox解析Java源代码,我们还可以处理其他解析任务: 1. **解析Excel文件**(如引用[4]所述) - 使用Apache POI库来解析Excel文件(.xls和.xlsx格式)。 - 示例代码可参考引用[4]中的描述。 2. **处理延迟任务**(如引用[3]所述) - 使用`java.util.Timer`、`ScheduledExecutorService`或第三方库(如Quartz)来处理延迟任务。 - 注意引用[3]提到的任务丢失问题,可以考虑使用消息队列(MQ)或Redis来实现持久化。 ### 总结 - 对于Java代码解析,QDox是一个强大的工具,可以提取类、方法、字段等详细信息- 对于其他解析任务(如Excel解析),可以使用Apache POI等库。 - 处理延迟任务时,需要考虑任务的持久化,避免因程序崩溃导致任务丢失。 ### 相关问题 1. QDox能否解析Java 8及更高版本的语法(如lambda表达式)? 2. 除了QDox,还有哪些Java代码解析库? 3. 如何解析Java字节码(如使用ASM库)? 4. 使用Apache POI解析Excel时如何处理大数据量? 5. 在分布式系统中如何保证延迟任务的可靠执行? 希望这些信息能帮助你进行Java相关的解析任务。</think>### 如何使用 Java 进行代码解析及处理解析任务 #### 一、核心解析工具与场景 1. **QDox:Java 源码解析利器** - **功能**:将 Java 源码解析为结构化对象模型,提取类/接口定义、方法签名、参数名、注解、注释等元素[^1] - **典型应用**: ```java JavaDocBuilder builder = new JavaDocBuilder(); builder.addSource(new FileReader("UserService.java")); JavaClass javaClass = builder.getClassByName("com.example.UserService"); // 获取方法信息 for (JavaMethod method : javaClass.getMethods()) { System.out.println("方法名: " + method.getName()); System.out.println("返回值: " + method.getReturnType().getValue()); System.out.println("参数: " + method.getParameters()); System.out.println("注解: " + method.getAnnotations()); } ``` - **优势**:保留参数原名(编译后通常丢失),支持 Javadoc 标签解析[^1] 2. **ASM:字节码级解析** - **场景**:需修改或分析已编译的 `.class` 文件 - **示例**(统计方法调用): ```java ClassReader reader = new ClassReader("UserService.class"); ClassVisitor cv = new ClassVisitor(Opcodes.ASM9) { @Override public MethodVisitor visitMethod(...) { return new MethodVisitor(Opcodes.ASM9) { @Override public void visitMethodInsn(...) { System.out.println("调用方法: " + owner + "." + name); } }; } }; reader.accept(cv, 0); ``` #### 二、特定场景解析方案 1. **Excel 解析(Apache POI)** - **流程**: ```java // 读取 .xlsx 文件 Workbook workbook = new XSSFWorkbook(new File("data.xlsx")); Sheet sheet = workbook.getSheetAt(0); for (Row row : sheet) { for (Cell cell : row) { String value = switch (cell.getCellType()) { case STRING -> cell.getStringCellValue(); case NUMERIC -> String.valueOf(cell.getNumericCellValue()); default -> ""; }; System.out.print(value + "\t"); } System.out.println(); } ``` - **注意**:区分 HSSF(.xls)和 XSSF(.xlsx)实现[^4] 2. **延迟任务解析** - **方案选择**: | 方案 | 优点 | 缺点 | |---|---|---| | `ScheduledExecutorService` | 原生支持 | 宕机丢失任务[^3] | | Redis 有序集合 | 持久化 | 需额外维护 | | RabbitMQ 延迟队列 | 可靠 | 架构复杂 | - **Java 原生实现**: ```java ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.schedule(() -> System.out.println("任务执行"), 5, TimeUnit.MINUTES); ``` #### 三、自定义解析器开发指南 1. **词法/语法分析基础** - **工具组合**: ```mermaid graph LR A[源代码] --> B(ANTLR 词法分析) B --> C[Token流] C --> D(JavaCC 语法分析) D --> E[抽象语法树 AST] E --> F[自定义处理逻辑] ``` 2. **关键步骤**: - **步骤1**:定义语法规则(BNF 格式) - **步骤2**:生成解析器骨架(ANTLR/JavaCC) - **步骤3**:实现 `Visitor` 遍历 AST - **示例**(简单表达式计算): ```java public class EvalVisitor extends ExprBaseVisitor<Integer> { @Override public Integer visitAddSub(ExprParser.AddSubContext ctx) { int left = visit(ctx.expr(0)); int right = visit(ctx.expr(1)); return ctx.op.getType() == ExprParser.ADD ? left + right : left - right; } } ``` #### 四、性能优化技巧 1. **大型文件处理**: - 使用 SAX 模式解析 XML/Excel(流式读取- 分块处理:`Files.lines().parallel()` 并行流 2. **内存管理**: - 及时关闭资源:`try-with-resources` 自动管理 - 避免全量加载:增量解析 + 回调机制 > 提示:复杂场景优先考虑成熟工具(如 QDox 用于源码分析[^1],POI 用于 Excel[^4]),底层操作选择 ASM 或 ANTLR。 --- ### 相关问题 1. QDox 能否解析 Lambda 表达式和方法引用? 2. 如何用 ASM 实现字节码插桩监控? 3. 解析 GB 级 Excel 文件有哪些优化方案? 4. 分布式环境下如何保证延迟任务的精确执行? 5. ANTLR 与 JavaCC 在 Java 解析场景下的性能对比?
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值