在IntelliJ IDEA插件开发中,需通过PsiModifierListOwner获取PsiModifierList再调用getAnnotations()获取PsiAnnotation数组,利用getQualifiedName()获取全限定名,getParameterList().getAttributes()读取属性值,并注意线程安全与空指针防护。

在 IntelliJ IDEA 插件开发中,通过 PsiElement 读取 Java 文件中的注解(@Annotation)节点,核心是利用 PSI(Program Structure Interface)解析 Java 源码结构,定位到 PsiAnnotation 类型的元素。关键不在于“找注解字符串”,而在于准确遍历和筛选 PSI 树中符合语义的注解节点。
定位注解所在的 PSI 上下文
Java 中的注解可出现在多种位置:类、方法、字段、参数、局部变量、类型使用等。不同位置对应不同的父节点类型(如 PsiClass、PsiMethod、PsiField、PsiParameter、PsiTypeElement 等)。需先获取目标元素,再从中提取注解:
- 若处理当前编辑的文件,可用
psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument())获取PsiJavaFile - 若已知光标位置,调用
file.findElementAt(editor.getCaretModel().getOffset())得到最近的PsiElement,再向上查找最近的声明节点(如getParent() instanceof PsiModifierListOwner) -
PsiModifierListOwner是关键接口 —— 所有可带修饰符(包括注解)的元素(类、方法、字段等)都实现它
从 ModifierList 提取 PsiAnnotation
每个 PsiModifierListOwner 都有 getModifierList() 方法,返回 PsiModifierList;该列表包含所有修饰符(public、static)和注解节点。注解以 PsiAnnotation 形式存在:
- 调用
owner.getModifierList()?.getAnnotations()直接获取PsiAnnotation[] - 或遍历
modifierList.getChildren(),筛选出instanceof PsiAnnotation的元素 - 注意:
PsiAnnotation是 PSI 节点,不是运行时java.lang.annotation.Annotation,不可直接调用.annotationType()
读取注解名称与属性值
拿到 PsiAnnotation 后,常用信息如下:
立即学习“Java免费学习笔记(深入)”;
-
全限定名:用
annotation.getQualifiedName()(如"org.junit.Test"),若为简写(如@Test),需结合导入语句解析,推荐用annotation.getQualifiedName()(PSI 已解析好) -
简单名:
annotation.getName()(如"Test") -
属性值:调用
annotation.getParameterList().getAttributes()获取PsiNameValuePair[];每个PsiNameValuePair有getName()(键)和getValue()(值节点,可能是PsiLiteralExpression、PsiReferenceExpression或PsiArrayInitializerMemberValue等) - 例如读取
@RequestMapping(value = "/api", method = RequestMethod.GET)中的value字符串:检查pair.getName().equals("value"),再对pair.getValue()调用computeConstantValue()(若为字面量)或进一步解析
实用技巧与注意事项
实际开发中容易忽略的细节:
- 确保 PSI 树是最新的:在非 UI 线程操作前,用
ApplicationManager.getApplication().runReadAction()包裹读取逻辑 - 避免 NPE:
getModifierList()可能返回null(如匿名内部类的字段可能无显式修饰符列表) - 注解可能被继承或重复(
@Repeatable):getAnnotations()返回全部直接声明的注解,重复注解会作为独立节点出现 - 若需匹配特定注解(如只找
@Override),建议用AnnotationUtil.isAnnotated(..., "java.lang.Override", 0)(更健壮,支持继承和 meta-annotation)


















