Adnotacje w Kotlinie
Innym specjalnym rodzajem klasy w Kotlinie są adnotacje, które używamy do dostarczania dodatkowych informacji o elementach naszego kody (takich jak klasy, funkcje, właściwości). Oto przykład klasy, której elementy używają adnotacji JvmField
, JvmStatic
oraz Throws
2.
Możesz również definiować własne adnotacje. Oto przykład deklaracji i użycia adnotacji:
Możesz się zastanawiać, co robią te adnotacje. Odpowiedź jest zaskakująco prosta: absolutnie nic. Adnotacje same w sobie nie zmieniają sposobu działania naszego kodu. Przechowują jedynie informacje. Jednak wiele bibliotek uzależnia swoje działanie od użytych adnotacji. Służą więc one do określania, jak odpowiednie biblioteki mają się zachować.
Wiele ważnych bibliotek korzysta z mechanizmu zwanego przetwarzaniem adnotacji (ang. annotation processing). Działa to prosto: istnieją klasy zwane procesorami adnotacji, które są uruchamiane podczas budowy naszego kodu. Analizują nasz kod i generują dodatkowy kod. Ogólnie rzecz biorąc, są one silnie związane z adnotacjami. Powstały nowy kod nie jest częścią źródeł naszego projektu, nie możemy go więc sami zmieniać, ale możemy z niego korzystać w innych częściach naszego kodu, jak również mogą z niego korzystać używane biblioteki. Tak właśnie biblioteki używają przetwarzania adnotacji. Spójrz na poniższą klasę, używającą biblioteki Mockito
z procesorem adnotacji:
Właściwość doctorRepository
jest oznaczona jako Mock
, co sprawia, że procesor biblioteki Mockito w specjalnie wygenerowanej klasie generuje kod, który ustawia wartość właściwości doctorRepository
na nowo stworzony obiekty typu mock. Oczywiście, ta wygenerowana klasa nie będzie działać sama z siebie, ponieważ musi być uruchomiona. Właśnie po to jest MockitoAnnotations.initMocks(this)
: używa refleksji, aby wywołać tę wygenerowaną klasę.
Przetwarzanie adnotacji jest lepiej opisane w Zaawansowane Kotlin, w rozdziale Przetwarzanie adnotacji oraz Kotlin Symbol Processing, gdzie pokazuję jak pisać różnego rodzaju procesory adnotacji.
Adnotacje takie jak Throws
, JvmField
i JvmStatic
są częścią biblioteki standardowej Kotlina i wpływają na działanie kompilatora. O nich również więcej będzie w książce Zaawansowane Kotlin, w rozdziale Interoperacyjność z Javą.
Meta-adnotacje
Adnotacje, które służą do oznaczania innych adnotacji, są znane jako meta-adnotacje. W bibliotece standardowej Kotlina są cztery kluczowe meta-adnotacje:
Target
wskazuje rodzaje elementów kodu, które są możliwymi celami adnotacji. Jako argumenty przyjmuje wartości wyliczeniaAnnotationTarget
, które obejmują wartości takie jakCLASS
,PROPERTY
,FUNCTION
, itp.Retention
określa, czy adnotacja jest przechowywana w binarnym wyniku kompilacji i jest widoczna dla refleksji. Domyślnie obie wartości są określone jakotrue
.Repeatable
określa, że adnotacja może być stosowana więcej niż raz dla pojedynczego elementu kodu.MustBeDocumented
określa, że adnotacja jest częścią publicznego API i dlatego powinna być uwzględniona w wygenerowanej dokumentacji dla elementu, do którego adnotacja jest stosowana.
Oto przykłady użycia niektórych z tych adnotacji:
Adnotowanie konstruktora głównego
Aby oznaczyć konstruktor główny adnotacją, należy użyć słowa kluczowego constructor
jako części jego definicji, przed nawiasami tego konstruktora.
Literał listy
Gdy określamy adnotację z wartością tablicy, możemy użyć specjalnej składni zwanej "literałem tablicy". Oznacza to, że zamiast używać arrayOf
, możemy zadeklarować tablicę za pomocą nawiasów kwadratowych.
Ten zapis jest dozwolony tylko dla adnotacji i aktualnie nie działa przy definiowaniu tablic w żadnym innym kontekście w naszym kodzie.
Podsumowanie
Adnotacje służą do opisywania naszego kodu. Mogą być interpretowane przez procesory adnotacji lub przez klasy używające refleksji w czasie wykonywania. Narzędzia i biblioteki wykorzystują to do automatyzacji niektórych działań dla nas. Adnotacje same w sobie są prostą funkcjonalnością, ale w połączeniu z procesorami adnotacji, dają one niesamowite możliwości.
Przejdźmy teraz do słynnej funkcjonalności Kotlin, która daje nam możliwość rozszerzenia dowolnego typu o metody lub właściwości: pomówmy o rozszerzeniach.
Adnotacje JvmField
, JvmStatic
i Throws
są opisane w książce Zaawansowany Kotlin i służą do dostosowywania sposobu, w jaki elementy Kotlin mogą być używane w kodzie Java.