从重复劳动到智能助手:我为什么要开发一个 JavaDoc 插件

random-pic-api

现有方案的痛点

写 JavaDoc 是一件所有人都觉得该做、但没人愿意做的事。CI/CD 检查会因为缺少文档卡你,Code Review 会因为文档质量不行打回,但真要写的时候,你发现这完全是重复劳动——方法签名已经告诉你参数和返回值,方法体就在眼前,你只是用自然语言复述一遍代码本身就能表达的信息。

市面上的自动生成工具要么只给你空壳模板(@param userId the user id),要么需要你切换到命令行或者外部工具,打断开发流程。而直接用 ChatGPT 或者 Cursor,虽然能生成不错的文档,但每次都要手动复制代码、切换窗口、等结果再贴回来,而且通用 AI 工具加载了大量 Agent、MCP、Skill 上下文,你只是想给一个方法加个文档,也要消耗大量 token。

这个问题的核心其实很简单:输入是光标所在的代码元素,输出是格式化的 JavaDoc 注释,一轮问答就够了。用最轻量的 AI 调用嵌入 IDE,不离开编辑器,不多消耗一个 token,这就是这个插件要做的事。

功能一览

功能入口说明
生成 JavaDocAlt+Enter / 快捷键 / 右键菜单为光标所在的类、方法、字段生成文档
修复已有注释FIX 模式保留原注释发给 AI,只修正错误或补充缺失部分
CodeVision 行内提示编辑器行内缺少文档的元素显示”Generate Javadoc”提示,点击即生成
保存时自动生成文件保存触发保存时自动为改动范围内的元素补充文档,不影响保存速度
Git 提交时检查提交页面提交前扫描缺失文档,提示批量补全
删除 JavadocIntention Action一键删除元素的 Javadoc 注释

支持 Java 和 Kotlin,通过 IntelliAI Engine 统一调用 OpenAI、Anthropic、Ollama 等多种 AI 后端。

和其他方案比,好在哪

vs 空壳模板工具:不只是填充模板。插件通过 PSI 分析代码结构和业务语义,AI 看到的是带上下文的代码,生成的文档有实际意义,不是 @param userId the user id 这种废话。

vs 通用 AI 工具(ChatGPT、Cursor 等):

  • Token 消耗低一个数量级。插件会对代码做压缩预处理,不是把整个文件原样扔给 AI
  • 无缝集成在 IDE 里,光标定位 → Alt+Enter → 出结果,不需要切换窗口
  • 支持多服务商并行生成,批量处理几十个文件不会卡住
  • 模板和标签完全可定制,生成风格和格式可控

vs 其他 AI JavaDoc 插件

  • **不是”生成就完了”**:AI 返回的文本会经过多层后处理——过滤多余的 Markdown 代码块、根据方法签名清理 AI 错误添加的 @param/@throws 标签、中英文之间自动加空格、中文标点转英文标点、单行注释自动压缩
  • 不只是手动触发:CodeVision 行内提示、保存时自动生成、Git 提交时检查,覆盖了开发流程中的每一个文档需求时机
  • **不只是”覆盖重写”**:FIX 模式下保留原注释让 AI 只修正错误,不会丢失人工编写的有价值内容
  • PSI 语义分析:不是把代码原样扔给 AI,而是分析架构位置、职责、依赖关系,注入结构化上下文

核心:怎么让 AI 理解你的代码并生成准确的文档

用 AI 生成 JavaDoc 看起来简单,但要做好很难。直接把 element.getText() 扔给 AI 不行,原因有三:

  • 代码太长:一个复杂类可能几百上千行,全部发过去 token 浪费严重
  • 缺少上下文:单个方法的代码是孤立的,AI 不知道这个方法属于哪个类、被谁调用、在架构中扮演什么角色
  • 噪音干扰:注释、空行、格式化代码占据了大量篇幅,对生成文档没有帮助

插件围绕这三个问题做了多层优化。

代码压缩

对发给 AI 的代码做预处理,去掉对文档生成无用的内容:

1
2
3
4
5
6
7
// AiCodePreprocessor.java
public static String preprocess(String code, boolean removeComments) {
// 1. 删除 Javadoc、块注释、单行注释(FIX 模式下保留注释,让 AI 看到原文修正)
// 2. 多空格合并为单空格,删除符号两侧空格
// 3. 删除空行
// 4. 缩进压缩到最小层级(每层 1 个空格)
}

实际效果:一个 200 行的类,压缩后可能只有 60-80 行,token 消耗减少 60% 以上。而且因为去掉了噪音,AI 生成的质量反而更高。

类级上下文注入

生成方法或字段的文档时,AI 需要知道这个元素在类中的位置。插件会在方法/字段代码前注入压缩后的类代码片段作为上下文:

1
2
3
4
// TaskCollector.java - buildClassCodeContext()
String reformatCode = AiCodePreprocessor.preprocess(
optimizeClassCode(psiClass.getText()));
String snippet = limitLines(reformatCode); // 限制最大行数

AI 看到的 prompt 结构是这样的:

1
2
3
4
5
6
7
### 类级上下文(仅供参考,不直接生成注释)
<CLASS_CONTEXT_START>
...压缩后的类代码...
<CLASS_CONTEXT_END>

### 最终需要生成注释的代码片段
...当前方法/字段代码...

这样 AI 既能理解方法所属的类和上下文,又不会把类级代码也生成注释。

PSI 语义分析

这是插件和”直接把代码扔给 AI”最本质的区别。插件通过 IntelliJ PSI 接口分析类的语义信息,注入给 AI 的不是裸代码,而是带有语义标注的结构化数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// ClassSemanticAnalyzer.java
public ClassSemanticModel analyze(PsiClass psiClass, Project project) {
// 1. 架构位置:通过 Spring 注解和包名判断
// @RestController → 控制器
// @Service → 服务层
// 包名含 .repository → 仓库层

// 2. 职责推断:从类名提取领域 + 方法名提取动词
// UserService → "user 创建和管理逻辑"
// 方法名含 query/get/find → "查询和检索逻辑"

// 3. 暴露范围:检查是否被其他模块引用
// Controller 一律是"作为公共API暴露"
// 被跨模块引用 → "作为公共API暴露"
// 否则 → "仅内部使用"

// 4. 使用场景:分析调用者类型
// 被 Controller 引用 → "REST控制器"
// 被 @EventListener 引用 → "事件监听器"

// 5. 依赖关系:分析字段注入和方法调用
// 注入 *Repository → "数据库访问"
// 注入 *Client → "远程服务"
// 方法中调用 publish/send → "发布领域事件"
// 方法中调用 save/persist → "执行数据库操作"

// 6. 设计意图:推断类的设计目的
// 无基础设施依赖 → "避免基础设施关注"
// 含 create/validate/calculate → "封装业务规则"
}

这些语义信息会被组装成结构化的 prompt 注入给 AI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
### 语义上下文
类的角色摘要:
- 架构层级:服务层
- 主要职责:user 创建和管理逻辑
- 暴露范围:作为公共API暴露

使用场景:
- 主要由 REST控制器、事件监听器 调用

依赖关系:
- UserRepository (数据库访问)
- EventPublisher (事件发布)

设计意图:
- 封装业务规则

AI 拿到这些信息后,生成的 JavaDoc 不会再是泛泛的描述,而是能准确反映类在架构中的位置、职责和设计意图。

不同元素类型的差异化处理

插件不会用同一个模板处理所有元素。根据元素类型(类、方法、字段、测试方法)使用不同的 prompt 模板,覆写模式也有区分:

1
2
3
4
5
6
7
8
9
10
// AIRequestComposer.java
String template = switch (task.getType()) {
case CLASS, INTERFACE, ENUM -> {
// 类模板:注入语义上下文 + 自定义标签(@author, @date, @version)
yield mergeContextAndCode(classTemplate, task.getContext(), task.getCode());
}
case FIELD -> fieldPromptTemplate;
case TEST_METHOD -> testPromptTemplate; // 测试方法用简化模板
default -> methodPromptTemplate;
};

修复已有注释(FIX 模式)

不只是”没有注释才生成”。当元素已有 Javadoc 时,插件提供两种覆写模式:

  • FIX:保留原注释发给 AI,用专门的修复提示词让 AI 只修正错误或补充缺失信息。不会丢失人工编写的有价值内容
  • REPLACE:删除原注释,让 AI 从头生成
1
2
3
4
5
6
7
8
9
10
11
// AIRequestComposer.java
if (settings.overrideExisting && settings.overrideMode == OverrideMode.FIX) {
PsiElement element = task.getElement();
if (PsiElementLocator.hasJavaDoc(element)) {
// 有注释 → 用修复提示词,AI 看到原文后只做修正
String template = resolveTemplate(settings.fixJavadocPromptTemplate, ...);
String codeWithContext = mergeContextAndCode(task.getContext(), task.getCode());
return String.format(template, codeWithContext);
}
// 没有注释 → 用正常的生成提示词
}

AI 响应后处理

AI 返回的文本不能直接插入代码。插件在插入前做了多层清洗:

过滤多余内容

AI 经常不听话——你说”只返回注释”,它偏要返回代码块或者把原始代码也带上:

1
2
3
4
5
6
7
8
9
10
11
12
// DocumentationInserterHelper.java

// 1. 过滤 Markdown 代码块(AI 有时会用 ```java 包裹返回内容)
javadoc = filterMarkdownCodeBlocks(javadoc);

// 2. 过滤注释之后的代码(AI 有时会把原始方法代码也返回)
javadoc = filterCodeAfterComment(javadoc);

// 3. 确保是合法的 Javadoc(必须以 /** 开头,*/ 结尾)
if (!javadoc.startsWith("/**") || !javadoc.endsWith("*/")) {
return "";
}

根据方法签名清理多余标签

AI 最常见的错误:给没有参数的方法加上 @param,给 void 方法加上 @return,给字段加上 @throws。插件会根据实际的 PSI 方法签名做校验:

1
2
3
4
5
6
7
8
9
10
11
// DocumentationInserterHelper.java - cleanParamAndThrowsTags()

// 字段:移除所有 @param、@throws、@return(字段不应该有这些标签)
if (element instanceof PsiField) {
// 删除所有参数/异常/返回值标签
}

// 方法:根据实际签名清理
if (!hasParams) 删除 @param 行; // 方法没有参数 → 删掉 AI 乱加的 @param
if (!hasThrows) 删除 @throws 行; // 方法没有声明异常 → 删掉 @throws
if (!hasReturnValue) 删除 @return 行; // void 方法 → 删掉 @return

这个校验是基于 PSI 的精确判断,不是字符串匹配。

中英文之间自动加空格

AI 生成的中文文档里,中英文混排时经常没有空格,读起来很不舒服。插件集成了 Pangu 排版工具,自动在中文和英文/数字之间插入空格:

1
2
3
4
5
// 处理前
"这是一个User类,包含100个方法,使用Java开发"

// 处理后
"这是一个 User 类,包含 100 个方法,使用 Java 开发"

这个处理是可配置的,在设置中可以开关。

中文标点转英文标点

同样的,AI 生成的文档里标点符号风格不统一。插件可以将中文标点()替换为英文标点(,.()),保持 Javadoc 标点风格一致。

1
2
3
4
5
6
// DocumentationInserterHelper.java - formatJavaDocContent()
javadoc = MessageFormatter.format(
javadoc,
settings.addSpaceBetweenChineseAndEnglish, // 中英文间距
settings.replaceChinesePunctuation // 标点规范化
);

两项处理都是可配置的,用户可以根据团队规范自由开关。

单行注释压缩

当 Javadoc 只有一行描述、没有 @param/@return 等标签时,插件会自动把三行格式压缩为单行:

1
2
3
4
5
6
7
// 压缩前(3行)
/**
* 用户服务类
*/

// 压缩后(1行)
/** 用户服务类 */

压缩条件:内容只有一行非空文本、不包含 Javadoc 标签、长度不超过 120 字符。超过限制的不会压缩,避免一行太长影响阅读。

IDE 深度集成

CodeVision 行内提示

在编辑器中,缺少 Javadoc 的类、方法、字段会显示类似”x usages”的行内提示,写着”Generate Javadoc”。点击即可生成,不需要移动光标、不需要按快捷键。

对于已有注释的元素,提示会变成”Override Javadoc”(如果启用了覆盖模式)。CodeVision 提示完全遵循用户配置——只显示你选择要生成的元素类型(类/方法/字段),只在你选择的语言(Java/Kotlin)上生效。

为了不影响编辑器性能,CodeVision 计算做了多项优化:

  • 快速检查在 UI 线程(precomputeOnUiThread)完成,只做文件系统类型检查
  • 慢操作(PSI 遍历、文件索引检查)放到后台线程的 ReadAction.nonBlocking
  • 串行处理,避免 parallelStream 导致 IDEA 死锁
  • 限制最大处理数量(50 个类、每个类 100 个方法/字段),防止大文件卡顿

保存时自动生成

开启后,每次保存文件时插件会自动检测改动范围内的方法和字段,只为它们补充 Javadoc。关键设计:

  • 只处理改动的元素:通过 DocumentListener 跟踪每次编辑的范围(RangeMarker),保存时只检查改动范围内的方法/字段,不是全文件扫描
  • 不阻塞保存:生成在后台异步执行,保存操作本身不会被延迟
  • 防重复触发:用 AtomicBoolean 确保同一时间只有一个生成流程在运行
  • 延迟 500ms 执行:避免与保存操作本身冲突
1
2
3
4
5
// GenerateOnSaveListener.java
// 1. DocumentListener 记录每次编辑的 RangeMarker
// 2. 保存时消费这些 RangeMarker,转为 TextRange
// 3. 只收集改动范围内的方法/字段任务
// 4. 延迟 500ms 后在后台线程执行生成

Git 提交时检查

在 Git 提交页面,插件会扫描所有待提交的 Java/Kotlin 文件,检测缺失 Javadoc 的类、方法、字段,生成汇总报告(比如”检测到 3 个类、12 个方法缺少 Javadoc”),提示用户是否一键补全。

这个功能不依赖配置,专门用于提交前的文档完整性检查。它会强制检查所有类型的元素(类、方法、字段),忽略用户的 generateForClass/generateForMethod/generateForField 设置,确保提交的代码不会缺少文档。

多服务商并行生成

批量处理文件时(比如整个项目补文档),插件支持多服务商并行执行。把任务分配给多个已配置的 AI 服务商,同一个文件内的任务按顺序处理,不同文件的任务并行处理:

1
2
3
4
5
// ParallelTaskExecutor.java
// 每个文件是一个队列,多个线程并发消费
// 同一文件的任务必须按顺序(避免插入位置冲突)
// 不同文件的任务可以完全并行
// 支持 429 限流自动切换、超时控制、重试机制

配置了多个 AI 服务商时,生成速度随服务商数量线性提升。还可以在设置中查看每个服务商的统计信息(响应速度、成功率、token 消耗),方便选择最优服务商。

配置项

设置面板支持:

  • AI 提供商:OpenAI、Anthropic、Ollama 等,可配置多个并设置优先级
  • 模板定制:类、方法、字段、测试方法各自的 prompt 模板,包括修复已有注释的专用模板
  • 系统提示词:调整 AI 的生成风格和语言偏好
  • JavaDoc 标签:自定义 @author、@date、@version 等标签的默认值
  • 代码压缩:启用/禁用代码预处理,控制压缩程度
  • 语义上下文:启用/禁用 PSI 语义分析
  • 类上下文行数:控制注入的类级上下文最大行数
  • 中英文间距:启用/禁用 Pangu 自动排版
  • 标点规范化:启用/禁用中文标点转英文标点
  • 单行注释压缩:启用/禁用单行 Javadoc 压缩为一行
  • CodeVision 提示:启用/禁用编辑器行内提示
  • 保存时生成:启用/禁用保存时自动生成
  • 语言支持:选择生成文档的语言(Java / Kotlin)
  • 性能模式:启用多服务商并行处理,查看各服务商统计

效率对比

场景手动插件提升
简单方法 JavaDoc3-5 分钟10-20 秒~15x
复杂方法 JavaDoc10-15 分钟30-60 秒~12x
类级别 JavaDoc20-30 分钟1-2 分钟~15x
批量处理 50 个文件2-3 小时10-15 分钟~12x
提交前文档检查人工逐文件检查一键扫描 + 批量补全-

相关文章:

  1. IntelliAI Engine - 统一接入 30+ AI 服务商的底层平台
  2. IntelliAI Terminal - 终端自然语言生成 Shell 命令
  3. IntelliAI Changelog - AI 一键生成 Changelog、日报、周报

相关链接