NullAway ist ein Tool zur Beseitigung von NullPointerException
s (NPEs) in Ihrem Java-Code. Um NullAway zu verwenden, fügen Sie Ihrem Code zunächst @Nullable
-Anmerkungen hinzu, wo immer ein Feld, ein Methodenparameter oder ein Rückgabewert null
sein kann. Angesichts dieser Anmerkungen führt NullAway eine Reihe typbasierter, lokaler Prüfungen durch, um sicherzustellen, dass kein Zeiger, der in Ihrem Code dereferenziert wird, null
sein kann. NullAway ähnelt der typbasierten Nullbarkeitsprüfung in den Sprachen Kotlin und Swift sowie den Nullprüfern Checker Framework und Eradicate für Java.
NullAway ist schnell . Es ist als Plugin für Error Prone konzipiert und kann auf jedem einzelnen Build Ihres Codes ausgeführt werden. In unseren Messungen beträgt der Build-Zeit-Overhead beim Ausführen von NullAway normalerweise weniger als 10 %. NullAway ist auch praktisch : Es verhindert nicht alle möglichen NPEs in Ihrem Code, aber es fängt die meisten NPEs ab, die wir in der Produktion beobachtet haben, und erlegt gleichzeitig einen angemessenen Annotationsaufwand auf, was ein tolles Preis-Leistungs-Verhältnis bietet.
NullAway erfordert, dass Sie Ihren Code mit Error Prone, Version 2.14.0 oder höher, erstellen. Anweisungen zum Einstieg in Error Prone und zur Integration in Ihr Build-System finden Sie in der Dokumentation zu Error Prone. Bei den folgenden Anweisungen wird davon ausgegangen, dass Sie Gradle verwenden. Informationen zu anderen Build-Systemen finden Sie in den Dokumenten.
Um NullAway in Ihr Nicht-Android-Java-Projekt zu integrieren, fügen Sie Folgendes zu Ihrer build.gradle
Datei hinzu:
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 " )
}
}
}
Lassen Sie uns dieses Skript Schritt für Schritt durchgehen. Der Abschnitt plugins
enthält das Gradle Error Prone-Plugin für die Error Prone-Integration.
In dependencies
lädt die erste errorprone
Zeile NullAway und die api
Zeile lädt die JSpecify-Bibliothek, die geeignete Nullbarkeitsanmerkungen bereitstellt, z. B. org.jspecify.annotations.Nullable
. NullAway ermöglicht die Verwendung jeder @Nullable
-Annotation, sodass beispielsweise auch @Nullable
aus der AndroidX-Annotationsbibliothek oder JetBrains-Annotationen in Ordnung sind. Die zweite errorprone
Zeile legt die Version von Error Prone fest, die verwendet wird.
Schließlich übergeben wir im Abschnitt tasks.withType(JavaCompile)
einige Konfigurationsoptionen an NullAway. First check("NullAway", CheckSeverity.ERROR)
setzt NullAway-Probleme auf die Fehlerstufe (entspricht dem standardmäßigen fehleranfälligen Argument -Xep:NullAway:ERROR
); Standardmäßig gibt NullAway Warnungen aus. Dann option("NullAway:AnnotatedPackages", "com.uber")
(entspricht dem fehleranfälligen Standardargument -XepOpt:NullAway:AnnotatedPackages=com.uber
) NullAway mit, dass der Quellcode in Paketen unter dem Namensraum com.uber
liegen sollte auf Null-Dereferenzierungen und die ordnungsgemäße Verwendung von @Nullable
Annotationen überprüft und dass davon ausgegangen werden sollte, dass Klassendateien in diesen Paketen die korrekte Verwendung von @Nullable
aufweisen (siehe Weitere Informationen finden Sie in den Dokumenten. NullAway erfordert zur Ausführung mindestens das Konfigurationsargument AnnotatedPackages
, um zwischen annotiertem und nicht annotiertem Code zu unterscheiden. Weitere nützliche Konfigurationsoptionen finden Sie in den Konfigurationsdokumenten. Für eine noch einfachere Konfiguration der NullAway-Optionen verwenden Sie das Gradle NullAway-Plugin. Abschließend zeigen wir, wie Sie NullAway bei Bedarf im Testcode deaktivieren können.
Wir empfehlen, alle von Error Prone gemeldeten Probleme anzugehen, insbesondere solche, die als Fehler (und nicht als Warnungen) gemeldet werden. Wenn Sie NullAway jedoch ausprobieren möchten, ohne andere fehleranfällige Prüfungen auszuführen, können Sie options.errorprone.disableAllChecks
verwenden (entspricht der Übergabe von "-XepDisableAllChecks"
an den Compiler vor den NullAway-spezifischen Argumenten).
Versionen 3.0.0 und höher des Gradle Error Prone Plugins unterstützen Android nicht mehr. Wenn Sie also eine aktuelle Version dieses Plugins verwenden, müssen Sie einige weitere Konfigurationen hinzufügen, um Error Prone und NullAway auszuführen. Unsere Beispiel-App build.gradle
Datei zeigt eine Möglichkeit, dies zu tun, aber Ihr Android-Projekt erfordert möglicherweise Anpassungen. Alternativ unterstützen 2.x-Versionen des Gradle Error Prone Plugin weiterhin Android und funktionieren möglicherweise weiterhin mit Ihrem Projekt.
Darüber hinaus kann im Vergleich zur Java-Konfiguration die JSpecify-Abhängigkeit entfernt werden; Sie können stattdessen die Annotation androidx.annotation.Nullable
aus der AndroidX-Annotationsbibliothek verwenden.
Einige Annotationsprozessoren wie Dagger und AutoValue generieren Code im selben Paket-Namespace wie Ihr eigener Code. Dies kann zu Problemen führen, wenn NullAway wie oben vorgeschlagen auf die Stufe ERROR
gesetzt wird, da Fehler in diesem generierten Code den Build blockieren. Derzeit besteht die beste Lösung für dieses Problem darin, Error Prone für generierten Code mithilfe der in Error Prone 2.1.3 hinzugefügten Option -XepExcludedPaths
vollständig zu deaktivieren (hier dokumentiert, verwenden Sie options.errorprone.excludedPaths=
in Gradle). Finden Sie zur Verwendung heraus, welches Verzeichnis den generierten Code enthält, und fügen Sie dieses Verzeichnis der ausgeschlossenen Pfad-Regex hinzu.
Hinweis für Dagger-Benutzer : Dagger-Versionen älter als 2.12 können fehlerhafte Interaktionen mit NullAway haben; siehe hier. Bitte aktualisieren Sie auf Dagger 2.12, um das Problem zu beheben.
Im Gegensatz zu anderen oben genannten Annotationsprozessoren ändert Lombok den speicherinternen AST des von ihm verarbeiteten Codes, was die Ursache zahlreicher Inkompatibilitäten mit Error Prone und folglich NullAway ist.
Wir empfehlen die Verwendung von NullAway mit Lombok nicht besonders. Allerdings kodiert NullAway einige Kenntnisse über gängige Lombok-Annotationen und wir bemühen uns um größtmögliche Kompatibilität. Insbesondere sollten gängige Verwendungen wie die Klassen @lombok.Builder
und @Data
unterstützt werden.
Damit NullAway den von Lombok generierten Code im In-Memory-Java-AST erfolgreich erkennen kann, muss die folgende Konfigurationsoption als Teil einer anwendbaren lombok.config
Datei an Lombok übergeben werden:
lombok.addLombokGeneratedAnnotation = true
Dies führt dazu, dass Lombok @lombok.Generated
zu den von ihm generierten Methoden/Klassen hinzufügt. NullAway ignoriert (dh überprüft nicht) die Implementierung dieses generierten Codes und behandelt ihn als nicht kommentiert.
Sehen wir uns anhand eines einfachen Codebeispiels an, wie NullAway funktioniert:
static void log ( Object x ) {
System . out . println ( x . toString ());
}
static void foo () {
log ( null );
}
Dieser Code ist fehlerhaft: Wenn foo()
aufgerufen wird, schlägt der nachfolgende Aufruf von log()
mit einem NPE fehl. Sie können diesen Fehler in der NullAway-Beispiel-App sehen, indem Sie Folgendes ausführen:
cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build
Standardmäßig geht NullAway davon aus, dass jeder Methodenparameter, Rückgabewert und Feld nicht null ist, d. h., ihm kann niemals ein null
zugewiesen werden. Im obigen Code wird davon ausgegangen, dass der x
Parameter von log()
ungleich Null ist. Daher meldet NullAway den folgenden Fehler:
warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
log(null);
^
Wir können diesen Fehler beheben, indem wir zulassen, dass null
mit einer @Nullable
-Annotation an log()
übergeben wird:
static void log ( @ Nullable Object x ) {
System . out . println ( x . toString ());
}
Mit dieser Anmerkung weist NullAway auf die mögliche Null-Dereferenzierung hin:
warning: [NullAway] dereferenced expression x is @Nullable
System.out.println(x.toString());
^
Wir können diese Warnung beheben, indem wir eine Nullprüfung hinzufügen:
static void log ( @ Nullable Object x ) {
if ( x != null ) {
System . out . println ( x . toString ());
}
}
Mit dieser Änderung werden alle NullAway-Warnungen behoben.
Weitere Einzelheiten zu den Prüfungen, Fehlermeldungen und Einschränkungen von NullAway finden Sie in unserem ausführlichen Leitfaden.
Wenn Sie Fragen zur Verwendung von NullAway haben, können Sie gerne ein GitHub-Problem eröffnen. Oder Sie können dem NullAway Discord-Server beitreten und uns dort eine Frage stellen.
Wir würden uns freuen, wenn Sie zu NullAway beitragen! Bitte beachten Sie, dass Sie nach dem Erstellen einer Pull-Anfrage aufgefordert werden, unsere Uber Contributor-Lizenzvereinbarung zu unterzeichnen.
NullAway ist unter der MIT-Lizenz lizenziert. Weitere Informationen finden Sie in der Datei LICENSE.txt.