如何在IntelliJ IDEA中编写自定义检查规则检测重复@Link注解值
IDEA自定义检查工具实现@Link注解value全局重复检测
核心实现步骤
1. 项目级全局缓存实现
因为需要跨Java文件检测重复,首先要实现项目级的全局缓存,存储所有@Link注解的value值与对应方法PSI元素的映射,并且要监听文件变动事件,动态更新缓存内容,避免缓存失效。
// 项目级缓存示例 public class LinkValueCache implements ProjectComponent { private final Project project; private final Map<String, List<PsiMethod>> valueToMethods = new ConcurrentHashMap<>(); public static LinkValueCache getInstance(Project project) { return project.getComponent(LinkValueCache.class); } public LinkValueCache(Project project) { this.project = project; } // 新增value与方法的映射 public void addValue(String value, PsiMethod method) { valueToMethods.computeIfAbsent(value, k -> new ArrayList<>()).add(method); } // 查询value对应的所有方法 public List<PsiMethod> getMethodsByValue(String value) { return valueToMethods.getOrDefault(value, Collections.emptyList()); } // 文件变更时清理对应文件的缓存 public void removeFileCache(VirtualFile file) { // 遍历缓存删除该文件下所有方法的映射 valueToMethods.values().forEach(list -> list.removeIf(method -> method.getContainingFile().getVirtualFile().equals(file) )); valueToMethods.entrySet().removeIf(entry -> entry.getValue().isEmpty()); } }
2. 自定义检查类实现
继承IDEA提供的AbstractBaseJavaLocalInspectionTool类,实现对方法上@Link注解的扫描逻辑:
public class LinkValueDuplicateInspection extends AbstractBaseJavaLocalInspectionTool { @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { return new JavaElementVisitor() { @Override public void visitMethod(@NotNull PsiMethod method) { super.visitMethod(method); // 读取方法上的@Link注解,替换为你实际的@Link注解全类名 PsiAnnotation linkAnno = method.getAnnotation("com.xxx.Link"); if (linkAnno == null) return; // 读取value属性值 PsiAnnotationMemberValue valueAttr = linkAnno.findAttributeValue("value"); if (!(valueAttr instanceof PsiLiteralExpression valueLiteral)) return; Object valueObj = valueLiteral.getValue(); if (valueObj == null) return; String value = valueObj.toString(); // 从全局缓存判断是否重复 List<PsiMethod> sameValueMethods = LinkValueCache.getInstance(method.getProject()).getMethodsByValue(value); if (sameValueMethods.size() >= 2) { holder.registerProblem( valueAttr, "@Link注解value值全局不唯一,存在重复", ProblemHighlightType.ERROR ); } } }; } }
3. 注册检查与监听
在插件的plugin.xml配置文件中注册自定义检查和文件变动监听器:
<!-- 注册自定义检查 --> <localInspection language="JAVA" shortName="LinkValueDuplicate" displayName="@Link注解value重复检测" groupName="注解校验" groupPath="Java" enabledByDefault="true" level="ERROR" implementationClass="com.xxx.LinkValueDuplicateInspection"/> <!-- 注册文件变动监听器,动态更新缓存 --> <applicationListener listener="com.intellij.openapi.vfs.VirtualFileListener" implementationClass="com.xxx.LinkValueCacheUpdateListener"/>
最终效果
对于示例代码,两个value = "123456"的@Link注解都会被高亮标注错误:
// 此处高亮提示重复 @Link(type = "manual", value = "123456") void someTest1(){ } @Link(type = "manual", value = "654321") void someTest2(){ } // 此处同样高亮提示重复 @Link(type = "manual", value = "123456") void someTest3(){ }
优化建议
- 如果项目体量较大,可改用IDEA自定义索引功能实现全局检索,降低全量扫描的性能损耗
- 可新增快速修复功能,自动生成不重复的value值填充到注解中
内容的提问来源于stack exchange,提问作者pro100filimon
相关产品推荐
相关产品推荐

