IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> 【IDEA插件开发】Quick Fix 快速修复插件开发 -> 正文阅读

[开发工具]【IDEA插件开发】Quick Fix 快速修复插件开发


前言

以下代码为开发idea quick fix功能插件演示代码,该代码实现的功能是:对于标注有SpingMVC中的 GetMappingPostMappingPatchMappingPutMappingDeleteMappingRequestMapping等注解等方法,若没有同时标注LevenApi注解,则在方法名上会出现警告,提示开发者加上LevenApi注解,此时使用quick fix的功能即可在方法上生成LevenApi注解。


一、Quick Fix是什么?

quick fix就是快速修复的意思,在idea编辑代码的时候,当我们输入一些违法或者是不安全(或是不推荐)的代码时,idea会自动帮我们检测出来,并使用红色或黄色波浪线提示我们修改代码。对于有些非法或者是不推荐的代码,idea能够推测出正确或者是被推荐的代码时,就会给我们提供一个快速修复的功能,这个功能就是quick fix。
而前面的检测行为则是由Annotator功能完成的,因此quick fix通常是跟着Annotator出现的,而有Annotator却是不一定有quick fix(就是没有推荐修改的情况)。


常见的quick fix场景-导入类
以上图片演示就是常见的quick fix场景——导入类。红色方块就是Annotator,提示“无法解析BigDecimal”;橙色框则是quick fix,通过点击Import class或者使用快捷键(Windows是alt + enter,Mac是option + enter)快速导入BigDecimal类。


二、开发quick fix 通常包含两部分

1. Annotator

筛选出需要quick fix的代码段:校验标注有SpringMVC mapping相关注解的方法是否同时标注有@LevenApi注解,如果没有则在这个方法名上添加Annotator,提示需要加上@LevenApi注解

package run.leven.fix;

import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Create By  leven [2021/12/21 9:34 下午]
 */
public class LevenApiAnnotator implements Annotator {
    
    private static final Set<String> MAPPING_NAME_SET;
    static {
        MAPPING_NAME_SET = new HashSet<>(
                Arrays.asList(
                        FixAnnotationEnum.PatchMapping.getQualifiedName(),
                        FixAnnotationEnum.PutMapping.getQualifiedName(),
                        FixAnnotationEnum.PostMapping.getQualifiedName(),
                        FixAnnotationEnum.GetMapping.getQualifiedName(),
                        FixAnnotationEnum.RequestMapping.getQualifiedName(),
                        FixAnnotationEnum.DeleteMapping.getQualifiedName()
                )
        );
    }

    @Override
    public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
        final Project project = element.getProject();
        // 项目或者引入的依赖包含LevenApi时才处理
        if (JavaPsiFacade.getInstance(project).findClass(FixAnnotationEnum.LevenApi.getQualifiedName(), GlobalSearchScope.allScope(project)) == null){
            return;
        }
        // 仅对Java方法处理
        if (!(element instanceof PsiMethod)){
            return;
        }
        // 仅对Java文件处理
        if (!(element.getContainingFile() instanceof PsiJavaFile)){
            return;
        }

        final PsiMethod psiMethod = (PsiMethod) element;

        final PsiAnnotation[] methodAnnotations = psiMethod.getAnnotations();
        PsiAnnotation mappingAnnotation = null;
        PsiAnnotation levenApiAnnotation = null;
        
        for (PsiAnnotation methodAnnotation : methodAnnotations) {
            if (MAPPING_NAME_SET.contains(methodAnnotation.getQualifiedName())){
                mappingAnnotation = methodAnnotation;
            }else if (FixAnnotationEnum.LevenApi.getQualifiedName().equals(methodAnnotation.getQualifiedName())
                    && psiMethod.getNameIdentifier() != null){
                levenApiAnnotation = methodAnnotation;
            }
        }
        // 方法上标注了spring mvc相关的mapping注解时,如果同时不存在@LevenApi注解,则quick fix生效
        if (mappingAnnotation != null && levenApiAnnotation == null && psiMethod.getNameIdentifier() != null){
            holder.newAnnotation(HighlightSeverity.WARNING, "添加@LevenApi注解")
                    .range(psiMethod.getNameIdentifier())
                    .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL)
                    .withFix(new LevenApiQuickFix(psiMethod))
                    .create();
        }
    }
}


2.quick fix

quick fix处理:在方法上创建@LevenApi注解

package run.leven.fix;

import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
import com.intellij.codeInspection.util.IntentionFamilyName;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;

/**
 * Create By  leven [2021/12/21 10:30 下午]
 */
public class LevenApiQuickFix extends BaseIntentionAction {
    private final PsiMethod psiMethod;

    public LevenApiQuickFix(PsiMethod psiMethod) {
        this.psiMethod = psiMethod;
    }

    @Override
    public @IntentionName @NotNull String getText() {
        return "Create @LevenApi";
    }

    @Override
    public @NotNull @IntentionFamilyName String getFamilyName() {
        return "Create @LevenApi";
    }

    @Override
    public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile psiFile) {
        return true;
    }

    @Override
    public void invoke(@NotNull Project project, Editor editor, PsiFile psiFile) throws IncorrectOperationException {
        // GlobalSearchScope.projectScope(project) 为allScope
        final PsiClass levenApiClass = JavaPsiFacade.getInstance(project).findClass(FixAnnotationEnum.LevenApi.getQualifiedName(), GlobalSearchScope.projectScope(project));
        if (levenApiClass != null){
            ApplicationManager.getApplication().invokeLater(() -> WriteCommandAction.runWriteCommandAction(project, () ->{
                final PsiClass containingClass = psiMethod.getContainingClass();
                if (containingClass == null){
                    return;
                }
                final PsiImportList importList = ((PsiJavaFile) containingClass.getContainingFile()).getImportList();
                if (importList == null){
                    return;
                }
                importLevenApiClass(project, levenApiClass, importList);

                psiMethod.getModifierList().addAnnotation("LevenApi(name = \"" + psiMethod.getName() + "\")");
            }));
        }

    }

    private void importLevenApiClass(@NotNull Project project, PsiClass levenApiClass, PsiImportList importList) {
        boolean notExistLevenApiImportStatement = true;
        for (PsiImportStatement importStatement : importList.getImportStatements()) {
            if (FixAnnotationEnum.LevenApi.getQualifiedName().equals(importStatement.getQualifiedName())){
                notExistLevenApiImportStatement = false;
            }
        }
        if (notExistLevenApiImportStatement){
            final PsiImportStatement levenApiImportStatement = JavaPsiFacade.getElementFactory(project).createImportStatement(levenApiClass);
            importList.add(levenApiImportStatement);
        }
    }
}

3. FixAnnotationEnum

package run.leven.fix;

/**
 * Create By  leven [2021/12/21 9:37 下午]
 */
public enum FixAnnotationEnum {
    GetMapping("GetMapping", "org.springframework.web.bind.annotation.GetMapping"),
    PostMapping("PostMapping", "org.springframework.web.bind.annotation.PostMapping"),
    PutMapping("PutMapping", "org.springframework.web.bind.annotation.PutMapping"),
    PatchMapping("PatchMapping", "org.springframework.web.bind.annotation.PatchMapping"),
    RequestMapping("RequestMapping", "org.springframework.web.bind.annotation.RequestMapping"),
    DeleteMapping("DeleteMapping", "org.springframework.web.bind.annotation.DeleteMapping"),

    LevenApi("LevenApi", "run.leven.fix.LevenApi");

    FixAnnotationEnum(String shortName, String qualifiedName) {
        this.shortName = shortName;
        this.qualifiedName = qualifiedName;
    }

    private String shortName;
    private String qualifiedName;

    public String getShortName() {
        return shortName;
    }

    public String getQualifiedName() {
        return qualifiedName;
    }
}


总结

提示:这里对文章进行总结:

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2021-12-23 15:56:13  更:2021-12-23 15:58:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 14:48:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码