NullAway est un outil pour vous aider à éliminer les NullPointerException
(NPE) dans votre code Java. Pour utiliser NullAway, ajoutez d'abord des annotations @Nullable
dans votre code partout où un champ, un paramètre de méthode ou une valeur de retour peut être null
. Compte tenu de ces annotations, NullAway effectue une série de vérifications locales basées sur le type pour garantir que tout pointeur déréférencé dans votre code ne peut pas être null
. NullAway est similaire à la vérification de nullité basée sur le type dans les langages Kotlin et Swift, ainsi qu'aux vérificateurs nuls Checker Framework et Eradicate pour Java.
NullAway est rapide . Il est construit comme un plugin pour Error Prone et peut s'exécuter sur chaque version de votre code. Dans nos mesures, la surcharge de temps de construction liée à l'exécution de NullAway est généralement inférieure à 10 %. NullAway est également pratique : il n'empêche pas tous les NPE possibles dans votre code, mais il détecte la plupart des NPE que nous avons observés en production tout en imposant une charge d'annotation raisonnable, ce qui vous en donne pour votre argent.
NullAway nécessite que vous construisiez votre code avec Error Prone, version 2.14.0 ou supérieure. Consultez la documentation Error Prone pour obtenir des instructions sur la prise en main d’Error Prone et l’intégration avec votre système de build. Les instructions ci-dessous supposent que vous utilisez Gradle ; voir la documentation pour une discussion sur d'autres systèmes de construction.
Pour intégrer NullAway dans votre projet Java non Android, ajoutez ce qui suit à votre fichier build.gradle
:
plugins {
// we assume you are already using the Java plugin
id " net.ltgt.errorprone " version " <plugin version> "
}
dependencies {
errorprone " com.uber.nullaway:nullaway:<NullAway version> "
// Some source of nullability annotations; JSpecify recommended,
// but others supported as well.
api " org.jspecify:jspecify:1.0.0 "
errorprone " com.google.errorprone:error_prone_core:<Error Prone version> "
}
import net.ltgt.gradle.errorprone.CheckSeverity
tasks . withType( JavaCompile ) {
options . errorprone {
check( " NullAway " , CheckSeverity . ERROR )
option( " NullAway:AnnotatedPackages " , " com.uber " )
}
// Include to disable NullAway on test code
if (name . toLowerCase() . contains( " test " )) {
options . errorprone {
disable( " NullAway " )
}
}
}
Parcourons ce script étape par étape. La section plugins
extrait le plugin Gradle Error Prone pour l'intégration d'Error Prone.
Dans dependencies
, la première ligne errorprone
charge NullAway et la ligne api
charge la bibliothèque JSpecify qui fournit des annotations de nullité appropriées, par exemple org.jspecify.annotations.Nullable
. NullAway permet d'utiliser n'importe quelle annotation @Nullable
, donc, par exemple, @Nullable
de la bibliothèque d'annotations AndroidX ou les annotations JetBrains conviennent également. La deuxième ligne errorprone
définit la version d’Error Prone utilisée.
Enfin, dans la section tasks.withType(JavaCompile)
, nous transmettons certaines options de configuration à NullAway. Premier check("NullAway", CheckSeverity.ERROR)
définit les problèmes NullAway au niveau d'erreur (c'est équivalent à l'argument standard -Xep:NullAway:ERROR
Error Prone) ; par défaut, NullAway émet des avertissements. Ensuite, option("NullAway:AnnotatedPackages", "com.uber")
(équivalent à l'argument -XepOpt:NullAway:AnnotatedPackages=com.uber
Error Prone) indique à NullAway que le code source des packages sous l'espace de noms com.uber
doit être vérifié les déréférencements nuls et l'utilisation correcte des annotations @Nullable
, et que les fichiers de classe dans ces packages doivent être supposés avoir une utilisation correcte de @Nullable
(voir le documents pour plus de détails). NullAway nécessite au moins l'argument de configuration AnnotatedPackages
pour s'exécuter, afin de faire la distinction entre le code annoté et non annoté. Consultez les documents de configuration pour d'autres options de configuration utiles. Pour une configuration encore plus simple des options NullAway, utilisez le plugin Gradle NullAway. Enfin, nous montrons comment désactiver NullAway sur le code de test, si vous le souhaitez.
Nous vous recommandons de résoudre tous les problèmes signalés par Error Prone, en particulier ceux signalés sous forme d'erreurs (plutôt que d'avertissements). Mais, si vous souhaitez essayer NullAway sans exécuter d'autres vérifications sujettes aux erreurs, vous pouvez utiliser options.errorprone.disableAllChecks
(équivalent à passer "-XepDisableAllChecks"
au compilateur, avant les arguments spécifiques à NullAway).
Les versions 3.0.0 et ultérieures du plugin Gradle Error Prone ne prennent plus en charge Android. Donc, si vous utilisez une version récente de ce plugin, vous devrez ajouter une configuration supplémentaire pour exécuter Error Prone et NullAway. Notre exemple de fichier build.gradle
d'application montre une façon de procéder, mais votre projet Android peut nécessiter des ajustements. Alternativement, les versions 2.x du plugin Gradle Error Prone prennent toujours en charge Android et peuvent toujours fonctionner avec votre projet.
Au-delà, par rapport à la configuration Java, la dépendance JSpecify peut être supprimée ; vous pouvez plutôt utiliser l'annotation androidx.annotation.Nullable
de la bibliothèque d'annotations AndroidX.
Certains processeurs d'annotations comme Dagger et AutoValue génèrent du code dans le même espace de noms de package que votre propre code. Cela peut entraîner des problèmes lors de la définition de NullAway au niveau ERROR
comme suggéré ci-dessus, car des erreurs dans ce code généré bloqueront la construction. Actuellement, la meilleure solution à ce problème consiste à désactiver complètement Error Prone sur le code généré, en utilisant l'option -XepExcludedPaths
ajoutée dans Error Prone 2.1.3 (documentée ici, utilisez options.errorprone.excludedPaths=
dans Gradle). Pour l'utiliser, déterminez quel répertoire contient le code généré et ajoutez ce répertoire à l'expression régulière du chemin exclu.
Note pour les utilisateurs de Dagger : les versions de Dagger antérieures à 2.12 peuvent avoir de mauvaises interactions avec NullAway ; voir ici. Veuillez mettre à jour vers Dagger 2.12 pour résoudre le problème.
Contrairement aux autres processeurs d'annotations ci-dessus, Lombok modifie l'AST en mémoire du code qu'il traite, ce qui est à l'origine de nombreuses incompatibilités avec Error Prone et, par conséquent, NullAway.
Nous ne recommandons pas particulièrement d'utiliser NullAway avec Lombok. Cependant, NullAway code une certaine connaissance des annotations courantes de Lombok et nous essayons d'assurer une compatibilité au mieux. En particulier, les utilisations courantes telles que les classes @lombok.Builder
et @Data
doivent être prises en charge.
Pour que NullAway puisse détecter avec succès le code généré par Lombok dans le Java AST en mémoire, l'option de configuration suivante doit être transmise à Lombok dans le cadre d'un fichier lombok.config
applicable :
lombok.addLombokGeneratedAnnotation = true
Cela amène Lombok à ajouter @lombok.Generated
aux méthodes/classes qu'il génère. NullAway ignorera (c'est-à-dire ne vérifiera pas) l'implémentation de ce code généré, le traitant comme non annoté.
Voyons comment NullAway fonctionne sur un exemple de code simple :
static void log ( Object x ) {
System . out . println ( x . toString ());
}
static void foo () {
log ( null );
}
Ce code est bogué : lorsque foo()
est appelé, l'appel suivant à log()
échouera avec un NPE. Vous pouvez voir cette erreur dans l'exemple d'application NullAway en exécutant :
cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build
Par défaut, NullAway suppose que chaque paramètre de méthode, valeur de retour et champ est non-null , c'est-à-dire qu'une valeur null
ne peut jamais lui être attribuée. Dans le code ci-dessus, le paramètre x
de log()
est supposé être non nul. Ainsi, NullAway signale l'erreur suivante :
warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
log(null);
^
Nous pouvons corriger cette erreur en autorisant la transmission null
à log()
, avec une annotation @Nullable
:
static void log ( @ Nullable Object x ) {
System . out . println ( x . toString ());
}
Avec cette annotation, NullAway souligne le possible déréférencement null :
warning: [NullAway] dereferenced expression x is @Nullable
System.out.println(x.toString());
^
Nous pouvons corriger cet avertissement en ajoutant une vérification nulle :
static void log ( @ Nullable Object x ) {
if ( x != null ) {
System . out . println ( x . toString ());
}
}
Avec ce changement, tous les avertissements NullAway sont corrigés.
Pour plus de détails sur les vérifications, les messages d'erreur et les limitations de NullAway, consultez notre guide détaillé.
N'hésitez pas à ouvrir un problème GitHub si vous avez des questions sur la façon d'utiliser NullAway. Ou bien, vous pouvez rejoindre le serveur NullAway Discord et nous y poser une question.
Nous serions ravis que vous contribuiez à NullAway ! Veuillez noter qu'une fois que vous aurez créé une pull request, il vous sera demandé de signer notre contrat de licence de contributeur Uber.
NullAway est sous licence MIT. Consultez le fichier LICENSE.txt pour plus d'informations.