【idea】idea插件编写教程,博主原创idea插件 欢迎下载

news2024/9/24 22:18:30

前言:经常使用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本身是件不容易的事,而阅读代码时,已经处于一个上帝视角,则会显得非常简单。

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
下载一:( idea团队给博主发了邮件 插件最开始的命名不规范 目前在重新审核 不知道后续结果 先在github下载吧)
idea插件商店搜索: Equals Inspection

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

releases区
在这里插入图片描述
安装方式:1. 直接将jar包拖进idea,2.重启idea

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

在这里插入图片描述

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flask 小程序菜品搜索

mina/pages/food/index.wxml <!--index.wxml--> <!--1px 750/320 2.34rpx;--> <view class"container"><!--轮播图--><view class"swiper-container"><swiper class"swiper_box" autoplay"{{autoplay}…

品牌帮助中心:提升企业客户服务水平与效率的实用指南

什么是品牌帮助中心&#xff1f;简单来理解&#xff0c;他就是一种加速问题解决效率的方式&#xff0c;是通过在官网设置文章库或者社区的形式&#xff0c;为客户提供自助服务&#xff0c;自我查找问题答案。是一种既能提升问题解决效率&#xff0c;又能提升品牌形象的方式。接…

【LeetCode】203. 移除链表元素(简单)——代码随想录算法训练营Day03

题目链接&#xff1a;203. 移除链表元素 题目描述 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff…

蓝牙音视频远程控制协议(AVRCP) AV/C command格式介绍

零.声明 本专栏文章我们会以连载的方式持续更新&#xff0c;本专栏计划更新内容如下&#xff1a; 第一篇:蓝牙综合介绍 &#xff0c;主要介绍蓝牙的一些概念&#xff0c;产生背景&#xff0c;发展轨迹&#xff0c;市面蓝牙介绍&#xff0c;以及蓝牙开发板介绍。 第二篇:Trans…

09-Python服务链路追踪案例

skyWalking Python agent requires SkyWalking 8.0 and Python 3.7 # 将django包导入 ~$ cd /apps ~$ tar xf django-test.tgz ~$ cd django-test# 安装模块 ~$ apt install python3-pip ~$ pip3 install -r requirements.txt# 创建django项目mysite ~$ django-admin startpro…

Vue:将以往的JQ页面,重构成Vue组件页面的大致思路梳理(组件化编码大致流程)

一、实现静态组件 组件要按照功能点拆分&#xff0c;命名不要与HTML元素冲突。 1、根据UI提供的原型图&#xff0c;进行结构拆分&#xff0c;拆分的粒度以是否方便给组件起名字为依据。并梳理好对应组件的层级依赖关系。 2、拆分好结构后&#xff0c;开始对应的写组件&#x…

案例118:基于微信小程序的电影院订票选座系统设计及实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

新型的变现和引流方式

AI 数字人短视频正成为一种新型的变现和引流方式。随着人工智能技术的不断发展&#xff0c;数字人技术也越来越成熟&#xff0c;为用户提供了更加逼真、生动的虚拟形象。通过AI 数字人短视频&#xff0c;用户可以创作出具有个性化特点的短视频内容&#xff0c;并将其发布在各大…

探索短链接:让网络分享更便捷

短链接是一种将长网址缩短为简洁形式的编码&#xff0c;它在互联网领域具有广泛的应用。本文将从多个方面介绍短链接的原理、类型、优势及应用场景&#xff0c;帮助您深入了解这一重要的网络技术。 短链接 | 一个覆盖广泛主题工具的高效在线平台(amd794.com) https://amd794.…

数据结构之int类

int类 int 是数字类。在其他语言中&#xff0c;数字类有很明细的区分&#xff0c;如 int&#xff08;整型&#xff09;、unsigned int(无符号整型&#xff09;、short&#xff08;短整型&#xff09;、long&#xff08;长整型&#xff09;、longlong&#xff08;长长整型&…

AMEYA360:广和通RedCap模组FG131FG132系列

2024年1月&#xff0c;广和通RedCap模组FG131&FG132系列已进入工程送样阶段&#xff0c;可为终端客户提供样片。广和通RedCap模组系列满足不同终端对5G速率、功耗、尺寸、成本的需求&#xff0c;全面助力RedCap技术的行业应用。 FG131&FG132系列基于骁龙X35 5G调制解调…

apache、nginx、php 隐藏版本号

apache、nginx、php 隐藏版本号 针对的系统都是CentOS 1、没配置之前 1.1 Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.2.24 mod_wsgi/3.4 Python/2.7.5 1.2 Server: nginx/1.16.0 1.3 X-Powered-By&#xff1a;7.2.24 2、配置信息 不知道具体位置&#xff0c;可…

QT上位机开发(加密和解密)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 加密和解密是我们在软件开发中经常遇到的一种情形。最早的时候&#xff0c;加密是用在军事上面。现在由于各个行业、各个公司之间的竞争也非常激烈…

大模型开启应用时代 数钉科技一锤定音

叮叮叮叮&#xff01;数钉智造大模型&#xff0c;“定音”强势发布&#xff01; 随着科技的飞速发展&#xff0c;大模型技术已逐渐成为推动产业变革的核心力量。在这一浪潮中&#xff0c;数钉科技凭借深厚的技术积累和敏锐的市场洞察力&#xff0c;成功利用大模型技术搭建起智能…

银行接口测试学习笔记:接口测试从分析到设计!

一、接口测试流程 01\接口测试计划 制定:人员,工具/平台,脚本,时间,标准,输出接口测试计划文档 02\银行接口文档解析 ①.接口名称:说明接口的作用,不用测试 ②.接口地址:http开头,和URL一样,不用测试 ③.请求方式:post/get/delete/put, 当一个接口有多个方式的时候是需要进…

Leetcode202快乐数(java实现)

今天分享的题目是快乐数&#xff1a; 快乐数的定义如下&#xff1a; 快乐数&#xff08;Happy Number&#xff09;是指一个正整数&#xff0c;将其替换为各个位上数字的平方和&#xff0c;重复这个过程直到最后得到的结果为1&#xff0c;或者无限循环但不包含1。如果最终结果为…

金融疆界:在线支付系统渠道网关的创新设计(一)

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;11.1&#xff09;篇。点击上方关注&#xff0c;深入了解支付系统的方方面面。 整个渠道网关的内容预计会分成5篇来讲&#xff1a;1&#xff09;定位、术语、概要设计。2&#xff09;领域模型、状态机设计。3…

小程序开发公司哪家好?哪家最好?

小程序具有轻量、聚焦、快捷等特点&#xff0c;这有别于 web 端类和移动端 app 类产品。 小程序的第一印象非常关键&#xff0c;因此对于首页设计&#xff0c;关键要加强注意力表达&#xff0c;给予用户尽可能直观的信息感知&#xff0c;加快建立其对于业务价值的兴趣&#xf…

linux环境安装docker

一、Docker是什么? 当我们开发一个应用程序时&#xff0c;通常需要配置和安装各种软件、库和依赖项。而这些环境配置可能会因为不同的操作系统或版本而存在差异&#xff0c;导致应用在不同环境中运行出现问题。 Docker就像是一个集装箱&#xff0c;可以将应用程序及其所有依…