【idea】idea插件编写教程,博主原创idea插件已上架idea插件市场 欢迎下载

前言:经常使用Objects.equals(a,b)方法的同学 应该或多或少都会因为粗心而传错参, 例如日常开发中 我们使用Objects.equals去比较 status(入参),statusEnum(枚举), 很容易忘记statusEnum.getCode() 或 statusEnum.getVaule() ,再比如 我们比较一个订单code时 orderCode(入参),orderDTO(其它业务对象) 很容易忘记orderDTO.getCode() 因为Objects.equals()两个参数都是Object类型,idea默认不会提示告警, 如果经常使用该方法 你一定很清楚的明白我在说什么。

针对以上痛点,博主编写了一个idea插件: Equals Inspection , 插件代码本身很简单,极其轻量级。难得的是 在目前暂没发现有人做了这件事时,而博主想到了可以通过IDE告警方式去解决问题,并且实际行动了。此外,知道该用什么API本身是件不容易的事,而阅读代码时,已经处于一个上帝视角,则会显得非常简单。

下载一(推荐):
idea插件市场搜索: Equals Inspection 

在这里插入图片描述

下载二:
github :  https://github.com/qiuhuanhen/objects-equals-inspect/releases    


安装方式:1.idea内插件下载会自动安装  2. github下载直接将jar包拖进idea,重启idea

Q:为什么是IDE插件层面,而不是在java项目中重写一个工具类 针对类型判断呢?
A:
1.效率问题:java项目代码判断 说明要执行到该方法时才能校验,很多时候我们编写完,在测试环节被提了bug,我们自己断点执行一遍,才能发现传错了参,插件层面在我们编写时即可提醒,节省了大量时间.

2.设计问题: 很重要的一点,java项目层面的提示,要怎么提示?throw new RuntimeExection? 显然不太合理吧,例如在设计一些框架/通用代码时,类型就是可以不一致 难道抛一个异常阻止程序运行吗?插件尽管会提示报错,但它归根结底都只是一个样式,并不会阻止程序运行。

使用前后效果对比:

使用前没有告警
在这里插入图片描述

使用后示例:

在这里插入图片描述
vo.getStatus(Integer类型)与枚举比较时,能直接提示我们类型不一致
(正确写法是StatusEnum.AWAIT.getValue() 与枚举类型的值进行比较)
在这里插入图片描述

以下就以博主编写的插件为例 ,写一篇如何编写idea插件的教程

注:本文由csdn博主 孟秋与你 编写,如您在其它地方看到本文,很可能是被其它博主爬虫/复制过来的,文章可能会持续更新,强烈建议您搜索:孟秋与你csdn 找到原文查看

第一步:创建插件项目
tips:
1.需要jdk11
2.以idea2021.1版本为例,不同idea版本可能有所差异

new project ->IntelliJ Platform Plugin-> Project SDK (需要jdk11)

在这里插入图片描述

第二步:修改plugin.xml文件内容及创建java代码

其中plugin.xml的description节点,需要40个字符以上,否则插件上传时会报错。

编写插件的核心难点在于,我们不知道idea的api是什么,什么情况用什么api。
以下是可以参考的几点:

  1. idea官方文档 https://plugins.jetbrains.com/docs/intellij/welcome.html
  2. github idea 示例项目:https://github.com/JetBrains/intellij-sdk-code-samples
<idea-plugin>
  <id>csdn-mengqiuyuni</id>
  <name>Equals参数类型检查</name>
  <version>0.1.0</version>
  <vendor email="1005738053@qq.com" url="https://blog.csdn.net/qq_36268103"> </vendor>

  <description><![CDATA[
      <li>check java.lang.Objects equals method params type ,if not match,idea will show the error line</li><br>
      <li>could reduce Objects.equals(a,b) error params type by mistake</li><br>
      <li>notice:this plugin can only inspect your code,it's just reminder java developers,but don't impact code execution,and never change or fix your code.</li>
    ]]></description>

  <change-notes><![CDATA[
      <li>github:qiuhuanhen,project name :objects-equals-inspect</li><br>
      <li>beta version.csdn:孟秋与你</li><br>
      <li>the first beta version,welcome,update date:2024.01.09</li>
    ]]>
  </change-notes>

  <vendor>qiuhuanhen</vendor>

  <!-- please see https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html for description -->
  <idea-version since-build="173.0"/>

  <!-- please see https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html
       on how to target different products -->
  <depends>com.intellij.modules.platform</depends>
  <depends>com.intellij.java</depends>
  <depends>com.intellij.modules.java</depends>

  <extensions defaultExtensionNs="com.intellij">
    <localInspection
            language="JAVA"
            displayName="Title"
            groupPath="Java"
            groupBundle="messages.InspectionsBundle"
            groupKey="group.names.probable.bugs"
            enabledByDefault="true"
            level="ERROR"
            implementationClass="com.qiuhuanhen.ObjectsEqualsInspection"/><!--java类所在路径-->
  </extensions>

</idea-plugin>

package com.qiuhuanhen;

import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;


/**
 * @author qiuhuanhen
 */
public class ObjectsEqualsInspection extends LocalInspectionTool {

    @NotNull
    @Override
    public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
        return new MyVisitor(holder);
    }

    private static class MyVisitor extends JavaElementVisitor {
        private final ProblemsHolder holder;

        public MyVisitor(ProblemsHolder holder) {
            this.holder = holder;
        }

        @Override
        public void visitMethodCallExpression(PsiMethodCallExpression expression) {
            super.visitMethodCallExpression(expression);

            String methodName = expression.getMethodExpression().getReferenceName();

            if ("equals".equals(methodName)) {

                PsiExpressionList argumentList = expression.getArgumentList();
                PsiExpression[] expressions = argumentList.getExpressions();


                if (expressions.length == 2) {
                    PsiType arg1Type = expressions[0].getType();
                    PsiType arg2Type = expressions[1].getType();

                    // 都为空 不做提示  注:即使idea会提示 type不为空 ,为防止插件报NPE 还是有大量的非空判断
                    if (null == arg1Type && null == arg2Type) {
                        return;
                    }

                    // 其一为空 给出错误提示
                    if (null == arg1Type || null == arg2Type) {
                        holder.registerProblem(expression, "Objects.equals parameters are not of the same type.", ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                        return;
                    }
                    // 这是忽视某些通用类,框架 用于比较反射class类型的情况
                    if (arg1Type.getCanonicalText().contains("Class") && arg2Type.getCanonicalText().contains("Class")) {
                        return;
                    }

                    if (isByte(arg1Type) && isByte(arg2Type)) {
                        return;
                    }
                    if (isShort(arg1Type) && isShort(arg2Type)) {
                        return;
                    }
                    if (isInt(arg1Type) && isInt(arg2Type)) {
                        return;
                    }
                    if (isLong(arg1Type) && isLong(arg2Type)) {
                        return;
                    }
                    if (isFloat(arg1Type) && isFloat(arg2Type)) {
                        return;
                    }
                    if (isDouble(arg1Type) && isDouble(arg2Type)) {
                        return;
                    }
                    if (isChar(arg1Type) && isChar(arg2Type)) {
                        return;
                    }
                    if (isBoolean(arg1Type) && isBoolean(arg2Type)) {
                        return;
                    }


                    if (!arg1Type.equals(arg2Type)) {

                        holder.registerProblem(expression, "Objects.equals parameters are not of the same type.", ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                    }
                }
            }
        }

        private boolean isInt(PsiType type) {
            PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
            if (PsiType.INT.equals(unboxedType)) {
                // 是 int 类型
                return true;
            }

            return PsiType.INT.equals(type) || "java.lang.Integer".equals(type.getCanonicalText());
        }

        private boolean isLong(PsiType type) {
            PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
            if (PsiType.LONG.equals(unboxedType)) {
                // 是 long 类型
                return true;
            }

            return PsiType.LONG.equals(type) || "java.lang.Long".equals(type.getCanonicalText());
        }

        private boolean isDouble(PsiType type) {
            PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
            if (PsiType.DOUBLE.equals(unboxedType)) {
                return true;
            }

            return PsiType.DOUBLE.equals(type) || "java.lang.Double".equals(type.getCanonicalText());
        }

        private boolean isFloat(PsiType type) {
            PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
            if (PsiType.FLOAT.equals(unboxedType)) {
                return true;
            }

            return PsiType.FLOAT.equals(type) || "java.lang.Float".equals(type.getCanonicalText());
        }

        private boolean isBoolean(PsiType type) {
            PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
            if (PsiType.BOOLEAN.equals(unboxedType)) {
                return true;
            }

            return PsiType.BOOLEAN.equals(type) || "java.lang.Boolean".equals(type.getCanonicalText());
        }

        private boolean isByte(PsiType type) {
            PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
            if (PsiType.BYTE.equals(unboxedType)) {
                return true;
            }

            return PsiType.BYTE.equals(type) || "java.lang.Byte".equals(type.getCanonicalText());
        }

        private boolean isChar(PsiType type) {
            PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
            if (PsiType.CHAR.equals(unboxedType)) {
                return true;
            }

            return PsiType.CHAR.equals(type) || "java.lang.Char".equals(type.getCanonicalText());
        }

        private boolean isShort(PsiType type) {
            PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
            if (PsiType.SHORT.equals(unboxedType)) {
                return true;
            }

            return PsiType.SHORT.equals(type) || "java.lang.Short".equals(type.getCanonicalText());
        }

    }
}


第三步:打成jar包
在这里插入图片描述
没有main方法则不用选择main class
在这里插入图片描述
在这里插入图片描述

第四步:发布插件
在这里插入图片描述

发布插件没有什么难点,唯一值得注意的是description非常严格,必须要40个字符以上,且不能有非拉丁字符,博主在反复修改后发现不能有任何中文,最后把description里面的中文都改成了英文。

插件项目源码地址:https://github.com/qiuhuanhen/objects-equals-inspect

打开项目方式:
在github下载博主的项目,idea打开后 默认是常规项目,这时我们需要稍作处理
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后一步:
在这里插入图片描述

最后: 原创不易 ,欢迎各位在idea插件商店下载 Equals Inspection , 给github项目点上star 非常感谢各位

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/329530.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java可视化物联网智慧工地综合云平台源码 私有化部署

智慧工地平台围绕建筑施工人、物、事的安全管理为核心&#xff0c;对应研发了劳务实名制、视频监控、扬尘监测、起重机械安全监测、安全帽监测等功能一体化管理的解决方案。 智慧工地是聚焦工程施工现场&#xff0c;紧紧围绕人、机、料、法、环等关键要素&#xff0c;综合运用…

docker安装运行CloudBeaver并设置默认语言为中文

1、CloudBeaver CloudBeaver 是一个开源的 Web 数据库管理工具&#xff0c;它提供了一个基于浏览器的用户界面&#xff0c;允许用户管理和操作各种类型的数据库。CloudBeaver 支持多种数据库系统&#xff0c;包括但不限于 PostgreSQL、MySQL、SQLite、Oracle、SQL Server 以及…

RabbitMQ入门精讲

1. 什么是消息队列 消息指的是两个应用间传递的数据。数据的类型有很多种形式&#xff0c;可能只包含文本字符串&#xff0c;也可能包含嵌入对象。 “消息队列(Message Queue)”是在消息的传输过程中保存消息的容器。在消息队列中&#xff0c;通常有生产者和消费者两个角色。…

【Java基础_01】Java运行机制及运行过程

【Java基础_01】Java运行机制及运行过程 文章目录 【Java基础_01】Java运行机制及运行过程1.Java 运行机制及运行过程1.1 Java 核心机制-Java 虚拟机 [JVM java virtual machine] 1.2 JDK&#xff0c;JRE1.3 JVM,JDK和JRE1.4 环境变量path1.4.1 为什么要配置path1.4.2 配置环…

【一步一步学】ROS软路由设置代理IP教程

申明&#xff1a;本文仅针对国内L2TP/PPTP&#xff0c;适用于国内的游戏加速或学术研究&#xff0c;禁止一切利用该技术的翻墙行为。 今天和大家分享的是ROS软路由如何设置分流的问题&#xff0c;很多做过工作室的小伙伴肯定很熟悉。 简单来讲&#xff0c;ROS软路由就是普通的路…

数模转换 120dB,192kHz DAC 音频转换芯片DP7398 软硬件兼容替代CS4398

数模转换芯片&#xff08;DAC&#xff09;是一种将数字信号转换为模拟信号的集成电路。它通过将数字数据转换为相应的模拟电压或电流输出&#xff0c;实现了数字系统与模拟系统之间的接口和互联。 DAC具有许多优势&#xff0c;使其在各种应用领域得到广泛应用。首先&#xff0c…

接口测试 01 -- 基础与原理

接口概述 什么是接口 接口是计算机系统中不同组件之间进行交流和互动的一种方式。 在软件开发中&#xff0c;接口通常指的是一组定义了输入、输出、功能和规范的方法、函数或协议。接口定义了组件之间的通信协议&#xff0c;使得它们可以相互协作&#xff0c;实现特定的功能。…

23.实战演练--个人主页

<?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"><applicationandroid:allowBackup"true"an…

【latex】参考文献排版前移,在最前面引用\usepackage{url}

【LaTeX】参考文献排版前移&#xff0c;在最前面引用\usepackage{url} 写在最前面完整解决步骤请教申申latex编译报错解决方案 写在最前面 参考文献从21开始排版前移了 解决方案&#xff1a;在最前面加一行 \usepackage{url}完整解决步骤 请教申申 申申yyds&#xff01;&am…

VsCode插件开发之ChatGPT实战

基础介绍&#x1f5e3;︎ VSCode 是采用了 Electron开发的跨平台的桌面应用&#xff0c;它兼容 Mac、Windows 和Linux&#xff0c;可以构建出三个平台的应用程序&#xff0c;基于VSCode开发的插件&#xff0c;同样也能在多个平台同时运行。 VSCode布局&#xff1a; 插件开发&…

IDEA插件中的postman,你试试

Postman是大家最常用的API调试工具&#xff0c;那么有没有一种方法可以不用手动写入接口到Postman&#xff0c;即可进行接口调试操作&#xff1f;今天给大家推荐一款IDEA插件&#xff1a;Apipost Helper&#xff0c;写完代码就可以调试接口并一键生成接口文档&#xff01;而且还…

JAVA方法及练习

目录 Java方法的定义以及调用 带返回值方法的定义和调用 方法的重载 方法大练习 练习1 练习2 练习3 练习4 Java方法的定义以及调用 方法练习package java方法;public class fangfa1 {public static void main(String[] args) {xuexi();}//定义一个方法public static vo…

UG全参数化建模

在UG全参数化建模中&#xff0c;可以先创建表达式再设计图形&#xff0c;也可先设计图形再关联表达式 UG表达式类型有&#xff1a;数字&#xff0c;字符串&#xff0c;布尔&#xff0c;整数&#xff0c;点&#xff0c;矢量&#xff0c;列表 数字&#xff1a;在数字类型中&…

【Python学习】Python学习20- 面向对象(3)

目录 【Python学习】Python学习20- 面向对象&#xff08;1&#xff09; 前言类属性与方法类的私有属性类的私有方法实例 单下划线、双下划线、头尾双下划线说明&#xff1a;参考 文章所属专区 Python学习 前言 本章节主要说明Python的面向对象的处理最后一部分。 类属性与方…

【已解决】fatal: Authentication failed for ‘https://github.com/.../‘

文章目录 异常原因解决方法 异常原因 在 Linux 服务器上使用git push命令&#xff0c;输入用户名和密码之后&#xff0c;总会显示一个报错&#xff1a; fatal: Authentication failed for https://github.com/TianJiaQi-Code/Linux.git/ # 致命&#xff1a;无法通过验证访问起…

.NET国产化改造探索(三)、银河麒麟安装.NET 8环境

随着时代的发展以及近年来信创工作和…废话就不多说了&#xff0c;这个系列就是为.NET遇到国产化需求的一个闭坑系列。接下来&#xff0c;看操作。 上一篇介绍了如何在银河麒麟操作系统上安装人大金仓数据库&#xff0c;这篇文章详细介绍下在银河麒麟操作系统上安装.NET8环境。…

MySQL入门篇:约束(主键,外键),多表查询(连接查询,联合查询,子查询)

目录 1.约束1.约束分类2.演示3.外键约束1.语法2.删除/更新行为 2.多表查询1.多表关系2.多表查询分类1.连接查询1.内连接2.外连接1.左外连接2.右外连接 3.自连接 2.联合查询(union)3.子查询1.标量子查询2.列子查询3.行子查询4.表子查询 1.约束 ①概念:约束是作用于表中字段上的规…

Python4Delphi安装及编译

1.下载或直接克隆python4delphi组件资源到指定目录,我这里下载到Components文件夹下,并对下载的文件夹进行了重命名为(P4D),重命名不是必须的 下载地址:https://github.com/pyscripter/python4delphi 2.安装 2.1在已下载的目录下进入Install文件夹,双击MultiInstaller.exe…

如何快速打造属于自己的接口自动化测试框架

1 接口测试 接口测试是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。 接口自动化相对于UI自动化来说&#xff0c;属于更底层的测试&#xff0c;这样带来的好处就是测试收益更大&#xff…

Stream API 函数式编程 - 告别for循环,代码竟能写的如此优雅?

目录 一、Stream API 函数式编程 1.1、Stream 简介 a&#xff09;为什么引入 Stream&#xff1f;Stream 的出现就是为了让关于集合的操作更加简单&#xff1a; b&#xff09;Stream 的特性&#xff1a; c&#xff09;对stream的操作分为为两类&#xff0c;中间操作 和 结束…