Welche @NotNull Java-Annotation soll ich verwenden?

998

Ich möchte meinen Code besser lesbar machen und Tools wie IDE-Code-Inspektion und / oder statische Code-Analyse (FindBugs und Sonar) verwenden, um NullPointerExceptions zu vermeiden. Viele der Werkzeuge scheinen unvereinbar mit jedem anderen @NotNull/ @NonNull/ @NonnullAnmerkung und in meinem Code alle von ihnen Auflistung wäre schrecklich zu lesen. Irgendwelche Vorschläge, welcher der "besten" ist? Hier ist die Liste der entsprechenden Anmerkungen, die ich gefunden habe:

  • javax.validation.constraints.NotNull
    Erstellt für die Laufzeitvalidierung, nicht für statische Analysen.
    Dokumentation

  • edu.umd.cs.findbugs.annotations.NonNull
    Wird von der statischen Analyse von Findbugs und damit von der Sonar- Dokumentation (jetzt Sonarqube ) verwendet

  • javax.annotation.Nonnull
    Dies funktioniert möglicherweise auch mit Findbugs, aber JSR-305 ist inaktiv. (Siehe auch: Wie ist der Status von JSR 305? ) Quelle

  • org.jetbrains.annotations.NotNull
    Wird von IntelliJ IDEA IDE für die statische Analyse verwendet.
    Dokumentation

  • lombok.NonNull
    Wird zur Steuerung der Codegenerierung in Project Lombok verwendet .
    Platzhalter-Annotation, da es keinen Standard gibt.
    Quelle , Dokumentation

  • android.support.annotation.NonNull
    Markierungsanmerkung in Android verfügbar, bereitgestellt durch die Dokumentation des Support-Annotations-Pakets

  • org.eclipse.jdt.annotation.NonNull
    Wird von Eclipse für die Dokumentation der statischen Code-Analyse verwendet

Jaxzin
quelle
203
Apache sollte eine "allgemeine" Annotation und ein Tool erfinden, das sie in jede andere Annotation konvertieren kann. Die Lösung für das Problem zu vieler Standards besteht darin, einen neuen Standard zu erfinden.
unwiderlegbar
6
@irreputable Wenn Apache ein neues "Common" erfindet, gibt es 56 Versionen davon, die sich mit anderen Projekten überschneiden. Und es wäre sowieso nicht Standard (Standard! = Weit verbreitet). Verwenden Sie besser etwas wirklich Standard, Javax ?. *. Übrigens gibt es in diesen Beispielen nicht "zu viele Standards", ich sehe nur 1 oder 2.
ymajoros
6
javax.annotation.Nonnull funktioniert mit Findbugs (hat es gerade getestet), was für mich ein zwingender Grund ist, es zu verwenden.
Nicolas C
20
Wenn ich einfach @NotNull schreibe, bezieht es sich auf com.sun.istack.internal.NotNull. OMG ...
Thomas Weller
3
@MozartBrocchini - Optionale Optionen sind nützlich, wenn Sie zuvor möglicherweise NullObjects verwendet haben. Sie sprechen jedoch nicht wirklich das gleiche Ziel an wie eine Laufzeit-Annotation \ @NotNull, und sie führen mühsames Auspacken ein.
Dave

Antworten:

205

Da JSR 305 (dessen Ziel es war, zu standardisieren @NonNullund @Nullable) seit mehreren Jahren inaktiv ist, gibt es leider keine gute Antwort. Wir können nur eine pragmatische Lösung finden, und meine lautet wie folgt:

Syntax

Aus rein stilistischer Sicht möchte ich jegliche Bezugnahme auf IDE, Framework oder ein Toolkit außer Java selbst vermeiden.

Dies schließt aus:

  • android.support.annotation
  • edu.umd.cs.findbugs.annotations
  • org.eclipse.jdt.annotation
  • org.jetbrains.annotations
  • org.checkerframework.checker.nullness.qual
  • lombok.NonNull

Was uns entweder javax.validation.constraintsoder lässt javax.annotation. Ersteres kommt mit JEE. Ob dies besser ist als javax.annotation, was irgendwann mit JSE oder gar nicht kommen könnte, ist umstritten. Ich persönlich bevorzuge es, javax.annotationweil mir die JEE-Abhängigkeit nicht gefallen würde.

Das lässt uns mit

javax.annotation

Das ist auch die kürzeste.

Es gibt nur eine Syntax, die noch besser wäre : java.annotation.Nullable. Da andere Pakete in der Vergangenheit von javaxbis javaaufgestiegen sind, wäre die javax.annotation ein Schritt in die richtige Richtung.

Implementierung

Ich hatte gehofft, dass sie alle im Grunde die gleiche triviale Implementierung haben, aber eine detaillierte Analyse zeigte, dass dies nicht wahr ist.

Zunächst zu den Ähnlichkeiten:

Die @NonNullAnmerkungen haben alle die Zeile

public @interface NonNull {}

ausser für

  • org.jetbrains.annotationsdas nennt es @NotNullund hat eine triviale Implementierung
  • javax.annotation das hat eine längere Implementierung
  • javax.validation.constraintsdas nennt es auch @NotNullund hat eine Implementierung

Die @NullableAnmerkungen haben alle die Zeile

public @interface Nullable {}

mit Ausnahme (wieder) der org.jetbrains.annotationsmit ihrer trivialen Umsetzung.

Für die Unterschiede:

Auffällig ist das

  • javax.annotation
  • javax.validation.constraints
  • org.checkerframework.checker.nullness.qual

Alle haben Laufzeitanmerkungen ( @Retention(RUNTIME)), während

  • android.support.annotation
  • edu.umd.cs.findbugs.annotations
  • org.eclipse.jdt.annotation
  • org.jetbrains.annotations

sind nur Kompilierzeit ( @Retention(CLASS)).

Wie in dieser SO-Antwort beschrieben, ist die Auswirkung von Laufzeitanmerkungen geringer als man denkt, aber sie haben den Vorteil, dass Tools zusätzlich zu den Kompilierungszeitpunkten Laufzeitprüfungen durchführen können.

Ein weiterer wichtiger Unterschied besteht darin, wo im Code die Anmerkungen verwendet werden können. Es gibt zwei verschiedene Ansätze. Einige Pakete verwenden JLS 9.6.4.1-Kontexte. Die folgende Tabelle gibt einen Überblick:

                                FELDMETHODENPARAMETER LOCAL_VARIABLE 
android.support.annotation XXX   
edu.umd.cs.findbugs.annotations XXXX
org.jetbrains.annotation XXXX
lombok XXXX
javax.validation.constraints XXX   

org.eclipse.jdt.annotation, javax.annotationUnd org.checkerframework.checker.nullness.qualverwenden Sie die definierte Kontexte in JLS 4.11, was der richtige Weg , meiner Meinung nach ist es zu tun.

Das lässt uns mit

  • javax.annotation
  • org.checkerframework.checker.nullness.qual

in dieser Runde.

Code

Um Ihnen zu helfen, weitere Details selbst zu vergleichen, liste ich den Code jeder Anmerkung unten auf. Um den Vergleich zu erleichtern, habe ich Kommentare, Importe und @DocumentedAnmerkungen entfernt. (Sie hatten alle @Documentedbis auf die Klassen aus dem Android-Paket). Ich habe die Zeilen und @TargetFelder neu angeordnet und die Qualifikationen normalisiert.

package android.support.annotation;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER})
public @interface NonNull {}

package edu.umd.cs.findbugs.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface NonNull {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NotNull {String value() default "";}

package javax.annotation;
@TypeQualifier
@Retention(RUNTIME)
public @interface Nonnull {
    When when() default When.ALWAYS;
    static class Checker implements TypeQualifierValidator<Nonnull> {
        public When forConstantValue(Nonnull qualifierqualifierArgument,
                Object value) {
            if (value == null)
                return When.NEVER;
            return When.ALWAYS;
        }
    }
}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf(MonotonicNonNull.class)
@ImplicitFor(
    types = {
        TypeKind.PACKAGE,
        TypeKind.INT,
        TypeKind.BOOLEAN,
        TypeKind.CHAR,
        TypeKind.DOUBLE,
        TypeKind.FLOAT,
        TypeKind.LONG,
        TypeKind.SHORT,
        TypeKind.BYTE
    },
    literals = {LiteralKind.STRING}
)
@DefaultQualifierInHierarchy
@DefaultFor({TypeUseLocation.EXCEPTION_PARAMETER})
@DefaultInUncheckedCodeFor({TypeUseLocation.PARAMETER, TypeUseLocation.LOWER_BOUND})
public @interface NonNull {}

Der Vollständigkeit halber hier die @NullableImplementierungen:

package android.support.annotation;
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {}

package edu.umd.cs.findbugs.annotations;
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
@Retention(CLASS)
public @interface Nullable {}

package org.eclipse.jdt.annotation;
@Retention(CLASS)
@Target({ TYPE_USE })
public @interface Nullable {}

package org.jetbrains.annotations;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface Nullable {String value() default "";}

package javax.annotation;
@TypeQualifierNickname
@Nonnull(when = When.UNKNOWN)
@Retention(RUNTIME)
public @interface Nullable {}

package org.checkerframework.checker.nullness.qual;
@Retention(RUNTIME)
@Target({TYPE_USE, TYPE_PARAMETER})
@SubtypeOf({})
@ImplicitFor(
    literals = {LiteralKind.NULL},
    typeNames = {java.lang.Void.class}
)
@DefaultInUncheckedCodeFor({TypeUseLocation.RETURN, TypeUseLocation.UPPER_BOUND})
public @interface Nullable {}

Die folgenden zwei Pakete haben keine @Nullable, daher liste ich sie separat auf. Lombok hat eine ziemlich langweilige @NonNull. In javax.validation.constraintsder @NonNullist eigentlich eine @NotNull und es hat eine längliche Umsetzung.

package lombok;
@Retention(CLASS)
@Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE})
public @interface NonNull {}

package javax.validation.constraints;
@Retention(RUNTIME)
@Target({ FIELD, METHOD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Constraint(validatedBy = {})
public @interface NotNull {
    String message() default "{javax.validation.constraints.NotNull.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default {};
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        NotNull[] value();
    }
}

Unterstützung

Aus meiner Erfahrung javax.annotationwird zumindest von Eclipse und dem Checker Framework sofort unterstützt.

Zusammenfassung

Meine ideale Anmerkung wäre die java.annotationSyntax mit der Checker Framework-Implementierung.

Wenn Sie das Checker Framework nicht verwenden möchten, ist das javax.annotation( JSR-305 ) vorerst immer noch die beste Wahl.

Wenn Sie bereit sind, sich in das Checker Framework einzukaufen, verwenden Sie einfach deren org.checkerframework.checker.nullness.qual.


Quellen

  • android.support.annotation von android-5.1.1_r1.jar
  • edu.umd.cs.findbugs.annotations von findbugs-annotations-1.0.0.jar
  • org.eclipse.jdt.annotation von org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
  • org.jetbrains.annotations von jetbrains-annotations-13.0.jar
  • javax.annotation von gwt-dev-2.5.1-sources.jar
  • org.checkerframework.checker.nullness.qual von checker-framework-2.1.9.zip
  • lombokvon lombokCommitf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
  • javax.validation.constraints von validation-api-1.0.0.GA-sources.jar
Ludwig Weinzierl
quelle
7
Der Nachteil von javax.annotationist, dass es a) auf einem toten JSR basiert, b) schwer zu finden ist, ein Artefakt, das nur die Anmerkungen liefert und beibehalten wird. Der von findbugs ist nicht: search.maven.org/…
robinst
18
Ein weiterer Punkt dagegen javax.annotationist, dass es Probleme mit Java 9 verursacht, da andere Module ebenfalls Klassen in diesem Paket bereitstellen (jax-ws).
Robinst
10
@kevinarpe: Das Findbugs-Projekt ist tot, und das Nachfolgeprojekt Spotbugs entfernt diese Anmerkungen: github.com/spotbugs/spotbugs/pull/180
robinst
4
JSR 305 , das standardisiert worden wäre javax.annotation.NonNull, wurde nie fertiggestellt, da sein Spezifikationsvorsprung AWOL ging. Es hatte nichts mit einer Entscheidung von Oracle zu tun.
Mark Reinhold
5
Ein weiterer Grund, jsr305.jar nicht zu verwenden, ist, dass es anscheinend die Oracle Java-Binärlizenz verletzt: github.com/google/guava/issues/2960
Flow
91

Ich mag das Checker Framework sehr , eine Implementierung von Typanmerkungen ( JSR-308 ), mit der Fehlerprüfer wie ein Nullheitsprüfer implementiert werden. Ich habe nicht wirklich versucht, einen Vergleich anzubieten, aber ich war mit dieser Implementierung zufrieden.

Ich bin nicht mit der Gruppe verbunden, die die Software anbietet, aber ich bin ein Fan.

Vier Dinge, die ich an diesem System mag:

  1. Es hat eine Fehlerprüfung für die Nichtigkeit (@Nullable), aber auch eine für Unveränderlichkeit und Internierung (und andere). Ich benutze die erste (Nullheit) und versuche, die zweite (Unveränderlichkeit / IGJ) zu verwenden. Ich probiere das dritte aus, bin mir aber noch nicht sicher, ob ich es langfristig einsetzen soll. Ich bin noch nicht von der allgemeinen Nützlichkeit der anderen Prüfer überzeugt, aber es ist schön zu wissen, dass das Framework selbst ein System zur Implementierung einer Vielzahl zusätzlicher Anmerkungen und Prüfer ist.

  2. Das Standardeinstellung für die Nullheitsprüfung funktioniert gut: Nicht null außer Einheimischen (NNEL). Grundsätzlich bedeutet dies, dass der Prüfer standardmäßig alles (Instanzvariablen, Methodenparameter, generische Typen usw.) mit Ausnahme lokaler Variablen so behandelt, als hätten sie standardmäßig den Typ @NonNull. Gemäß der Dokumentation:

    Die NNEL-Standardeinstellung führt zu der geringsten Anzahl expliziter Anmerkungen in Ihrem Code.

    Sie können einen anderen Standard für eine Klasse oder eine Methode festlegen, wenn NNEL für Sie nicht funktioniert.

  3. Mit diesem Framework können Sie verwenden, ohne eine Abhängigkeit vom Framework zu erstellen, indem Sie Ihre Anmerkungen in einen Kommentar einfügen: z /*@Nullable*/. Dies ist hilfreich, da Sie eine Bibliothek oder einen gemeinsam genutzten Code mit Anmerkungen versehen und überprüfen können, diese Bibliothek / diesen gemeinsam genutzten Code jedoch weiterhin in einem anderen Projekt verwenden können, das das Framework nicht verwendet. Dies ist eine schöne Funktion. Ich habe mich daran gewöhnt, es zu verwenden, obwohl ich das Checker Framework jetzt für alle meine Projekte aktiviere.

  4. Das Framework bietet eine Möglichkeit, von Ihnen verwendete APIs zu kommentieren , die nicht bereits mit Stub-Dateien auf Null gesetzt wurden.

Bert F.
quelle
3
Scheint großartig und ich würde es gerne benutzen, kann es aber nicht. Warum GPL? Könnte es nicht stattdessen die LGPL sein?
Burkhard
13
In den häufig gestellten Fragen heißt es : "Die freizügigere MIT-Lizenz gilt für Code, den Sie möglicherweise in Ihr eigenes Programm aufnehmen möchten, z. B. die Anmerkungen."
Seanf
1
Die Links sind derzeit defekt. Aber +1 für den Rat zur Verwendung von Checker Framework.
Paul Wagland
1
Es ist schade, dass die Unveränderlichkeitsprüfer in der neuesten Version fallengelassen wurden.
Franklin Yu
1
Checker Framework wird auch in Oracle Java Tutorials empfohlen .
Quazi Irfan
55

Ich benutze die IntelliJ, weil ich mich hauptsächlich mit der Kennzeichnung von Dingen befasse, die eine NPE erzeugen könnten. Ich stimme zu, dass es frustrierend ist, keine Standardanmerkung im JDK zu haben. Es ist die Rede davon, es hinzuzufügen, es könnte es in Java 7 schaffen. In diesem Fall wird es eine weitere geben, aus der Sie auswählen können!

Sam Barnum
quelle
68
Update: IntelliJ unterstützt jetzt alle oben genannten Anmerkungen zur Code-Hervorhebung, sodass Sie nicht mehr auf die Anmerkungen von IntelliJ beschränkt sind: blogs.jetbrains.com/idea/2011/03/…
Daniel Alexiuc
31
Und Eclipse Juno auch!
jFrenetic
5
javax.annotation.Nonnullwird allgemein akzeptiert, nicht wahr?
Martin
1
@ DanielAlexiuc Aber leider verwendet es sie nicht für seine Laufzeitprüfungen, so dass es immer noch einen Vorteil hat, die JetBrains zu verwenden ...
Trejkaz
4
@Trejkaz Seit 2016.3 werden Laufzeitprüfungen für alle diese erstellt.
Karol S
32

Gemäß der Java 7-Funktionsliste werden Anmerkungen vom Typ JSR-308 auf Java 8 verschoben. Anmerkungen vom Typ JSR-305 werden nicht einmal erwähnt.

In einem Anhang des neuesten JSR-308-Entwurfs finden Sie einige Informationen zum Status von JSR-305 . Dies schließt die Beobachtung ein, dass JSR-305-Anmerkungen offenbar aufgegeben werden. Die JSR-305-Seite zeigt es auch als "inaktiv" an.

In der Zwischenzeit besteht die pragmatische Antwort darin, die Annotationstypen zu verwenden, die von den am häufigsten verwendeten Tools unterstützt werden ... und bereit zu sein, sie zu ändern, wenn sich die Situation ändert.


Tatsächlich definiert JSR-308 keine Annotationstypen / -klassen, und es sieht so aus, als ob sie denken, dass dies außerhalb des Gültigkeitsbereichs liegt. (Und sie haben Recht, angesichts der Existenz von JSR-305).

Wenn JSR-308 jedoch wirklich so aussieht, als würde es in Java 8 aufgenommen, würde es mich nicht überraschen, wenn das Interesse an JSR-305 wiederbelebt würde. AFAIK, das JSR-305-Team hat seine Arbeit nicht offiziell aufgegeben. Sie sind gerade seit 2+ Jahren still.

Es ist interessant, dass Bill Pugh (der technische Leiter für JSR-305) einer der Typen hinter FindBugs ist.

Stephen C.
quelle
4
@pst - der aktuelle Zeitplan ist, dass Java 8 im September 2013 zur allgemeinen Veröffentlichung kommt - infoq.com/news/2012/04/jdk-8-milestone-release-dates
Stephen C
2
Das ist jetzt auf März 2014 gerutscht - openjdk.java.net/projects/jdk8 . JSR 308 ist in Build M7 enthalten (siehe "104 - Anmerkungen zu Java-Typen").
Stephen C
28

Für Android-Projekte sollten Sie android.support.annotation.NonNullund verwenden android.support.annotation.Nullable. Diese und andere hilfreiche Android-spezifische Anmerkungen finden Sie in der Support-Bibliothek .

Von http://tools.android.com/tech-docs/support-annotations :

Die Support-Bibliothek selbst wurde ebenfalls mit diesen Annotationen versehen. Als Benutzer der Support-Bibliothek überprüft Android Studio bereits Ihren Code und kennzeichnet potenzielle Probleme anhand dieser Annotationen.

James Wald
quelle
3
Es wäre nützlich, diese Empfehlung zu begründen.
Aprikose
2
tools.android.com/tech-docs/support-annotations "Die Support-Bibliothek selbst wurde ebenfalls mit diesen Annotationen versehen. Als Benutzer der Support-Bibliothek überprüft Android Studio bereits Ihren Code und kennzeichnet potenzielle Probleme anhand dieser Annotationen . "
James Wald
3
BTW Android Studio unterstützt jsr305 auch mit javax.annotation.*Anmerkungen
CAMOBAP
19

Wenn jemand nur nach den IntelliJ-Klassen sucht: Sie können sie aus dem Maven-Repository mit abrufen

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 
Bruno Eberhard
quelle
Dies ist derjenige, der Intellij veranlasst, Warnungen auszulösen, yep.
Klicken Sie auf Upvote
Aktuelle Version (Stand 05/2017) ist 15.0
BamaPookie
Ihr Recht. Ich habe die Version aktualisiert. Auch wenn ich denke, es hat sich nicht viel geändert.
Bruno Eberhard
Beachten Sie, dass die JetBrains-Annotationen nicht zur Laufzeit beibehalten werden, sodass die Unterstützung von Guice @Nullable beispielsweise nicht damit funktioniert.
Peter Major
18

JSR305 und FindBugs wurden von derselben Person verfasst. Beide sind schlecht gewartet, aber so Standard wie es nur geht und werden von allen wichtigen IDEs unterstützt. Die gute Nachricht ist, dass sie so funktionieren, wie sie sind.

Hier erfahren Sie, wie Sie @Nonnull standardmäßig auf alle Klassen, Methoden und Felder anwenden. Siehe https://stackoverflow.com/a/13319541/14731 und https://stackoverflow.com/a/9256595/14731

  1. Definieren @NotNullByDefault
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;


    /**
     * This annotation can be applied to a package, class or method to indicate that the class fields,
     * method return types and parameters in that element are not null by default unless there is: <ul>
     * <li>An explicit nullness annotation <li>The method overrides a method in a superclass (in which
     * case the annotation of the corresponding parameter in the superclass applies) <li> there is a
     * default parameter annotation applied to a more tightly nested element. </ul>
     * <p/>
     * @see https://stackoverflow.com/a/9256595/14731
     */
    @Documented
    @Nonnull
    @TypeQualifierDefault(
    {
        ElementType.ANNOTATION_TYPE,
        ElementType.CONSTRUCTOR,
        ElementType.FIELD,
        ElementType.LOCAL_VARIABLE,
        ElementType.METHOD,
        ElementType.PACKAGE,
        ElementType.PARAMETER,
        ElementType.TYPE
    })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NotNullByDefault
    {
    }

2. Fügen Sie jedem Paket die Anmerkung hinzu: package-info.java

@NotNullByDefault
package com.example.foo;

UPDATE : Ab dem 12. Dezember 2012 ist JSR 305 als "ruhend" aufgeführt. Laut Dokumentation:

Eine JSR, die vom Exekutivkomitee als "ruhend" gewählt wurde oder die das Ende ihrer natürlichen Lebensdauer erreicht hat.

Es sieht aus wie JSR 308 ist es in JDK 8 zu machen , und obwohl die JSR @NotNull nicht definieren, die begleitend Checkers Frameworktut. Zum Zeitpunkt dieses Schreibens ist das Maven-Plugin aufgrund dieses Fehlers unbrauchbar: https://github.com/typetools/checker-framework/issues/183

Gili
quelle
2
Das Showstopper-Problem für Maven wurde behoben. Dies sollte also wieder eine Option sein.
Marc von Renteln
Ich verwende FindBugs über Maven. Meine IDE erledigt nichts. Dadurch werden IDE-spezifische Anmerkungen vermieden. Was würden Sie empfehlen?
Christophe Roussy
@ChristopheRoussy Ihre Frage ist IDE-spezifisch. Bitte öffnen Sie eine separate Frage.
Gili
15

Unterscheiden Sie zwischen statischer Analyse und Laufzeitanalyse. Verwenden Sie die statische Analyse für interne Inhalte und die Laufzeitanalyse für die öffentlichen Grenzen Ihres Codes.

Für Dinge, die nicht null sein sollten:

  • Laufzeitprüfung: Verwenden Sie "if (x == null) ..." (Nullabhängigkeit) oder @ javax.validation.NotNull (mit Bean-Validierung) oder @ lombok.NonNull (schlicht und einfach) oder Guaven Preconditions.checkNotNull (.. .)

    • Verwenden Sie Optional für Methodenrückgabetypen (nur). Entweder Java8 oder Guava.
  • Statische Prüfung: Verwenden Sie eine Annotation @NonNull

  • Verwenden Sie @ ... NonnullByDefault-Anmerkungen auf Klassen- oder Paketebene, wo es passt. Erstellen Sie diese Anmerkungen selbst (Beispiele sind leicht zu finden).
    • Verwenden Sie andernfalls @ ... CheckForNull für Methodenrückgaben, um NPEs zu vermeiden

Dies sollte das beste Ergebnis liefern: Warnungen in der IDE, Fehler von Findbugs und checkerframework, sinnvolle Laufzeitausnahmen.

Erwarten Sie nicht, dass statische Prüfungen ausgereift sind, ihre Benennung nicht standardisiert ist und verschiedene Bibliotheken und IDEs sie unterschiedlich behandeln, ignorieren Sie sie. Die JSR305-Klassen javax.annotations. * Sehen wie Standard aus, sind es jedoch nicht und verursachen Split-Pakete mit Java9 +.

Einige Anmerkungen Erklärungen:

  • Findbugs / spotbugs / jsr305-Annotationen mit dem Paket javax.validation. * Kollidieren mit anderen Modulen in Java9 + und verletzen möglicherweise auch die Oracle-Lizenz
  • Spotbugs-Annotationen hängen immer noch von jsr305 / findbugs-Annotationen zur Kompilierungszeit ab (zum Zeitpunkt des Schreibens von https://github.com/spotbugs/spotbugs/issues/421 ).
  • Der Name @NotNull von jetbrains steht in Konflikt mit @ javax.validation.NotNull.
  • Jetbrains-, Eclipse- oder Checkersframework-Annotationen für die statische Überprüfung haben gegenüber javax.annotations den Vorteil, dass sie nicht mit anderen Modulen in Java9 und höher kollidieren
  • @ javax.annotations.Nullable bedeutet für Findbugs / Spotbugs nicht, was Sie (oder Ihre IDE) denken, dass es bedeutet. Findbugs ignorieren dies (bei Mitgliedern). Traurig, aber wahr ( https://sourceforge.net/p/findbugs/bugs/1181 )
  • Für die statische Überprüfung außerhalb einer IDE stehen zwei kostenlose Tools zur Verfügung: Spotbugs (ehemals Findbugs) und checkersframework.
  • Die Eclipse-Bibliothek hat @NonNullByDefault, jsr305 hat nur @ParametersAreNonnullByDefault. Dies sind lediglich Convenience-Wrapper, die Basisanmerkungen auf alles in einem Paket (oder einer Klasse) anwenden. Sie können ganz einfach Ihre eigenen erstellen. Dies kann auf Paket verwendet werden. Dies kann zu Konflikten mit dem generierten Code (z. B. Lombok) führen.
  • Die Verwendung von Lombok als exportierte Abhängigkeit sollte für Bibliotheken vermieden werden, die Sie mit anderen Personen teilen. Je weniger transitive Abhängigkeiten, desto besser
  • Die Verwendung des Bean-Validierungsframeworks ist leistungsstark, erfordert jedoch einen hohen Overhead. Dies ist ein Overkill, um eine manuelle Nullprüfung zu vermeiden.
  • Die Verwendung von Optional für Felder und Methodenparameter ist umstritten (Artikel dazu finden Sie leicht).
  • Android-Nullanmerkungen sind Teil der Android-Unterstützungsbibliothek, enthalten viele andere Klassen und lassen sich nicht gut mit anderen Anmerkungen / Tools kombinieren

Vor Java9 ist dies meine Empfehlung:

// file: package-info.java
@javax.annotation.ParametersAreNonnullByDefault
package example;


// file: PublicApi
package example;

public interface PublicApi {

    Person createPerson(
        // NonNull by default due to package-info.java above
        String firstname,
        String lastname);
}

// file: PublicApiImpl
public class PublicApiImpl implements PublicApi {
    public Person createPerson(
            // In Impl, handle cases where library users still pass null
            @Nullable String firstname, // Users  might send null
            @Nullable String lastname // Users might send null
            ) {
        if (firstname == null) throw new IllagalArgumentException(...);
        if (lastname == null) throw new IllagalArgumentException(...);
        return doCreatePerson(fistname, lastname, nickname);
    }

    @NonNull // Spotbugs checks that method cannot return null
    private Person doCreatePerson(
             String firstname, // Spotbugs checks null cannot be passed, because package has ParametersAreNonnullByDefault
             String lastname,
             @Nullable String nickname // tell Spotbugs null is ok
             ) {
         return new Person(firstname, lastname, nickname);
    }

    @CheckForNull // Do not use @Nullable here, Spotbugs will ignore it, though IDEs respect it
    private Person getNickname(
         String firstname,
         String lastname) {
         return NICKNAMES.get(firstname + ':' + lastname);
    }
}

Beachten Sie, dass es keine Möglichkeit gibt, Spotbugs dazu zu bringen, eine Warnung auszulösen, wenn ein nullfähiger Methodenparameter dereferenziert wird (zum Zeitpunkt des Schreibens Version 3.1 von Spotbugs). Vielleicht kann checkerframework das tun.

Leider unterscheiden diese Anmerkungen nicht zwischen den Fällen einer öffentlichen Methode einer Bibliothek mit beliebigen Aufrufseiten und nicht öffentlichen Methoden, bei denen jede Aufrufstelle bekannt sein kann. Die doppelte Bedeutung von: "Geben Sie an, dass null unerwünscht ist, aber bereiten Sie sich dennoch darauf vor, dass null übergeben wird" ist in einer einzelnen Deklaration nicht möglich. Daher enthält das obige Beispiel unterschiedliche Anmerkungen für die Schnittstelle und die Implementierung.

In Fällen, in denen der Split-Interface-Ansatz nicht praktikabel ist, ist der folgende Ansatz ein Kompromiss:

        public Person createPerson(
                @NonNull String firstname,
                @NonNull String lastname
                ) {
            // even though parameters annotated as NonNull, library clients might call with null.
            if (firstname == null) throw new IllagalArgumentException(...);
            if (lastname == null) throw new IllagalArgumentException(...);
            return doCreatePerson(fistname, lastname, nickname);
        }

Dies hilft den Clients, nicht null zu übergeben (korrekten Code zu schreiben) und in diesem Fall nützliche Fehler zurückzugeben.

tkruse
quelle
Ich habe diese Antwort erst jetzt gefunden, aber @tkruse, wo haben Sie diese gefunden: "Eclipse-JDT-Annotationen gelten nicht für statische Methodenrückgaben und einige andere Fälle"? (Der erste Teil ist nicht wahr, der zweite ziemlich vage :)).
Stephan Herrmann
@StephanHerrmann: Ich kann mich nicht erinnern. Ich habe den Aufzählungspunkt entfernt.
tkruse
12

Eclipse hat auch eigene Anmerkungen.

org.eclipse.jdt.annotation.NonNull

Weitere Informationen finden Sie unter http://wiki.eclipse.org/JDT_Core/Null_Analysis .

Horkrux7
quelle
Es sieht so aus, als würde dies aus Eclipse 3.8 (Juno) integriert, wodurch Eclipse in dieser Hinsicht mit IntelliJ in Einklang gebracht wird. Außerdem sollten Sie damit Ihre eigenen Null-Annotationen konfigurieren können (z. B. javax.annotation.Nonnull) und NotNull als Standard festlegen können.
Motti Strom
11

Ich möchte nur darauf hinweisen, dass die Java Validation API ( javax.validation.constraints.*) keine @NullableAnmerkung enthält, was in einem statischen Analysekontext sehr wertvoll ist. Dies ist für die Laufzeit-Bean-Validierung sinnvoll, da dies die Standardeinstellung für nicht primitive Felder in Java ist (dh nichts, was validiert / erzwungen werden muss). Für die angegebenen Zwecke sollte das in Richtung der Alternativen abwägen.

Ophir Radnitz
quelle
7

Leider JSR 308werden hier nicht mehr Werte als in diesem Projekt hinzugefügt

Java 8wird nicht mit einer einzigen Standardanmerkung oder einem eigenen CheckerFramework geliefert. Ähnlich wie bei Find-Bugs oder JSR 305wird dieser JSR von einer kleinen Gruppe überwiegend akademischer Teams schlecht gepflegt.

Keine kommerzielle Macht dahinter, JSR 308startet daher EDR 3(Early Draft Review at JCP) JETZT, Java 8soll aber in weniger als 6 Monaten 310versendet werden : -O Ähnlich wie übrigens. Im Gegensatz dazu 308 Oraclehat sich das jetzt von seinen Gründern übernommen, um den Schaden für die Java-Plattform so gering wie möglich zu halten.

Jedes Projekt, jeder Anbieter und jede akademische Klasse, wie die hinter dem Checker Frameworkund JSR 308erstellt eine eigene Prüferanmerkung.

Quellcode für die kommenden Jahre inkompatibel machen, bis einige beliebte Kompromisse gefunden und möglicherweise zu Java 9oder 10oder über Frameworks wie Apache Commonsoder hinzugefügt werden konnten Google Guava;-)

Werner Keil
quelle
7

Android

Diese Antwort ist Android-spezifisch. Android hat Support-Paket namens support-annotations. Dies bietet Dutzende von Android-spezifischen Anmerkungen und häufig verwendete wie NonNull:Nullable usw.

Fügen Sie zum Hinzufügen des Support-Annotations- Pakets die folgende Abhängigkeit in Ihr build.gradle ein:

compile 'com.android.support:support-annotations:23.1.1'

und dann benutze:

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}
Shubham Chaudhary
quelle
5

Während Sie darauf warten, dass dies vorgelagert wird (Java 8?), Können Sie auch einfach Ihre eigenen projektlokalen @NotNullund @NullableAnmerkungen definieren. Dies kann auch nützlich sein, wenn Sie mit Java SE arbeiten, wo javax.validation.constraints es standardmäßig nicht verfügbar ist.

import java.lang.annotation.*;

/**
 * Designates that a field, return value, argument, or variable is
 * guaranteed to be non-null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface NotNull {}

/**
 * Designates that a field, return value, argument, or variable may be null.
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Documented
@Retention(RetentionPolicy.CLASS)
public @interface Nullable {}

Dies wäre zugegebenermaßen größtenteils zu dekorativen oder zukunftssicheren Zwecken, da das oben Gesagte offensichtlich an und für sich keine Unterstützung für die statische Analyse dieser Anmerkungen bietet.

Arto Bendiken
quelle
4

Wenn Sie für Android entwickeln, sind Sie etwas an Eclipse gebunden (bearbeiten: zum Zeitpunkt des Schreibens nicht mehr), das seine eigenen Anmerkungen hat. Es ist in Eclipse 3.8+ (Juno) enthalten, aber standardmäßig deaktiviert.

Sie können es unter Einstellungen> Java> Compiler> Fehler / Warnungen> Nullanalyse aktivieren (reduzierbarer Abschnitt unten).

Aktivieren Sie "Annotationsbasierte Nullanalyse aktivieren".

http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage enthält Empfehlungen zu Einstellungen. Wenn Sie jedoch externe Projekte in Ihrem Arbeitsbereich haben (wie das Facebook-SDK), erfüllen diese möglicherweise nicht diese Empfehlungen, und Sie möchten sie wahrscheinlich nicht bei jedem SDK-Update beheben ;-)

Ich benutze:

  1. Nullzeigerzugriff: Fehler
  2. Verletzung der Nullspezifikation: Fehler (verknüpft mit Punkt 1)
  3. Möglicher Nullzeigerzugriff: Warnung (andernfalls würde das Facebook SDK Warnungen enthalten)
  4. Konflikt zwischen Null-Annotationen und Null-Inferenz: Warnung (verknüpft mit Punkt 3)
Chaqke
quelle
4
an Eclipse gebunden? Nicht wahr.
dcow
1
@DavidCowden IntelliJ IDEA mit Unterstützung für Android-Entwicklung war meiner Meinung nach einige Zeit verfügbar, bevor AndroidStudio eingeführt wurde.
Mārtiņš Briedis
@ MārtiņšBriedis ja, das stimmt. Ich denke du meintest @chaqke.
dcow
Es ist erwähnenswert, dass Android und Intellij separate Anmerkungen haben und dies wahrscheinlich auch bleiben werden, bis Java offizielle Anmerkungen enthält. Dies sind Anweisungen zur Verwendung der Anmerkungen von Eclipse mit Eclipse.
Chaqke
Es war noch nie an Eclipse gebunden. Sie können jede gewünschte IDE verwenden.
DennisK
4

Wenn Sie an einem großen Projekt arbeiten, ist es möglicherweise besser, eigene @Nullable und / oder @NotNullAnmerkungen zu erstellen .

Zum Beispiel:

@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
@java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD,
                              java.lang.annotation.ElementType.METHOD,    
                              java.lang.annotation.ElementType.PARAMETER,
                              java.lang.annotation.ElementType.LOCAL_VARIABLE})
public @interface Nullable 
{
}

Wenn Sie die richtige Aufbewahrungsrichtlinie verwenden , sind die Anmerkungen zur Laufzeit nicht verfügbar . Aus dieser Sicht ist es nur eine interne Sache.

Obwohl dies keine strenge Wissenschaft ist, halte ich es für am sinnvollsten, eine interne Klasse dafür zu verwenden.

  • Es ist eine innere Sache. (keine funktionalen oder technischen Auswirkungen)
  • Mit vielen, vielen, vielen Verwendungen.
  • IDEs wie IntelliJ unterstützen benutzerdefinierte @Nullable/ @NotNullAnmerkungen.
  • Die meisten Frameworks bevorzugen auch die Verwendung ihrer eigenen internen Version.

Zusätzliche Fragen (siehe Kommentare):

Wie konfiguriere ich das in IntelliJ?

Klicken Sie auf den "Polizisten" in der unteren rechten Ecke der IntelliJ-Statusleiste. Klicken Sie im Popup auf "Inspektionen konfigurieren". Nächster ... Anmerkungen konfigurieren

bvdb
quelle
1
Ich habe Ihren Rat ausprobiert, aber ideanichts darüber erzählt void test(@NonNull String s) {}, vontest(null);
user1244932
3
@ user1244932 Meinst du IntelliJ IDEA? Sie können die Nullabilitätsanmerkungen konfigurieren, die für die statische Analyse verwendet werden. Ich weiß nicht genau, wo, aber ein Ort, an dem ich sie definieren kann, ist "Datei> Einstellungen> Erstellen, Ausführen, Bereitstellen> Compiler" und dort befindet sich eine Schaltfläche "Anmerkungen konfigurieren ...".
Adowrath
@ user1244932 siehe Screenshot, wenn Sie noch danach suchen.
Bvdb
3

Es gibt hier bereits zu viele Antworten, aber (a) es ist 2019 und es gibt immer noch keinen "Standard" Nullableund (b) keine anderen Antwortreferenzen Kotlin.

Der Verweis auf Kotlin ist wichtig, da Kotlin zu 100% mit Java interoperabel ist und über eine zentrale Null-Sicherheitsfunktion verfügt. Beim Aufrufen von Java-Bibliotheken können diese Anmerkungen genutzt werden, um Kotlin-Tools darüber zu informieren, ob eine Java-API akzeptieren oder zurückgeben kann null.

Soweit ich weiß, Nullablesind org.jetbrains.annotationsund android.support.annotation(jetzt androidx.annotation) die einzigen mit Kotlin kompatiblen Pakete . Letzteres ist nur mit Android kompatibel und kann daher nicht in Nicht-Android-JVM / Java / Kotlin-Projekten verwendet werden. Das JetBrains-Paket funktioniert jedoch überall.

Wenn Sie also Java-Pakete entwickeln, die auch in Android und Kotlin funktionieren sollten (und von Android Studio und IntelliJ unterstützt werden), ist das JetBrains-Paket wahrscheinlich die beste Wahl.

Maven:

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations-java5</artifactId>
    <version>15.0</version>
</dependency>

Gradle:

implementation 'org.jetbrains:annotations-java5:15.0'
noamtm
quelle
2
Hmm, das sagt etwas anderes: kotlinlang.org/docs/reference/…
skagedal
3

Es gibt eine andere Möglichkeit, dies in Java 8 zu tun. Ich mache zwei Dinge, um das zu erreichen, was ich brauchte:

  1. Nullbare Felder mit Typen explizit machen, indem nullbare Felder mit umbrochen werden java.util.Optional
  2. Überprüfen, ob alle nicht nullbaren Felder zum Zeitpunkt der Erstellung mit null sind java.util.Objects.requireNonNull

Beispiel:

import static java.util.Objects.requireNonNull;

public class Role {

  private final UUID guid;
  private final String domain;
  private final String name;
  private final Optional<String> description;

  public Role(UUID guid, String domain, String name, Optional<String> description) {
    this.guid = requireNonNull(guid);
    this.domain = requireNonNull(domain);
    this.name = requireNonNull(name);
    this.description = requireNonNull(description);
  }

Meine Frage ist also, müssen wir bei der Verwendung von Java 8 überhaupt Anmerkungen machen?

Bearbeiten: Ich fand später heraus, dass einige eine schlechte Praxis für die Verwendung Optionalin Argumenten in Betracht ziehen. Hier gibt es eine gute Diskussion mit Vor- und Nachteilen. Warum sollte Java 8's Optional nicht in Argumenten verwendet werden?

Alternative Option, da die Verwendung von Optional in Argumenten nicht empfohlen wird, benötigen wir 2 Konstruktoren:

  //Non null description
  public Role(UUID guid, String domain, String name, String description) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);

        // description will never be null
        requireNonNull(description);

        // but wrapped with an Optional
        this.description = Optional.of(description);
      }

  // Null description is assigned to Optional.empty
  public Role(UUID guid, String domain, String name) {
        this.guid = requireNonNull(guid);
        this.domain = requireNonNull(domain);
        this.name = requireNonNull(name);
        this.description = Optional.empty();
      }
Mozart Brocchini
quelle
Ich würde sagen, Sie benötigen immer noch die Annotation @NotNull für alle 4 formalen Parameter, damit statische Analyseprüfer Ihre Absicht kennen, dass keine null sein sollte. Es gibt noch nichts in der Java-Sprache, was dies erzwingt. Sie sollten auch überprüfen, ob die Beschreibung nicht null ist, wenn Sie defensiv programmieren.
Jaxzin
2
Ich kann diesen Code immer noch schreiben : new Role(null,null,null,null);. Mit den Anmerkungen warnt meine IDE und statische Analyse, dass null nicht an diese Parameter übergeben werden kann. Ohne es finde ich es nicht heraus, bis ich den Code ausführe. Das ist der Wert der Anmerkungen.
Jaxzin
2
Ich bin auch in Umgebungen, in denen Entwickler jede IDE oder jeden Texteditor verwenden können, die sie bevorzugen, da sie sich nicht gegenseitig ausschließen. Anschließend integrieren wir auch das maven-pmd-Plugin und / oder SonarQube in den Erstellungsprozess, um Probleme mit der Codequalität vor dem Zusammenführen zu fördern, hervorzuheben und sogar zu beheben, beispielsweise bei Pull-Anforderungen.
Jaxzin
2
Optional ist nicht als Methodenargument oder privates Feld gedacht. Siehe zum Beispiel: stuartmarks.wordpress.com/2016/09/27/vjug24-session-on-optional
assylias
1
@assylias ja, das habe ich später herausgefunden, sie sagen, es wird nicht empfohlen, weil es uns nichts kaufen wird, ich kann definitiv ihre Vernunft verstehen. In diesem Fall könnte ich das Argument description nicht null machen und der Client-Code könnte einen leeren String übergeben, aber in vielen Fällen könnte es nützlich sein, zwischen einem leeren String zu unterscheiden und keinen Wert zu haben. Vielen Dank für Ihren Kommentar. Ich werde die Antwort aktualisieren.
Mozart Brocchini
2

Hat die Sonne jetzt keine eigene? Was ist das:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm

Dies scheint mit allen Java-Versionen gepackt zu sein, die ich in den letzten Jahren verwendet habe.

Bearbeiten: Wie in den Kommentaren unten erwähnt, möchten Sie diese wahrscheinlich nicht verwenden. In diesem Fall stimme ich für die Anmerkungen zu IntelliJ Jetbrains!

Nate W.
quelle
10
Ich habe keine Ahnung, was es ist, aber der Paketname sollte ein großer Hinweis darauf sein, dass er NICHT für den allgemeinen Gebrauch bestimmt ist.
Stephen C
3
Normalerweise verzichtet man auf die Verwendung von Klassen im com.sun-Namespace, da diese intern sind. nicht für den direkten Gebrauch bestimmt; und ohne Garantie für ihre zukünftige Verfügbarkeit oder ihr zukünftiges Verhalten. Man muss einen wirklich soliden Fall haben, um ein com.sun-Artefakt direkt zu verwenden.
Luis.espinal
plus etwas, das in solch einem schlechten HTML-Format angezeigt wird (auf Java2s.com, um das Ganze abzurunden), sollte Ihnen einige rote Fahnen geben :)
luis.espinal
2

Eines der schönen Dinge an IntelliJ ist, dass Sie ihre Anmerkungen nicht verwenden müssen. Sie können Ihre eigenen schreiben oder die eines beliebigen anderen Tools verwenden. Sie sind nicht einmal auf einen einzigen Typ beschränkt. Wenn Sie zwei Bibliotheken verwenden, die unterschiedliche @ NotNull-Annotationen verwenden, können Sie IntelliJ anweisen, beide zu verwenden. Gehen Sie dazu zu "Inspektionen konfigurieren", klicken Sie auf die Inspektion "Konstante Bedingungen und Ausnahmen" und klicken Sie auf die Schaltfläche "Inspektionen konfigurieren". Ich verwende den Nullness Checker, wo immer ich kann, und richte IntelliJ so ein, dass diese Anmerkungen verwendet werden. Sie können ihn jedoch mit jedem anderen gewünschten Tool verwenden. (Ich habe keine Meinung zu den anderen Tools, da ich seit Jahren die Inspektionen von IntelliJ verwende und sie liebe.)

MiguelMunoz
quelle
1

Eine weitere Option sind die mit ANTLR 4 bereitgestellten Anmerkungen. Nach der Pull-Anforderung Nr. 434 enthält das Artefakt, das die Anmerkungen @NotNullund @Nullableenthält, einen Anmerkungsprozessor, der Fehler und / oder Warnungen zur Kompilierungszeit erzeugt, falls eines dieser Attribute missbraucht wird (z. B. wenn beide werden auf dasselbe Element @Nullableangewendet oder wenn es auf ein Element mit einem primitiven Typ angewendet wird). Der Anmerkungsprozessor bietet während des Softwareentwicklungsprozesses zusätzliche Sicherheit, dass die durch die Anwendung dieser Anmerkungen übermittelten Informationen korrekt sind, auch in Fällen von Methodenvererbung.

Sam Harwell
quelle
1

Wenn Sie Ihre Anwendung mit Spring Framework erstellen, würde ich die Verwendung von javax.validation.constraints.NotNullComming from Beans Validation empfehlen, das in der folgenden Abhängigkeit verpackt ist:

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>

Der Hauptvorteil dieser Annotation besteht darin, dass Spring sowohl Methodenparameter als auch mit Annotationen versehene Klassenfelder unterstützt javax.validation.constraints.NotNull. Alles, was Sie tun müssen, um den Support zu aktivieren, ist:

  1. Stellen Sie das API-JAR für die Beans-Validierung und das JAR mit der Implementierung des Validators für jsr-303 / jsr-349-Annotationen bereit (die mit der Abhängigkeit von Hibernate Validator 5.x geliefert werden):

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.4.1.Final</version>
    </dependency>
  2. Stellen Sie MethodValidationPostProcessor für den Spring-Kontext bereit

      @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
  3. Schließlich kommentieren Sie Ihre Klassen mit Spring's org.springframework.validation.annotation.Validatedund die Validierung wird automatisch von Spring durchgeführt.

Beispiel:

@Service
@Validated
public class MyServiceImpl implements MyService {

  @Override
  public Something doSomething(@NotNull String myParameter) {
        // No need to do something like assert myParameter != null  
  }
}

Wenn Sie versuchen, die Methode doSomething aufzurufen und null als Parameterwert zu übergeben, wird spring (mithilfe von HibernateValidator) ausgelöst ConstraintViolationException. Hier ist keine manuelle Arbeit erforderlich.

Sie können auch Rückgabewerte überprüfen.

Ein weiterer wichtiger Vorteil von javax.validation.constraints.NotNullComming for Beans Validation Framework besteht darin, dass es derzeit noch entwickelt wird und neue Funktionen für die neue Version 2.0 geplant sind.

Was ist mit @Nullable? In Beans Validation 1.1 gibt es nichts Vergleichbares. Nun, ich könnte argumentieren, dass, wenn Sie sich für die Verwendung entscheiden, @NotNullalles, was NICHT mit Anmerkungen versehen @NonNullist, effektiv "nullbar" ist, sodass die @NullableAnmerkung unbrauchbar ist.

Walkeros
quelle
1
Bitte benutzen Sie es nicht. Es wird zur Laufzeitüberprüfung verwendet, NICHT zur statischen Code-Analyse. Weitere Informationen finden Sie unter justsomejavaguy.blogspot.com/2011/08/… . Quelle: Gelöschte Antwort mit 219 Stimmen von @ luis.espinal.
Koppor
@koppor: Ich bin anderer Meinung. Wenn dies nicht für die Verwendung vorgesehen ist, warum sollte Spring es zur Laufzeit verarbeiten? Das Beans-Validierungsframework ermöglicht auch das Erstellen von Anmerkungen nur zur Laufzeitanalyse, da zur Laufzeit auf das Kontextobjekt (derzeit mit Anmerkungen versehene / validierte Instanz) zugegriffen werden kann.
Walkeros
0

Spring 5 hat @NonNullApi auf Paketebene. Dies scheint eine bequeme Wahl für ein Projekt zu sein, das bereits Spring-Abhängigkeiten aufweist. Alle Felder, Parameter und Rückgabewerte, die standardmäßig @NonNull und @Nullable sind, können an den wenigen Stellen angewendet werden, die sich unterscheiden.

Datei package-info.java:

@org.springframework.lang.NonNullApi
package com.acme;

https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations

Ken Jarrad
quelle