【云原生技术】写一条自定义 SonarJava 规则 这个需要怎么写?

写一条自定义 SonarJava 规则 这个需要怎么写?

  • 一、BigDecimalInstantiation 规则,它一口气覆盖了你要拦的 4 种写法:
    • 方案 A:直接用 PMD 插件自带的 BigDecimalInstantiation
    • 方案 B:只用 SonarJava(不装/不用 PMD)
    • 小结
  • 二、「从零开始」编写、打包并在 SonarQube 中启用 **自定义 SonarJava 规则**的完整示例
    • 一、准备工作
    • 二、创建 Maven 项目骨架
    • 三、实现规则类
    • 四、注册规则
    • 五、单元测试(可选但推荐)
    • 六、打包并部署
    • 七、在 SonarQube 中启用规则
    • 八、调整与扩展

目前我的sonarqube上存在BigDecimal(double) should not be used 这个规则,我想新增 bigDecimal(float) should not be used 、 BiqDecimal.valueof(double) should not be used 、BigDecivalueof(float) should not be used 这3个规则应该怎么加?

一、BigDecimalInstantiation 规则,它一口气覆盖了你要拦的 4 种写法:

• new BigDecimal(double) (已在你现有规则里)
• new BigDecimal(float)  (float 会自动提升为 double,也会命中)
• BigDecimal.valueOf(double)
• BigDecimal.valueOf(float)
在 SonarQube 里最简单、最稳妥的做法就是直接启用 PMD 的 BigDecimalInstantiation 规则,它一口气覆盖了你要拦的 4 种写法:

• new BigDecimal(double) (已在你现有规则里)
• new BigDecimal(float)  (float 会自动提升为 double,也会命中)
• BigDecimal.valueOf(double)
• BigDecimal.valueOf(float)

下面给出两条可选路径,任选其一即可。

────────────────────────────────────────────

方案 A:直接用 PMD 插件自带的 BigDecimalInstantiation

────────────────────────────────────────────

  1. 确认插件
    • Administration ➜ Marketplace ➜ PMD
    版本 ≥ 3.4.0(最好用 3.9.x;内部自带 PMD 6.5x)。
    • 若刚装完,要重启 SonarQube。

  2. 激活规则
    Rules ➜ Repository 选 “PMD Java”
    搜索关键字 BigDecimalInstantiation
    打开后勾选 Activate 到你的 Java Quality Profile。

  3. (可选)调参数
    点击铅笔图标修改:
    • violateConstructor = true (默认)
    • violateStaticMethod = true (默认)
    保持默认即可同时拦 constructor + valueOf。

  4. 重新跑一次扫描
    现在 4 种写法都会被报告为 Major (Code Smell)。
    如果不想重复报 “new BigDecimal(double)”(SonarJava 的 S2111 也会报),可以把 S2111 在同一个 Profile 里禁用。

────────────────────────────────────────────

方案 B:只用 SonarJava(不装/不用 PMD)

────────────────────────────────────────────
• SonarJava 自带 S2111 —— BigDecimal(double) / BigDecimal(float)
已经覆盖 构造函数 的 float + double,
不能 检查 valueOf。
• 如果你坚持连 valueOf 也要禁止,就必须:

  1. 写一条自定义 SonarJava 规则(需要扩展开发);或
  2. 安装并启用上面的 PMD 规则。
    实践里 99% 的团队选 1) 或 2) 而不是单独开发。

────────────────────────────────────────────

小结

────────────────────────────────────────────
• 想“一步搞定” → 安装/启用 PMD 插件里的 BigDecimalInstantiation;啥都不用写。
• 只想拦 constructor → 保留 SonarJava S2111 即可。
• 你现在看到的 “BigDecimal(double) should not be used” 大概率就是 S2111;加 PMD 规则后,再跑分析就能把另外 3 种写法一起抓出来。

二、「从零开始」编写、打包并在 SonarQube 中启用 自定义 SonarJava 规则的完整示例

下面给出一条「从零开始」编写、打包并在 SonarQube 中启用 自定义 SonarJava 规则的完整示例,专门拦截
BigDecimal.valueOf(double|float)

────────────────────────────

一、准备工作

────────────────────────────

  1. 环境
    • JDK 8 或以上      (与 SonarQube Server 兼容即可)
    • Maven 3.6+        (推荐)
    • 一台可以重启的 SonarQube 服务器(8.x-10.x 均可)

  2. 确认服务器已安装 SonarJava 分析器(官方默认自带)。

────────────────────────────

二、创建 Maven 项目骨架

────────────────────────────

mvn archetype:generate -DgroupId=com.example.sonar \
  -DartifactId=bigdecimal-rule-plugin \
  -DarchetypeGroupId=org.codehaus.mojo.archetypes \
  -DarchetypeArtifactId=sonar-plugin-archetype \
  -DarchetypeVersion=8.0
cd bigdecimal-rule-plugin

(如果找不到 archetype,可手动建一个普通 Maven 项目,后续内容一样。)

pom.xml 核心依赖保持:

<dependencies>
  
  <dependency>
    <groupId>org.sonarsource.sonarqubegroupId>
    <artifactId>sonar-plugin-apiartifactId>
    <version>${sonar.version}version>
    <scope>providedscope>
  dependency>

  
  <dependency>
    <groupId>org.sonarsource.javagroupId>
    <artifactId>sonar-java-pluginartifactId>
    <version>7.23.0.39526version>
    <classifier>allclassifier>
    <scope>providedscope>
  dependency>

  
  <dependency>
    <groupId>org.sonarsource.javagroupId>
    <artifactId>java-checks-testkitartifactId>
    <version>7.23.0.39526version>
    <scope>testscope>
  dependency>
dependencies>

sonar.version 设成与你服务器一致的版本号(如 10.3.0.82913)。

────────────────────────────

三、实现规则类

────────────────────────────

src/main/java/com/example/sonar/checks/AvoidBigDecimalValueOfDoubleCheck.java
package com.example.sonar.checks;

import java.util.List;
import org.sonar.check.Rule;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.symbols.Symbol;
import org.sonar.plugins.java.api.semantic.Type;

@Rule(key = "AvoidBigDecimalValueOfDouble")
public class AvoidBigDecimalValueOfDoubleCheck extends IssuableSubscriptionVisitor {

  @Override
  public List<Tree.Kind> nodesToVisit() {
    return List.of(Tree.Kind.METHOD_INVOCATION);
  }

  @Override
  public void visitNode(Tree tree) {
    MethodInvocationTree mit = (MethodInvocationTree) tree;

    // 1. 方法名必须叫 valueOf
    if (!"valueOf".equals(mit.symbol().name())) {
      return;
    }

    // 2. 所属类必须是 java.math.BigDecimal
    Symbol owner = mit.symbol().owner();
    if (owner == null || !"java.math.BigDecimal".equals(owner.type().fullyQualifiedName())) {
      return;
    }

    // 3. 至少有 1 个实参,而且所有实参都属于 float/double 基本型或装箱型
    if (mit.arguments().isEmpty()) {
      return;
    }

    boolean match = mit.arguments().stream().allMatch(arg -> {
      Type t = arg.symbolType();
      return t.isPrimitive(Type.Primitives.FLOAT) || t.isPrimitive(Type.Primitives.DOUBLE)
          || t.is("java.lang.Float") || t.is("java.lang.Double");
    });

    if (match) {
      reportIssue(tree, "Avoid BigDecimal.valueOf(float/double); use valueOf(long) or string ctor to prevent precision loss.");
    }
  }
}

────────────────────────────

四、注册规则

────────────────────────────

  1. 规则仓库
src/main/java/com/example/sonar/rules/CustomJavaRulesDefinition.java
package com.example.sonar.rules;

import com.example.sonar.checks.AvoidBigDecimalValueOfDoubleCheck;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.server.rule.RulesDefinitionXmlLoader;

public class CustomJavaRulesDefinition implements RulesDefinition {

  private static final String REPO_KEY = "custom-java";

  @Override
  public void define(Context context) {
    NewRepository repo = context.createRepository(REPO_KEY, "java")
                                .setName("Custom Java Rules");

    // 通过注解扫描
    RulesDefinitionXmlLoader loader = new RulesDefinitionXmlLoader();
    loader.load(repo, AvoidBigDecimalValueOfDoubleCheck.class.getResourceAsStream("/"), "UTF-8");

    repo.done();
  }
}

简化做法:也可以不用 XML,直接通过 Scanners 引擎扫描带 @Rule 的类;框架会自动把 rule load 进仓库。若使用自动扫描,就连上面 RulesDefinitionXmlLoader 都省掉,只需:

  context.createRepository(REPO_KEY, "java")
         .setName("Custom Java Rules")
         .addRule(AvoidBigDecimalValueOfDoubleCheck.class)
         .done();
  1. 插件入口
src/main/java/com/example/sonar/CustomRulesPlugin.java
package com.example.sonar;

import com.example.sonar.rules.CustomJavaRulesDefinition;
import org.sonar.api.Plugin;

public class CustomRulesPlugin implements Plugin {
  @Override
  public void define(Context context) {
    context.addExtension(CustomJavaRulesDefinition.class);
    context.addExtension(com.example.sonar.checks.AvoidBigDecimalValueOfDoubleCheck.class);
  }
}
  1. pom.xml 中指定:
<packaging>sonar-pluginpackaging>

<properties>
  <sonar.plugin.key>custom-bigdecimal-rulessonar.plugin.key>
  <sonar.plugin.class>com.example.sonar.CustomRulesPluginsonar.plugin.class>
  <sonar.plugin.display.name>Custom BigDecimal Rulessonar.plugin.display.name>
properties>

────────────────────────────

五、单元测试(可选但推荐)

────────────────────────────

src/test/java/com/example/sonar/checks/AvoidBigDecimalValueOfDoubleCheckTest.java
package com.example.sonar.checks;

import org.junit.Test;
import org.sonar.java.checks.verifier.JavaCheckVerifier;

public class AvoidBigDecimalValueOfDoubleCheckTest {

  @Test
  public void detect_all_variants() {
    JavaCheckVerifier.verify("src/test/files/BigDecimalValueOfSample.java",
      new AvoidBigDecimalValueOfDoubleCheck());
  }
}

BigDecimalValueOfSample.java 中用 // Noncompliant 标注违规行,让 JavaCheckVerifier 自动断言。

────────────────────────────

六、打包并部署

────────────────────────────

mvn clean package

生成:target/bigdecimal-rule-plugin-1.0-SNAPSHOT.jar

部署到 SonarQube:

cp target/bigdecimal-rule-plugin-*.jar $SONAR_HOME/extensions/plugins/
# 删除同目录下如有旧版 JAR
systemctl restart sonarqube        # 或 sonar.sh restart

────────────────────────────

七、在 SonarQube 中启用规则

────────────────────────────

  1. Web UI ➜ Rules
    Repository 里将看到新的 “Custom Java Rules”。
  2. 打开 AvoidBigDecimalValueOfDouble ➜ Activate 加入你的 Java Quality Profile。
  3. 重新执行一次项目扫描,BigDecimal.valueOf(double|float) 即会被报告。

────────────────────────────

八、调整与扩展

────────────────────────────
• 如还想拦 new BigDecimal(double|float),可以把 SonarJava 自带规则 S2111 也加到同一 Profile;
或把本规则扩展为同时监听 NEW_CLASS,判断构造函数参数类型。
• 若需配置阈值,可在 @Rule 上补充 cardinality=RuleCardinality.MULTIPLE, 再在 @RuleProperty 中定义参数。
• 针对大量自定义规则,可把每条规则写成独立类 ➜ 统一在 CustomJavaRulesDefinition 中注册。

到此,你就完成了一条自定义 SonarJava 规则的整个闭环:编码→测试→打包→部署→启用→生效。

你可能感兴趣的:(python,前端,开发语言)