所有子包的 IntelliJ IDEA @ParametersAreNonnullByDefault

IntelliJ IDEA @ParametersAreNonnullByDefault for all subpackages

我使用 IntelliJ 的空值检查机制 来防止空指针崩溃。 我已经使用 this 答案成功地将所有 Java 方法参数默认设置为 @NonNull。

创建package-info.java后,用于在Java中定义package annotations。在我的 Android Studio 项目中,作为该包直接后代的所有 java 文件都具有带有默认 @NonNull 参数的方法。

明显的问题是我需要为该包中的所有 Java 类 定义 @ParametersAreNonnullByDefault 包括所有子包

如何定义@ParametersAreNonnullByDefault 以便它向下传播到所有子包java 文件?我希望所有内部代码的方法都默认使用@NonNull 注释。

/**
  * File: package-info.java
  * Make all method parameters @NonNull by default
  */
  @ParametersAreNonnullByDefault
  package com.intive.nearbyplaces.main;

  import javax.annotation.ParametersAreNonnullByDefault;

问题是我无法强制 Android Studio 在所有子包中遵守 @ParametersAreNonnullByDefault(即递归地对 java 中的所有文件 com.company.name)

我写了一个gradle脚本,但是检查是否生成了package-info.java文件在每个子包文件夹中,并在必要时创建它。该脚本在 assembleDebug 任务之前运行。

所以事实证明可以在项目中的所有 java 类 上强制使用 @ParametersAreNonnullByDefault 注释。

下载源代码 here。请记住将第 19 行替换为 您的包名称 .

用法:

apply plugin: 'com.android.application'
apply from: 'nonnull.gradle'

android {
   compileSdkVersion 24
   buildToolsVersion "24.0.2"

   [...]
}

记得在.gitignore

中包含package-info.java文件
//File: .gitignore 

package-info.java

Checkstyle 规则:

<module name="JavadocPackage"/>

检查每个子包中是否包含package-info.java

来源:

/**
 *  File: nonnull.gradle
 *
 *  Generates package-info.java for appropriate packages
 *  inside src/main/java folder.
 *
 *  This is a workaround to define @ParametersAreNonnullByDefault for all Java classes in a package
 *  i.e. including all subpackages (note: edit package name in line no. 19).
 */
task generateNonNullJavaFiles(dependsOn: "assembleDebug", type: Copy) {
    group = "Copying"
    description = "Generate package-info.java classes"

    def infoFileContentHeader = getFileContentHeader();
    def infoFileContentFooter = getFileContentFooter();

    def sourceDir = file( "${projectDir}" + File.separatorChar + "src" + File.separatorChar +
            "main" + File.separatorChar + "java" + File.separatorChar +
            "com" + File.separatorChar + "company" + File.separatorChar + "name" )
    sourceDir.eachDirRecurse { dir ->
        def infoFilePath = dir.getAbsolutePath() + File.separatorChar + "package-info.java"

        if (!file(infoFilePath).exists()) {
            def infoFileContentPackage = getFileContentPackage(dir.getAbsolutePath());
            new File(infoFilePath).write(infoFileContentHeader +
                    infoFileContentPackage + infoFileContentFooter)
            println "[dir] " + infoFilePath + "  created";
        }
    }
    println "[SUCCESS] NonNull generator: package-info.java files checked"
}

def getFileContentPackage(path) {
    def mainSrcPhrase = "src" + File.separatorChar + "main" + File.separatorChar +
            "java" + File.separatorChar
    def mainSrcPhraseIndex = path.indexOf(mainSrcPhrase)
    def output = path.substring(mainSrcPhraseIndex)

    // Win hotfix
    if (System.properties['os.name'].toLowerCase().contains('windows')) {
        output = output.replace("\", "/")
        mainSrcPhrase = mainSrcPhrase.replace("\", "/")
    }

    return "package " + output.replaceAll(mainSrcPhrase, "").replaceAll(
            "/", ".") + ";\n"
}

def getFileContentHeader() {
    return  "/** javadoc goes here \n */\n" +
            "@ParametersAreNonnullByDefault\n" +
            "@ReturnValuesAreNonnullByDefault\n"
}

def getFileContentFooter() {
    return  "\n" +
            "import javax.annotation.ParametersAreNonnullByDefault;\n" +
            "\n" +
            "import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault;"
}

可以找到为 src main、test 和 androidTest 文件夹生成包信息文件的扩展版本 here

查找错误和 Lint:

确实可以使用 findbugs 和 lint。