Tworzenie adnotacji jest dość prostym procesem, choć ograniczonym pewnymi zasadami. Teraz musimy dowiedzieć się, jakie jest ich zastosowanie w praktyce.
Pamiętajmy jak tworzymy naszą adnotację.
Piszemy adnotację, która będzie adnotować klasy i metody oraz zawierać informacje o autorze i wersji:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Info {
String author() default "Author";
String version() default "0.0";
}
Nasze zajęcia, do których dodaliśmy adnotację:
@Info
public class MyClass1 {
@Info
public void myClassMethod() {}
}
@Info(version = "2.0")
public class MyClass2 {
@Info(author = "Anonymous")
public void myClassMethod() {}
}
@Info(author = "Anonymous", version = "2.0")
public class MyClass3 {
@Info(author = "Anonymous", version = "4.0")
public void myClassMethod() {}
}
Jak możemy wykorzystać te dane na etapie działania programu?
Możesz wyodrębnić metadane z adnotacji za pomocą odbicia. Przypomnijmy sobie, czym jest refleksja. Jest to mechanizm służący do sprawdzania danych o programie podczas jego działania. Refleksja pozwala uzyskać informacje o polach, metodach, konstruktorach klas, a także o klasach.
Za pomocą refleksji przeczytamy adnotacje w klasie i wyświetlimy potrzebne nam informacje.
Rozpoznawanie danych z naszych zajęć w głównym :
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
readMyClass(MyClass1.class);
readMyClass(MyClass2.class);
readMyClass(MyClass3.class);
}
static void readMyClass(Class<?> myClassObj) throws NoSuchMethodException {
System.out.println("\nClass: " + myClassObj.getName());
readAnnotation(myClassObj);
Method method = myClassObj.getMethod("myClassMethod");
readAnnotation(method);
}
static void readAnnotation(AnnotatedElement element) {
try {
System.out.println("Search for annotations in " + element.getClass().getName());
Annotation[] annotations = element.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof Info) {
final Info fileInfo = (Info) annotation;
System.out.println("Author: " + fileInfo.author());
System.out.println("Version: " + fileInfo.version());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Przekazujemy instancję naszej klasy do metody readMyClass w celu przetworzenia.
Ponadto do metody readAnnotation możemy przekazać zarówno klasę, jak i metodę . Więc zróbmy to: przekazujemy tam obiekt klasy i obiekt metody. Otrzymano obiekt, który implementuje kontrakt AnnotatedElement . Pozwala to pobrać z niego listę adnotacji i przeczytać informacje o każdej z nich.
Zauważ, że nie uzyskamy informacji bez sprawdzenia, czy adnotacja należy do naszego typu adnotacji ( if (annotation instanceof Info) ).
Na wyjściu otrzymujemy pełne informacje z adnotacji:
Szukaj adnotacji w java.lang.Class
Autor: Author
Wersja: 0.0
Szukaj adnotacji w java.lang.reflect.Method
Autor: Author
Wersja: 0.0
Class annotation.MyClass2
Szukaj adnotacji w java.lang.Class
Autor : Autor
Wersja : 2.0
Szukaj adnotacji w java.lang.reflect.Method
Autor: Anonimowa
Wersja: 0.0
Class annotation.MyClass3
Szukaj adnotacji w java.lang.Class
Autor: Anonimowa
Wersja: 2.0
Szukaj adnotacji w java.lang.reflect Metoda
Autor: Anonimowa
Wersja: 4.0
Tak więc z pomocą refleksji byliśmy w stanie wydobyć metainformacje.
Przyjrzyjmy się teraz przykładowi użycia adnotacji w celu ulepszenia kodu, w tym zwiększenia czytelności, szybkości i ogólnej jakości. Lombok nam w tym pomoże.
Lombok to wtyczka kompilatora, która wykorzystuje słowa kluczowe adnotacji, aby ukryć ogromną ilość kodu, rozszerzając język, upraszczając w ten sposób programowanie i dodając pewne funkcje.
Rozważmy przykład adnotacji z Lombok:
@ToString | Generuje implementację metody toString() , która składa się z przejrzystej reprezentacji obiektu: nazwy klasy, wszystkich pól i ich wartości. |
|
@EqualsAndHashCode | Generuje implementacje equals i hashCode , które domyślnie używają pól niestatycznych i niestatycznych, ale można je konfigurować. | Więcej szczegółów można znaleźć na stronie internetowej projektu . Przykład jest tam opisany przy użyciu @EqualsAndHashCode i bez niego ze standardową implementacją. |
@Getter / @Setter | Generuje metody pobierające i ustawiające dla pól prywatnych. |
|
@NonNull | Służy do potwierdzania, że pola nie są puste, gdy obiekt jest tworzony. W przeciwnym razie zgłaszany jest wyjątek NullPointerException . |
|
Lombok ma o wiele więcej przydatnych adnotacji, które są używane rzadziej. Rozważaliśmy prostą część jego adnotacji. Więcej o samym projekcie można przeczytać na oficjalnej stronie internetowej .