Której adnotacji @NotNull Java należy użyć?


997

Chcę uczynić mój kod bardziej czytelnym, a także użyć narzędzi takich jak kontrola kodu IDE i / lub analiza kodu statycznego (FindBugs i Sonar), aby uniknąć wyjątków NullPointerExceptions. Wiele narzędzi wydają się sprzeczne ze sobą innych @NotNull/ @NonNull/ @Nonnulladnotacji wystawianie ich wszystkich w moim kodu byłoby straszne czytać. Jakieś sugestie, który z nich jest „najlepszy”? Oto lista równorzędnych adnotacji, które znalazłem:

  • javax.validation.constraints.NotNull
    Stworzony do weryfikacji środowiska wykonawczego, a nie analizy statycznej.
    dokumentacja

  • edu.umd.cs.findbugs.annotations.NonNull
    Używany przez Findbugs analizy statycznej i dlatego Sonar (obecnie Sonarqube )
    dokumentacji

  • javax.annotation.Nonnull
    Może to również działać z Findbugs, ale JSR-305 jest nieaktywny. (Zobacz także: Jaki jest status JSR 305? ) Źródło

  • org.jetbrains.annotations.NotNull
    Używany przez IntelliJ IDEA IDE do analizy statycznej.
    dokumentacja

  • lombok.NonNull
    Służy do sterowania generowaniem kodu w Project Lombok .
    Adnotacja zastępcza, ponieważ nie ma standardu.
    źródło , dokumentacja

  • android.support.annotation.NonNull
    Adnotacja znacznika dostępna w systemie Android, dostarczona w dokumentacji pakietu wsparcia-adnotacji

  • org.eclipse.jdt.annotation.NonNull
    Używany przez Eclipse do dokumentacji statycznej analizy kodu


203
Apache powinien wymyślić „wspólną” adnotację i narzędzie, które może przekonwertować ją na dowolną inną adnotację. rozwiązaniem problemu zbyt wielu norm jest wynalezienie nowego standardu.
bezsporne

6
@irreputable, jeśli apache wymyśli nowy „wspólny”, będzie 56 wersji, pokrywających się z innymi projektami. I tak nie byłoby standardowe (standard! = Powszechne). Lepiej użyć czegoś naprawdę standardowego, javax?. *. BTW, w tych przykładach nie ma „zbyt wielu standardów”, widzę tylko 1 lub 2.
ymajoros 27.10

6
javax.annotation.Nonnull działa z findbugs (właśnie go przetestowałem), co jest dla mnie istotnym powodem, aby z niego korzystać.
Nicolas C

20
Jeśli po prostu napiszę @NotNull, odnosi się do com.sun.istack.internal.NotNull. OMG ...
Thomas Weller

3
@MozartBrocchini - Opcjonalne są przydatne w przypadkach, w których mogłeś wcześniej używać NullObjects. Jednak tak naprawdę nie zajmują się tym samym celem, co adnotacja środowiska uruchomieniowego \ @NotNull, i wprowadzają żmudne rozpakowywanie.
Dave

Odpowiedzi:


205

Ponieważ JSR 305 (którego celem była standaryzacja @NonNulli @Nullable) był nieaktywny od kilku lat, obawiam się, że nie ma dobrej odpowiedzi. Wszystko, co możemy zrobić, to znaleźć pragmatyczne rozwiązanie, a moje jest następujące:

Składnia

Z czysto stylistycznego punktu widzenia chciałbym uniknąć jakiegokolwiek odniesienia do IDE, frameworka lub jakiegokolwiek zestawu narzędzi oprócz samego Java.

Wyklucza to:

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

Który pozostawia nam albo javax.validation.constraintsalbo javax.annotation. Ten pierwszy pochodzi z JEE. Jeśli jest to lepsze niż javax.annotation, co może ostatecznie przynieść JSE lub wcale, jest kwestią do dyskusji. Osobiście wolę, javax.annotationponieważ nie chciałbym zależności JEE.

To nas zostawia

javax.annotation

który jest również najkrótszy.

Jest tylko jeden składnia co byłoby jeszcze lepiej: java.annotation.Nullable. Jak inne pakiety ukończył javaxaby javaw przeszłości javax.annotation byłby to krok we właściwym kierunku.

Realizacja

Miałem nadzieję, że wszystkie mają w zasadzie tę samą trywialną implementację, ale szczegółowa analiza wykazała, że ​​to nieprawda.

Najpierw podobieństwa:

Wszystkie @NonNulladnotacje mają linię

public @interface NonNull {}

z wyjątkiem

  • org.jetbrains.annotationsktóry to nazywa @NotNulli ma trywialną implementację
  • javax.annotation który ma dłuższą implementację
  • javax.validation.constraintsktóry również to nazywa @NotNulli ma implementację

Wszystkie @Nullableadnotacje mają linię

public @interface Nullable {}

z wyjątkiem (ponownie) org.jetbrains.annotationsz ich trywialną implementacją.

Różnice:

Uderzające jest to

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

wszystkie mają adnotacje środowiska wykonawczego ( @Retention(RUNTIME)), podczas gdy

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

są tylko czasem kompilacji ( @Retention(CLASS)).

Jak opisano w tej odpowiedzi SO, wpływ adnotacji środowiska wykonawczego jest mniejszy, niż mogłoby się wydawać, ale mają one tę zaletę, że oprócz narzędzi do kompilacji mają także możliwość przeprowadzania kontroli środowiska wykonawczego.

Inną ważną różnicą jest to, gdzie w kodzie można używać adnotacji. Istnieją dwa różne podejścia. Niektóre pakiety używają kontekstów w stylu JLS 9.6.4.1. Poniższa tabela zawiera przegląd:

                                PARAMETR METODY POLA 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.annotationI org.checkerframework.checker.nullness.qualużyć konteksty określonych w JLS 4.11, co jest moim zdaniem dobry sposób, żeby to zrobić.

To nas zostawia

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

w tej rundzie.

Kod

Aby pomóc Ci porównać dalsze szczegóły, poniżej zamieszczam kod każdej adnotacji. Aby ułatwić porównywanie, usunąłem komentarze, import i @Documentedadnotacje. (wszyscy mieli @Documentedoprócz zajęć z pakietu Androida). Zmieniłem kolejność linii i @Targetpól oraz znormalizowałem kwalifikacje.

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 {}

Dla kompletności, oto @Nullableimplementacje:

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 {}

Poniższe dwa pakiety nie mają @Nullable, więc wymieniam je osobno; Lombok jest dość nudny @NonNull. W jest w rzeczywistości i ma dość długi wdrożenia.javax.validation.constraints@NonNull@NotNull

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();
    }
}

Wsparcie

Z mojego doświadczenia javax.annotationwynika , że jest co najmniej obsługiwany przez Eclipse i Checker Framework od razu po wyjęciu z pudełka.

Podsumowanie

Moją idealną adnotacją byłaby java.annotationskładnia z implementacją Checker Framework.

Jeśli nie zamierzasz korzystać z Checker Framework, javax.annotation( JSR-305 ) jest na razie najlepszym wyborem.

Jeśli chcesz kupić w Checker Framework, skorzystaj z nich org.checkerframework.checker.nullness.qual.


Źródła

  • android.support.annotation od android-5.1.1_r1.jar
  • edu.umd.cs.findbugs.annotations od findbugs-annotations-1.0.0.jar
  • org.eclipse.jdt.annotation od org.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
  • org.jetbrains.annotations od jetbrains-annotations-13.0.jar
  • javax.annotation od gwt-dev-2.5.1-sources.jar
  • org.checkerframework.checker.nullness.qual od checker-framework-2.1.9.zip
  • lombokz lombokzatwierdzeniaf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
  • javax.validation.constraints od validation-api-1.0.0.GA-sources.jar

7
Minusem javax.annotationjest to, że a) opiera się na martwym JSR, b) ciężko znaleźć artefakt, który tylko zapewnia adnotacje i jest utrzymywany. Ten z findbugs nie jest: search.maven.org/…
robinst

18
Inną kwestią javax.annotationjest to, że powoduje problemy z Javą 9, ponieważ inne moduły również udostępniają klasy w tym pakiecie (jax-ws).
robinst

10
@kevinarpe: Projekt Findbugs nie żyje, a następca Spotbugs usuwa te adnotacje: github.com/spotbugs/spotbugs/pull/180
robinst

4
JSR 305 , który ujednoliciłby się javax.annotation.NonNull, nigdy nie został ukończony, ponieważ jego wiodąca specyfikacja przeszła AWOL. Nie miało to nic wspólnego z decyzją Oracle.
Mark Reinhold

5
Innym powodem, aby nie używać pliku jsr305.jar jest to, że najwyraźniej narusza licencję binarną Oracle Java: github.com/google/guava/issues/2960
Flow

91

Bardzo podoba mi się Checker Framework , który jest implementacją adnotacji typu ( JSR-308 ), która służy do implementacji sprawdzania defektów, takich jak sprawdzanie nullness. Tak naprawdę nie próbowałem nikogo oferować żadnego porównania, ale jestem zadowolony z tej implementacji.

Nie jestem związany z grupą, która oferuje oprogramowanie, ale jestem fanem.

Cztery rzeczy, które lubię w tym systemie:

  1. Ma sprawdzanie defektów pod kątem nieważności (@Nullable), ale ma także niezmienność i internowanie (i inne). Używam pierwszego (zerowanie) i próbuję zacząć używać drugiego (niezmienność / IGJ). Próbuję trzeciego, ale nie jestem pewien, czy będę go używać długoterminowo. Nie jestem jeszcze przekonany o ogólnej przydatności innych kontrolerów, ale miło jest wiedzieć, że sam framework jest systemem do wdrażania wielu dodatkowych adnotacji i kontrolerów.

  2. Ustawienie domyślne dla sprawdzenia nullness działa dobrze: niezerowe wyjątkiem mieszkańców (NNEL). Zasadniczo oznacza to, że domyślnie moduł sprawdzający traktuje wszystko (zmienne instancji, parametry metody, typy ogólne itp.) Oprócz zmiennych lokalnych tak, jakby miały domyślnie typ @NonNull. Według dokumentacji:

    Wartość domyślna NNEL prowadzi do najmniejszej liczby wyraźnych adnotacji w kodzie.

    Możesz ustawić inną wartość domyślną dla klasy lub metody, jeśli NNEL nie działa dla Ciebie.

  3. Framework ten pozwala na używanie bez tworzenia zależności od frameworka poprzez umieszczanie adnotacji w komentarzu: np /*@Nullable*/. Jest to miłe, ponieważ możesz dodawać adnotacje i sprawdzać bibliotekę lub kod współdzielony, ale nadal możesz korzystać z tej biblioteki / kodu współdzielonego w innym projekcie, który nie korzysta z frameworka. To miła funkcja. Przyzwyczaiłem się do korzystania z niego, mimo że teraz włączam Checker Framework we wszystkich moich projektach.

  4. Struktura ma sposób na opisywanie używanych interfejsów API , które nie są jeszcze opatrzone adnotacjami o null, za pomocą plików pośredniczących.


3
Wygląda świetnie i chciałbym go użyć, ale nie mogę. Dlaczego GPL? Czy to nie może być LGPL?
Burkhard,

13
Zgodnie z często zadawanymi pytaniami : „Bardziej liberalna licencja MIT dotyczy kodu, który możesz chcieć zawrzeć we własnym programie, na przykład adnotacji”.
seanf

1
Linki są obecnie zepsute. Ale +1 za porady dotyczące korzystania z Checker Framework.
Paul Wagland

1
Szkoda, że ​​kontrolery niezmienności zostały porzucone w najnowszej wersji.
Franklin Yu

1
Checker Framework jest również sugerowany w Samouczkach Java Oracle .
Quazi Irfan

55

Korzystam z IntelliJ, ponieważ najbardziej interesuje mnie oznaczanie przez IntelliJ rzeczy, które mogą produkować NPE. Zgadzam się, że frustrujące jest brak standardowych adnotacji w JDK. Mówi się o dodaniu go, może to zrobić w Javie 7. W takim przypadku będzie jeszcze jeden do wyboru!


68
Aktualizacja: IntelliJ obsługuje teraz wszystkie powyższe adnotacje do podświetlania kodu, więc nie jesteś już ograniczony do adnotacji IntelliJ: blogs.jetbrains.com/idea/2011/03/…
Daniel Alexiuc

31
Podobnie Eclipse Juno!
jFrenetic

5
javax.annotation.Nonnulljest szerzej akceptowany, prawda?
Martin

1
@DanielAlexiuc Ale niestety nie używa ich do sprawdzania czasu działania, więc korzystanie z JetBrains jest nadal korzystne ...
Trejkaz

4
@Trejkaz Od 2016 r.3 tworzy kontrole środowiska wykonawczego dla wszystkich z nich.
Karol S

32

Zgodnie z listą funkcji Java 7 adnotacje typu JSR-308 są odroczone do Java 8. Adnotacje JSR-305 nie są nawet wspomniane.

Trochę informacji o stanie JSR-305 znajduje się w załączniku do najnowszej wersji JSR-308. Obejmuje to spostrzeżenie, że adnotacje JSR-305 wydają się być porzucone. Strona JSR-305 również pokazuje ją jako „nieaktywną”.

Tymczasem pragmatyczną odpowiedzią jest użycie typów adnotacji obsługiwanych przez najczęściej używane narzędzia ... i być przygotowanym na ich zmianę, jeśli sytuacja się zmieni.


W rzeczywistości JSR-308 nie definiuje żadnych typów / klas adnotacji i wygląda na to, że uważają, że jest poza zakresem. (I mają rację, biorąc pod uwagę istnienie JSR-305).

Jeśli jednak JSR-308 naprawdę wygląda na przejście do Javy 8, nie zaskoczyłoby mnie, gdyby zainteresowanie JSR-305 wzrosło. AFAIK, zespół JSR-305 formalnie nie porzucił swojej pracy. Po prostu milczą od ponad 2 lat.

Interesujące jest to, że Bill Pugh (lider technologiczny w JSR-305) jest jednym z ludzi stojących za FindBugs.


4
@pst - aktualny harmonogram przewiduje, że Java 8 zostanie wydana we wrześniu 2013 r. - infoq.com/news/2012/04/jdk-8-milestone-release-dates
Stephen C

2
To spadło do marca 2014 r. - openjdk.java.net/projects/jdk8 . JSR 308 jest zawarty w kompilacji M7 (patrz „104 - Adnotacje do typów Java”).
Stephen C,

28

W przypadku projektów na Androida powinieneś użyć android.support.annotation.NonNulli android.support.annotation.Nullable. Te i inne pomocne adnotacje specyficzne dla Androida są dostępne w Bibliotece pomocy .

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

Sama biblioteka pomocy również została opatrzona adnotacjami, więc jako użytkownik biblioteki pomocy Android Studio już sprawdzi kod i oznaczy potencjalne problemy na podstawie tych adnotacji.


3
Przydatne byłoby uzasadnienie tego zalecenia.
morela

2
tools.android.com/tech-docs/support-annotations „Sama biblioteka pomocy również została opatrzona adnotacjami, więc jako użytkownik biblioteki pomocy Android Studio już sprawdzi kod i oznaczy potencjalne problemy na podstawie tych adnotacji . ”
James Wald

3
BTW Android Studio obsługuje także jsr305 z javax.annotation.*adnotacjami
CAMOBAP

19

Jeśli ktoś szuka tylko klas IntelliJ: możesz je pobrać z repozytorium maven za pomocą

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

To ten powoduje, że Intellij rzuca ostrzeżenia, tak.
Kliknij Upvote

Aktualna wersja (na 05/2017) to 15.0
BamaPookie

Masz rację. Zaktualizowałem wersję. Nawet jeśli myślę, że niewiele się zmieniło.
Bruno Eberhard

Należy pamiętać, że adnotacje JetBrains nie są zachowywane dla środowiska wykonawczego, więc obsługa Guice @ Nullable na przykład nie działa z tym.
Peter Major

18

JSR305 i FindBugs są autorstwa tej samej osoby. Oba są źle utrzymane, ale są tak standardowe, jak to możliwe i są obsługiwane przez wszystkie główne środowiska IDE. Dobra wiadomość jest taka, że ​​działają dobrze takie, jakie są.

Oto jak domyślnie zastosować @Nonnull do wszystkich klas, metod i pól. Zobacz https://stackoverflow.com/a/13319541/14731 i https://stackoverflow.com/a/9256595/14731

  1. Definiować @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. Dodaj adnotację do każdego pakietu: package-info.java

@NotNullByDefault
package com.example.foo;

AKTUALIZACJA : Od 12 grudnia 2012 r. JSR 305 jest wymieniony jako „Uśpiony”. Zgodnie z dokumentacją:

JSR, które zostało uznane za „uśpione” przez Komitet Wykonawczy lub takie, które osiągnęło kres swojej naturalnej długości życia.

Wygląda na to, JSR 308 jest co czyni go w JDK 8 i chociaż JSR nie definiuje @NotNull, towarzyszący mu Checkers Frameworkrobi. W chwili pisania tego tekstu wtyczka Maven nie nadaje się do użytku z powodu tego błędu: https://github.com/typetools/checker-framework/issues/183


2
Problem showstopper dla maven został naprawiony. To znowu powinna być opcja.
Marc von Renteln

Używam FindBugs przez Maven, moje IDE nic nie robi, to pozwala uniknąć adnotacji IDE, co byś polecił?
Christophe Roussy

@ChristopheRoussy Twoje pytanie dotyczy IDE. Proszę otworzyć osobne pytanie.
Gili

15

Rozróżnij analizę statyczną i analizę czasu wykonywania. Użyj analizy statycznej dla wewnętrznych elementów i analizy środowiska wykonawczego dla publicznych granic twojego kodu.

Dla rzeczy, które nie powinny być zerowe:

  • Kontrola działania: Użyj „if (x == null) ...” (zależność od zera) lub @ javax.validation.NotNull (z weryfikacją komponentu bean) lub @ lombok.NonNull (zwykły i prosty) lub guavas Preconditions.checkNotNull (.. .)

    • Użyj Opcjonalne dla typów zwracanych metod (tylko). Java8 lub Guava.
  • Kontrola statyczna: użyj adnotacji @NonNull

  • Jeśli to pasuje, użyj adnotacji @ ... NonnullByDefault na poziomie klasy lub pakietu. Utwórz te adnotacje samodzielnie (przykłady można łatwo znaleźć).
    • W przeciwnym razie użyj @ ... CheckForNull na metodach zwraca, aby uniknąć NPE

To powinno dać najlepszy wynik: ostrzeżenia w IDE, błędy Findbugs i checkerframework, znaczące wyjątki czasu wykonywania.

Nie oczekuj, że testy statyczne będą dojrzałe, ich nazewnictwo nie jest ustandaryzowane, a różne biblioteki i środowiska IDE traktują je inaczej, ignoruj ​​je. Klasy javax.annotations. * JSR305 wyglądają jak standardowe, ale nie są i powodują podział pakietów w Javie +.

Objaśnienia niektórych notatek:

  • Adnotacje Findbugs / spotbugs / jsr305 z pakietem javax.validation. * Kolidują z innymi modułami w Java9 +, prawdopodobnie również naruszają licencję Oracle
  • Adnotacje Spotbugs nadal zależą od adnotacji jsr305 / findbugs w czasie kompilacji (w momencie pisania https://github.com/spotbugs/spotbugs/issues/421 )
  • jetbrains @NotNull nazwa powoduje konflikt z @ javax.validation.NotNull.
  • adnotacje jetbrains, eclipse lub checkersframework do sprawdzania statycznego mają tę przewagę nad javax. adnotacje, że nie kolidują z innymi modułami w Javie 9 i wyższych
  • @ javax.annotations.Nullable nie oznacza Findbugs / Spotbugs, co myślisz (lub twoje IDE). Findbugs zignorują to (na członkach). Smutne, ale prawdziwe ( https://sourceforge.net/p/findbugs/bugs/1181 )
  • Do sprawdzania statycznego poza środowiskiem IDE istnieją 2 bezpłatne narzędzia: Spotbugs (wcześniej Findbugs) i checkersframework.
  • Biblioteka Eclipse ma @NonNullByDefault, jsr305 ma tylko @ParametersAreNonnullByDefault. Są to zwykłe opakowania, które stosują podstawowe adnotacje do wszystkiego w pakiecie (lub klasie), możesz łatwo stworzyć własne. Można tego użyć na opakowaniu. Może to powodować konflikt z generowanym kodem (np. Lombok).
  • Należy unikać używania lombok jako eksportowanej zależności w przypadku bibliotek udostępnianych innym osobom, im mniej zależności przechodnie, tym lepiej
  • Korzystanie ze struktury sprawdzania poprawności komponentu Bean jest potężne, ale wymaga dużego obciążenia, więc jest to przesada, aby uniknąć ręcznego sprawdzania wartości NULL.
  • Korzystanie z Opcjonalnego dla parametrów pól i metod jest kontrowersyjne (możesz łatwo znaleźć artykuły na ten temat)
  • Adnotacje zerowe w systemie Android są częścią biblioteki obsługi Androida, zawierają wiele innych klas i nie działają ładnie z innymi adnotacjami / narzędziami

Przed Java9 to moja rekomendacja:

// 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);
    }
}

Zauważ, że nie ma sposobu, aby Spotbugs wyświetlał ostrzeżenie, gdy parametr metody zerowalnej jest zaniedbany (w momencie pisania, wersja 3.1 Spotbugs). Może może to zrobić checkerframework.

Niestety, te adnotacje nie rozróżniają przypadków publicznej metody biblioteki z dowolnymi wywołaniami wywoławczymi i niepublicznych metod, w których każda strona wywoławcza może być znana. Podwójne znaczenie: „Wskazuj, że wartość null jest niepożądana, ale mimo wszystko przygotuj się na przekazanie wartości null” nie jest możliwe w pojedynczej deklaracji, stąd powyższy przykład zawiera różne adnotacje dla interfejsu i implementacji.

W przypadkach, w których podejście z podziałem interfejsu nie jest praktyczne, następujące podejście jest kompromisem:

        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);
        }

Pomaga to klientom nie przekazywać wartości null (pisanie poprawnego kodu), a jeśli tak, zwracają przydatne błędy.


Znalazłem tę odpowiedź dopiero teraz, ale @tkruse, gdzie ją znalazłeś: „Adnotacje jdt Eclipse nie mają zastosowania do zwrotów metod statycznych i niektórych innych przypadków”? (pierwsza część nie jest prawdą, druga dość niejasna :)).
Stephan Herrmann

@StephanHerrmann: Nie pamiętam. Usunąłem punktor.
tkruse

12

Eclipse ma także własne adnotacje.

org.eclipse.jdt.annotation.NonNull

Szczegółowe informacje można znaleźć na stronie http://wiki.eclipse.org/JDT_Core/Null_Analysis .


Wygląda na to, że będzie to zintegrowane z Eclipse 3.8 (Juno), dzięki czemu Eclipse będzie zgodne z IntelliJ w tym zakresie. Powinno również pozwolić ci skonfigurować własne adnotacje zerowe (np. Javax.annotation.Nonnull) i ma opcję domyślnego ustawienia NotNull.
Motti Strom

11

Wskazując tylko, że Java Validation API ( javax.validation.constraints.*) nie zawiera @Nullableadnotacji, która jest bardzo cenna w kontekście analizy statycznej. Ma to sens w przypadku sprawdzania poprawności komponentów środowiska uruchomieniowego, ponieważ jest to ustawienie domyślne dla dowolnego nieprecyzyjnego pola w Javie (tj. Nic do sprawdzania poprawności / egzekwowania). Do celów określonych, które powinny ważyć w kierunku alternatyw.


7

Niestety, JSR 308nie doda tutaj więcej wartości niż lokalna propozycja tego projektu

Java 8nie będzie zawierał ani jednej domyślnej adnotacji ani własnej Checkerstruktury. Podobnie jak w przypadku błędów Find lub JSR 305ten JSR jest źle obsługiwany przez niewielką grupę zespołów akademickich.

Nie kryje się za tym żadna komercyjna moc, dlatego JSR 308uruchamia EDR 3(Early Draft Review at JCP) TERAZ, podczas gdy Java 8ma zostać wysłany za mniej niż 6 miesięcy: -O Podobny do 310btw. ale w przeciwieństwie do 308 Oracletego przejął to teraz od swoich założycieli, aby zminimalizować szkody wyrządzone platformie Java.

Każdy projekt, sprzedawca i klasa akademicka, podobnie jak ci, którzy stoją za nimi Checker Frameworki JSR 308utworzą własną zastrzeżoną adnotację sprawdzającą.

Wykonywanie kodu źródłowego za niezgodną na długie lata, aż można było znaleźć kilka popularnych kompromisy, a może dodany do Java 9lub 10, lub za pośrednictwem struktur, takich jak Apache Commonslub Google Guava;-)


7

Android

Ta odpowiedź jest specyficzna dla Androida. Android ma pakiet wsparcia o nazwie support-annotations. Zapewnia to dziesiątki adnotacji na Androida, a także typowe, takie jak NonNull,Nullable etc.

Aby dodać pakiet wsparcia-adnotacji , dodaj następującą zależność w pliku build.gradle:

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

a następnie użyj:

import android.support.annotation.NonNull;

void foobar(@NonNull Foo bar) {}

5

Podczas oczekiwania na rozwiązanie tego problemu (Java 8?) Możesz również zdefiniować własny projekt lokalny @NotNull i @Nullableadnotacje. Może to być przydatne również w przypadku pracy z Java SE, gdzie domyślnie javax.validation.constraints nie jest dostępna .

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 {}

Byłoby to w dużej mierze przeznaczone do celów dekoracyjnych lub zabezpieczających na przyszłość, ponieważ powyższe oczywiście nie stanowi samo w sobie żadnego wsparcia dla analizy statycznej tych adnotacji.


4

Jeśli tworzysz dla Androida, jesteś trochę związany z Eclipse (edytuj: w chwili pisania tego tekstu, już nie), który ma własne adnotacje. Jest zawarty w Eclipse 3.8+ (Juno), ale domyślnie wyłączony.

Możesz go włączyć w Preferencje> Java> Kompilator> Błędy / Ostrzeżenia> Analiza zerowa (zwijana sekcja u dołu).

Zaznacz „Włącz analizę zerową opartą na adnotacjach”

http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage zawiera zalecenia dotyczące ustawień. Jeśli jednak masz w swoim obszarze roboczym zewnętrzne projekty (takie jak Facebook SDK), mogą one nie spełniać tych zaleceń i prawdopodobnie nie chcesz ich naprawiać przy każdej aktualizacji SDK ;-)

Używam:

  1. Dostęp do wskaźnika zerowego: błąd
  2. Naruszenie specyfikacji zerowej: Błąd (powiązany z punktem 1)
  3. Potencjalny dostęp do wskaźnika zerowego: Ostrzeżenie (w przeciwnym razie SDK na Facebooku będzie miał ostrzeżenia)
  4. Konflikt między adnotacjami o wartości NULL a wnioskiem o wartości NULL: Ostrzeżenie (powiązane z punktem 3)

4
związany z Eclipse? Nie prawda.
dosk

1
@DavidCowden IntelliJ IDEA ze wsparciem dla programistów Androida, myślę, że był dostępny na jakiś czas przed zaimplementowaniem AndroidStudio.
Mārtiņš Briedis

@ MārtiņšBriedis tak, to prawda. Myślę, że miałeś na myśli @chaqke.
moskwa

warto zauważyć, że android i intellij mają osobne adnotacje i prawdopodobnie tak pozostaną, dopóki java nie doda oficjalnych adnotacji. są to instrukcje używania adnotacji zaćmienia zaćmieniem.
chaqke

Nigdy nie był związany z Eclipse. Możesz użyć dowolnego IDE.
DennisK

4

Jeśli pracujesz nad dużym projektem, możesz lepiej tworzyć własne @Nullable i / lub @NotNulladnotacje.

Na przykład:

@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 
{
}

Jeśli użyjesz prawidłowych zasad przechowywania , adnotacje nie będą dostępne w czasie wykonywania . Z tego punktu widzenia jest to tylko kwestia wewnętrzna kwestia .

Chociaż nie jest to ścisła nauka, myślę, że najbardziej sensowne jest użycie do tego klasy wewnętrznej .

  • To jest sprawa wewnętrzna. (brak wpływu funkcjonalnego lub technicznego)
  • Przy wielu, wielu zastosowaniach.
  • IDE jak IntelliJ obsługują niestandardowe @Nullable/ @NotNulladnotacje.
  • Większość frameworków woli również używać własnej wersji wewnętrznej.

Dodatkowe pytania (patrz komentarze):

Jak to skonfigurować w IntelliJ?

Kliknij „policjanta” w prawym dolnym rogu paska stanu IntelliJ. I kliknij „Konfiguruj inspekcje” w wyskakującym okienku. Kolejny ... skonfigurować adnotacje


1
Wypróbowałem twoją radę, ale ideanie mów nic o void test(@NonNull String s) {}test(null);
telefonie

3
@ user1244932 Czy masz na myśli IntelliJ IDEA? Możesz skonfigurować adnotacje o dopuszczaniu wartości zerowej, których używa do analizy statycznej. Nie wiem dokładnie, gdzie jest, ale jednym miejscem do ich zdefiniowania jest „Plik> Ustawienia> Kompilacja, wykonanie, wdrożenie> Kompilator”, a tam jest przycisk „Konfiguruj adnotacje ...”.
Adowrath

@ user1244932 zobacz zrzut ekranu, jeśli nadal tego szukasz.
bvdb

3

Tutaj jest już zbyt wiele odpowiedzi, ale (a) to 2019 rok i nadal nie ma „standardu” Nullablei (b) żadne inne odniesienia nie odnoszą się do Kotlina.

Odniesienie do Kotlin jest ważne, ponieważ Kotlin jest w 100% interoperacyjny z Javą i ma podstawową funkcję Null Safety. Podczas wywoływania bibliotek Java może skorzystać z tych adnotacji, aby poinformować narzędzia Kotlin, czy interfejs API Java może zaakceptować lub zwrócić null.

O ile mi wiadomo, jedynymi Nullablepakietami kompatybilnymi z Kotlin są org.jetbrains.annotationsi android.support.annotation(teraz androidx.annotation). Ta ostatnia jest kompatybilna tylko z Androidem, więc nie można jej używać w projektach JVM / Java / Kotlin w wersji innej niż Android. Jednak pakiet JetBrains działa wszędzie.

Jeśli więc opracujesz pakiety Java, które powinny również działać w Androidzie i Kotlinie (i będą obsługiwane przez Android Studio i IntelliJ), najlepszym wyborem jest prawdopodobnie pakiet JetBrains.

Maven:

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

Stopień:

implementation 'org.jetbrains:annotations-java5:15.0'

2
Hmm, to mówi inaczej: kotlinlang.org/docs/reference/…
skagedal

3

Jest inny sposób, aby to zrobić w Javie 8. Robię 2 rzeczy, aby osiągnąć to, czego potrzebowałem:

  1. Wyraźne określanie typów pól zerowalnych przez zawijanie pól zerowalnych java.util.Optional
  2. Sprawdzanie, czy wszystkie pola, które nie mają wartości dopuszczających wartości zerowe, nie są zerowe w czasie budowy za pomocą java.util.Objects.requireNonNull

Przykład:

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);
  }

Więc moje pytanie brzmi: czy potrzebujemy adnotacji podczas korzystania z Java 8?

Edycja: Dowiedziałem się później, że niektórzy uważają za złą praktykę stosowanie Optionalargumentów, tutaj jest dobra dyskusja z zaletami i wadami Dlaczego nie należy używać Opcji Java 8 w argumentach

Alternatywna opcja, biorąc pod uwagę, że nie jest zalecane używanie Opcjonalne w argumentach, potrzebujemy 2 konstruktorów:

  //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();
      }

Powiedziałbym, że nadal potrzebujesz adnotacji @NotNull dla wszystkich 4 formalnych parametrów, aby osoby sprawdzające analizę statyczną wiedziały, że nie zamierzasz mieć wartości zerowej. W języku Java nic jeszcze tego nie wymusza. Powinieneś również sprawdzić, czy opis nie jest pusty, jeśli programujesz w obronie.
Jaxzin

2
Wciąż mogę napisać ten kod: new Role(null,null,null,null);. Dzięki adnotacjom moje IDE i analiza statyczna ostrzegą, że wartości zerowe nie mogą zostać przekazane do tych parametrów. Bez tego nie dowiem się, dopóki nie uruchomię kodu. To jest wartość adnotacji.
Jaxzin

2
Jestem również w środowiskach, w których programiści mogą korzystać z dowolnego IDE lub edytora tekstów, które wolą, nie wykluczając się wzajemnie. Następnie integrujemy wtyczkę maven-pmd i / lub SonarQube z procesem kompilacji, aby zachęcać i wyróżniać, a nawet bramkować problemy z jakością kodu przed scaleniem, na przykład przy żądaniach ściągania.
jaxzin

2
Opcjonalny nie jest przeznaczony do użycia jako argument metody lub pola prywatnego. Patrz na przykład: stuartmarks.wordpress.com/2016/09/27/vjug24-session-on-optional
assylias

1
@assylias tak, dowiedziałem się później, że mówią, że nie jest to zalecane, ponieważ nic nas nie kupi, zdecydowanie rozumiem ich racjonalność. W tym przypadku tutaj umieściłem argument, który może description nie mieć wartości null, a kod klienta może przekazać pusty ciąg, ale w wielu przypadkach przydatne może być rozróżnienie między pustym ciągiem i nieposiadanie wartości. Dzięki za komentarz. Zaktualizuję odpowiedź.
Mozart Brocchini

2

Czy słońce nie ma teraz własnego? Co to jest:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm

Wygląda na to, że zawiera wszystkie wersje Javy, z których korzystałem w ciągu ostatnich kilku lat.

Edycja: Jak wspomniano w komentarzach poniżej, prawdopodobnie nie chcesz ich używać. W takim przypadku głosuję za adnotacjami odrzutowca IntelliJ!


10
Nie mam pojęcia, co to jest, ale nazwa pakietu powinna być DUŻĄ WSKAZÓWKĄ, że NIE jest przeznaczona do ogólnego użytku.
Stephen C,

3
Zwykle powstrzymuje się od używania klas w przestrzeni nazw com.sun, ponieważ są one wewnętrzne; nieprzeznaczony do bezpośredniego użycia; i bez gwarancji co do ich przyszłej dostępności lub zachowania. Trzeba mieć naprawdę solidną obudowę, aby bezpośrednio użyć artefaktu com.sun.
luis.espinal

plus coś wyświetlanego w tak kiepskim formacie HTML (na Java2s.com na dodatek) powinno dać ci kilka czerwonych flag :)
luis.espinal

2

Jedną z fajnych rzeczy w IntelliJ jest to, że nie trzeba używać ich adnotacji. Możesz pisać własne lub korzystać z dowolnego innego narzędzia, które ci się podoba. Nie jesteś nawet ograniczony do jednego typu. Jeśli używasz dwóch bibliotek, które używają różnych adnotacji @NotNull, możesz powiedzieć IntelliJ, aby używał obu z nich. Aby to zrobić, przejdź do „Konfiguruj inspekcje”, kliknij inspekcję „Stałe warunki i wyjątki” i naciśnij przycisk „Konfiguruj inspekcje”. Korzystam z Nullness Checker, gdzie tylko mogę, więc skonfigurowałem IntelliJ do używania tych adnotacji, ale możesz sprawić, że będzie działał z każdym innym narzędziem, które chcesz. (Nie mam zdania na temat innych narzędzi, ponieważ od lat korzystam z inspekcji IntelliJ i uwielbiam je).


1

Inną opcją są adnotacje dostarczane z ANTLR 4. Po otrzymaniu żądania ściągnięcia # 434 artefakt zawierający adnotacje @NotNulli @Nullablezawiera procesor adnotacji, który generuje błędy kompilacji i / lub ostrzeżenia w przypadku niewłaściwego użycia jednego z tych atrybutów (na przykład, jeśli oba są stosowane do tego samego elementu lub jeśli @Nullablestosuje się do elementu z typem pierwotnym). Procesor adnotacji zapewnia dodatkową pewność podczas procesu tworzenia oprogramowania, że ​​informacje przekazywane przez zastosowanie tych adnotacji są dokładne, w tym w przypadku dziedziczenia metody.


1

Jeśli budujesz swoją aplikację za pomocą Spring Framework, sugerowałbym użycie javax.validation.constraints.NotNullpochodzącego z Beans Validation spakowanego w następującej zależności:

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

Główną zaletą tej adnotacji jest to, że Spring obsługuje zarówno parametry metody, jak i pola klasy opatrzone adnotacjami javax.validation.constraints.NotNull. Aby włączyć obsługę, wystarczy:

  1. dostarcz słoik interfejsu API do sprawdzania poprawności ziaren i słoik z implementacją walidatora adnotacji jsr-303 / jsr-349 (która jest zależna od Hibernacji Validatora 5.x):

    <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. dostarczyć MethodValidationPostProcessor do kontekstu wiosny

      @Configuration
      @ValidationConfig
      public class ValidationConfig implements MyService {
    
            @Bean
            public MethodValidationPostProcessor providePostProcessor() {
                  return new MethodValidationPostProcessor()
            }
      }
  3. w końcu adnotujesz swoje zajęcia wiosną, org.springframework.validation.annotation.Validateda walidacja zostanie automatycznie przeprowadzona przez Spring.

Przykład:

@Service
@Validated
public class MyServiceImpl implements MyService {

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

Gdy spróbujesz wywołać metodę doSomething i podać wartość null jako wartość parametru, sprężyna (za pomocą HibernateValidator) wyrzuci ConstraintViolationException. Nie ma tu potrzeby ręcznej pracy.

Możesz również sprawdzić wartości zwracane.

Kolejną ważną korzyścią javax.validation.constraints.NotNullzwiązaną z pojawieniem się Beans Validation Framework jest to, że w tej chwili jest on nadal rozwijany i planowane są nowe funkcje dla nowej wersji 2.0.

Co @Nullable? Nie ma nic takiego w Beans Validation 1.1. Cóż, mógłbym argumentować, że jeśli zdecydujesz się na użycie, @NotNullwszystko, co NIE jest opatrzone adnotacjami, @NonNulljest w rzeczywistości „zerowalne”, więc @Nullableadnotacja jest bezużyteczna.


1
Nie używaj go. Służy do sprawdzania poprawności środowiska wykonawczego, a NIE do analizy kodu statycznego. Szczegółowe informacje można znaleźć na stronie justsomejavaguy.blogspot.com/2011/08/… . Źródło: USUNIĘTO odpowiedź 219 głosami @ luis.espinal.
koppor

@koppor: Nie zgadzam się. Jeśli nie jest to przeznaczone do użytku, dlaczego Spring miałby obsługiwać go w czasie wykonywania. Również środowisko sprawdzania poprawności komponentu Beans umożliwia tworzenie adnotacji wyłącznie do analizy środowiska wykonawczego, ponieważ umożliwia dostęp do obiektu kontekstu (obecnie adnotacje / zatwierdzone instancje) w czasie wykonywania.
walkeros

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.