AICon 上海站|90%日程已就绪,解锁Al未来! 了解详情
写点什么

Error Prone 通过检测常见错误帮助改善 Java 代码

  • 2022-10-26
    北京
  • 本文字数:3718 字

    阅读完需:约 12 分钟

Error Prone 通过检测常见错误帮助改善Java代码

Error Prone是谷歌开源的一个 Java 编译插件,可以在编译时进行静态分析、bug 检测,或者对可能的优化提出建议。插件中包括了超过 500 个预定义的bug检查,并且允许第三方和自定义插件。检查到问题之后,Error Prone 能够将问题通过 warning 显示出来或者用预定义的解决方案自动修改代码。Error Prone 支持 Java 8、11,以及 17,可以被用来修复 bug 或者大规模重构。文档中提供了使用 Maven、Bazel、Ant 以及 Grandle 的安装和配置教程。需要将 Error Prone 在编译器中配置为 annotation processor(注解处理器),下面是通过 Maven 创建测试工程的示例:

<plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-compiler-plugin</artifactId>    <version>3.10.1</version>    <configuration>        <release>17</release>        <encoding>UTF-8</encoding>        <compilerArgs>            <arg>-XDcompilePolicy=simple</arg>            <arg>-Xplugin:ErrorProne</arg>        </compilerArgs>        <annotationProcessorPaths>            <path>                <groupId>com.google.errorprone</groupId>                <artifactId>error_prone_core</artifactId>                <version>2.15.0</version>            </path>        </annotationProcessorPaths>    </configuration></plugin>
复制代码


接下来可以创建一个示例类。下面的方法使用了 equals 方法来对比两个数组,更准确地说,此处所比较的是对象本身而不是数组的内容。


public boolean compare(String firstList[], String secondList[]) {    return firstList.equals(secondList);}
复制代码


执行 mvn clean verify 触发 Error Prone 分析,下面是运行结果中的错误信息中:


[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:        compile (default-compile) on project ErrorProne: Compilation failure[ERROR] …/ErrorProne/src/main/java/org/example/Main.java:[5,28]     [ArrayEquals] Reference equality used to compare arrays[ERROR]   (see https://errorprone.info/bugpattern/ArrayEquals)[ERROR]   Did you mean 'return Arrays.equals(firstList, secondList);'?
复制代码


报出了ArrayEquals错误,Error Prone 的建议是修改实现方式,以比较数组的内容而不是比较对象。


return Arrays.equals(firstList, secondList);
复制代码


报错不仅可以帮助改善代码,也可以让 Error Prone 自动应用解决方案。 -XepPatchChecks 参数的应用应该包含由逗号分隔开的 bug 模式列表,在上面的情况中,只有 ArrayEquals 解决方案用于这段代码。 -XepPatchLocation 参数用于具体定位解决方案文件位置,在当前情境中是修改了源文件:


<compilerArgs>    <arg>-XDcompilePolicy=simple</arg>    <arg>-Xplugin:ErrorProne -XepPatchChecks:ArrayEquals            -XepPatchLocation:IN_PLACE</arg></compilerArgs>
复制代码


现在,在执行 mvn clean verify 之后,类文件被自动修改为:


public boolean compare(String firstList[], String secondList[]) {    return Arrays.equals(firstList, secondList);}
复制代码


文档里提供了更多关于命令行标识的信息。除了内置的 bug 模式,也可以使用例如SLF4J等第三方发布的插件,或创建自定义插件。内置规则的源码提供了多种可用于定义插件的不同示例模板。例如,自定义一个能够用新的 JUnit 5 @BeforeEach 注解器代替旧版 @Before JUnit 注解器的 Error Prone 插件。


和前文例子不同,自定义的 Error Prone 插件应该被放置于 Maven 模块。Error Prone 通过服务加载器机制来加载 bug 检测。这类之际通常一定的配置,然而谷歌的AutoService项目借助 @AutoService 注解简化了配置工作。@BugPattern 注解用于定义 bug 的名称、简介以及严重性。在下面的例子中,如果没有找到 @Before 注解器会返回Description.NO_MATCH ,否则SuggestedFix会用 @BeforeEach 注解替代 @Before 注解。


@AutoService(BugChecker.class)@BugPattern(    name = "BeforeCheck",    summary = "JUnit 4's @Before is replaced by JUnit 5's @BeforeEach",    severity = BugPattern.SeverityLevel.SUGGESTION)public class BeforeCheck extends BugChecker implements BugChecker.AnnotationTreeMatcher {    private static final Matcher<AnnotationTree> matcher =            isType("org.junit.Before");
@Override public Description matchAnnotation(AnnotationTree annotationTree, VisitorState visitorState) { if (!matcher.matches(annotationTree, visitorState)) { return Description.NO_MATCH; } return describeMatch(annotationTree, SuggestedFix.replace(annotationTree, "@BeforeEach")); }}
复制代码


构建自定义 Error Prone 插件的时候都是需要 Error Prone 和 AutoService 依赖的。


<dependency>  <groupId>com.google.errorprone</groupId>  <artifactId>error_prone_annotations</artifactId>  <version>2.15.0</version></dependency><dependency>  <groupId>com.google.errorprone</groupId>  <artifactId>error_prone_check_api</artifactId>  <version>2.15.0</version></dependency><dependency>  <groupId>com.google.auto.service</groupId>  <artifactId>auto-service-annotations</artifactId>  <version>1.0.1</version></dependency>
复制代码


AutoService 应该被配置为一个注解处理器。


<annotationProcessorPaths>    <path>        <groupId>com.google.auto.service</groupId>        <artifactId>auto-service</artifactId>        <version>1.0.1</version>    </path></annotationProcessorPaths>
复制代码


现在,自定义的 Error Prone 插件可以通过 mvn install 命令,安装在本地的 Maven 仓库。执行命令后,示例工程应该会被配置为使用新的自定义插件作为注解处理器。


<annotationProcessorPaths>    <path>        <groupId>org.example.custom.plugin</groupId>        <artifactId>ErrorProneBeforeCheck</artifactId>        <version>1.0-SNAPSHOT</version>    </path></annotationProcessorPaths>
复制代码


新的 BeforeCheck 应该被加入到了 Error Prone 分析中。


<compilerArgs>  <arg>-XDcompilePolicy=simple</arg>  <arg>-Xplugin:ErrorProne -XepPatchChecks:BeforeCheck            -XepPatchLocation:IN_PLACE</arg></compilerArgs>
复制代码


添加一个示例测试类,其中包含@Before@BeforeEach的两个注解。


public class ErrorProneTest {  @Before  void before() {  }  @BeforeEach  void beforeEach() {  }}
复制代码


运行 mvn verify 时,新的自定义 Error Prone 插件将用@BeforeEach注解替换@Before注解。


public class ErrorProneTest {  @BeforeEach  void before() {  }  @BeforeEach  void beforeEach() {  }}
复制代码


Error Prone 所使用的 Java internal 目前处于隐藏状态,可能会导致如下错误:


java.lang.IllegalAccessError: class com.google.errorprone.BaseErrorProneJavaCompiler (in unnamed module @0x1a6cf771) cannot access class com.sun.tools.javac.api.BasicJavacTask (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.api to unnamed module @0x1a6cf771
复制代码


Maven 的解决办法是通过在项目根目录下创建.mvn 目录来暴露 Java internal,在目录中创建一个 jvm.config 文件,其中配置如下:


--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
复制代码


或者可以将--add-exports--add-opens 参数配置添加到 Maven 编译器插件的 pom 文件中:


<plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-compiler-plugin</artifactId>    <version>3.10.1</version>    <configuration>        <compilerArgs>            <arg>--add-exports</arg>            <arg>jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
复制代码


更多在 Bazel、Ant 和 Gradle 中使用 Error Prone 的信息可参见安装引导


相关阅读:

Java 近期新闻:顺序集合、Spring 6.0-RC1、Tomcat、Reactor 2022.0-RC1

Spring Boot 3 将于 2022 年 11 月发布,延迟了对 Java 模块系统的支持


2022-10-26 08:008759

评论

发布
暂无评论
发现更多内容

实践探讨Python如何进行异常处理与日志记录

华为云开发者联盟

Python 开发 华为云 华为云开发者联盟 企业号2024年4月PK榜

领跑数字化转型:望繁信科技荣登「2024智能自动化技术商Top 15」榜单

望繁信科技

数据挖掘 流程挖掘 流程资产 流程智能

TikTok海外直播网络专线的优势有哪些?

Ogcloud

海外直播专线 海外直播 tiktok直播 tiktok直播专线 海外直播网络

京东广告研发——效率为王:广告统一检索平台实践

京东科技开发者

青椒云桌面玩转AIGC应用部署

青椒云云电脑

云桌面 AIGC

HCDG天津站精彩回顾 | AI高效开发, ModelArts技术动手工作坊

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号2024年4月PK榜 华为云HCDG

关于数据动态脱敏,业务部与安全部终于不用battle了!

极盾科技

数据安全

颜水成挂帅,昆仑万维2050全球研究院联合NUS、NTU发布Vitron,奠定通用视觉多模态大模型终极形态

新消费日报

万物生长,数智融合,又拍云荣登「2024杭州准独角兽企业榜单」

极客天地

服务于金融新核心系统 XSKY星辰天合与中电金信完成产品兼容认证

XSKY星辰天合

XSKY 星辰天合 金融新核心

人民日报媒体技术公司与华为达成鸿蒙合作 助力超千家党媒单位融入鸿蒙生态

最新动态

云电脑如何选择使用?详细介绍

青椒云云电脑

云电脑 云电脑平台

用一个数据库解决80%的问题,YashanDB数据库一体化的实践

极客天地

易点天下入选虎嗅智库大鲸榜AIGC数字营销技术商TOP15

新消费日报

软件测试学习笔记丨业务架构分析工具 plantuml

测试人

软件测试

三十分钟入门基础Go(Java小子版)

京东科技开发者

安全测试之探索windows游戏扫雷

京东科技开发者

AIGC硬件成本太高?试试云电脑

青椒云云电脑

云电脑 AIGC

Pandabuy VS Wegobuy哪个代购系统强?类似软件哪家公司开发

tbapi

淘宝代购系统 Pandabuy wegobuy 代购系统

如何基于Django中的WebSockets和异步视图来实现实时通信功能

不在线第一只蜗牛

django Web websockets

拓展海外社媒市场,云手机抢占先机

Ogcloud

云手机 海外云手机 云手机海外版 社媒运营 社媒营销

深度解析阿里巴巴1688商品详情API返回值:商品信息一手掌握

技术冰糖葫芦

Error Prone 通过检测常见错误帮助改善Java代码_编程语言_Johan Janssen_InfoQ精选文章