Własne adnotacje. Definiowanie i zastosowanie.

Co to są adnotacje?

Najłatwiej będzie zacząć od fragmentu kodu. Adnotacje zaczynają się od znaku małpy @, następnie podawana jest nazwa klasy. Poprzedza się nimi deklaracje pakietów, klas, pól i metod.

@DatabaseTable(tableName = "notes")
 public class Note {
 
 	@DatabaseField(id = true, columnName = "date")
 	private long date;
 
 	@DatabaseField(columnName = "text")
 	private String text;
 }

Adnotacje zostały dodane wraz z Java 5. Często spotykane w bibliotekach ORM, a także w JUnitach. Służą do wygodnego ustawiania własności. Powyższy fragment pochodzi z mojego projektu na platformę Android, korzystającej z biblioteki OrmLite. Ten fragment kodu wystarcza by wygenerować w bazie danych tabelę o nazwie "notes" z dwoma kolumnami: "date" i "text", gdzie "date" to klucz podstawowy (uprzedzając pytania: tak, zdaję sobie sprawę, że ustawianie daty jako klucza jest dziwne :))

Kurs Java

Jak zdefiniować własną adnotację?

Definiowanie własnej adnotacji jest bardzo proste.

@Target({ ElementType.FIELD })
 public @interface DatabaseField {
 
 } 

Ciężko było mi wymyślić jakiś kreatywny przykład, więc spróbujemy zreplikować kod z przykładu. Zdefiniowaniu takiej adnotacji możemy jej użyć w kodzie:

public class User {
 
 	@DatabaseField
 	private String name;
 
 }

Nowością jest linia zawierająca: @Target({ ElementType.FIELD }). Oznacza to ograniczenia, że tę adnotację możemy zastosować jedynie do pól. Oto lista dostępnych ograniczeń:

  • ElementType.ANNOTATION_TYPE
  • ElementType.CONSTRUCTOR
  • ElementType.FIELD
  • ElementType.LOCAL_VARIABLE
  • ElementType.METHOD
  • ElementType.PACKAGE
  • ElementType.PARAMETER
  • ElementType.TYPE

Wpisujemy je bezpośrednio przed deklaracją, jak w przykładzie powyżej. W celu zastosowania kilku możliwych typów wpisujemy je po przecinku np: @Target({ ElementType.FIELD, ElementType.METHOD })

Parametry dla adnotacji

W celu umożliwienia dodania parametrów dla adnotacji należy stworzyć metody o odpowiadającej nazwie i zwracające typ parametru:

@Target({ ElementType.FIELD })
 @Retention(value = RetentionPolicy.RUNTIME)
 public @interface DatabaseField {
 
 	String columnName();
 
 }

Zauważcie, że dodałem także: @Retention(value = RetentionPolicy.RUNTIME). Oznacza to tyle, że adnotacje będą wykrywane w czasie wykonywania programu.

Jak użyć adnotacji?

Do tej pory nie było nic skomplikowanego. No, ale dopiero teraz zaczyna robić się ciekawie. Celem skorzystania z adnotacji musimy użyć refleksji (tutaj chciałem wstawić link do artykułu opisującego ten mechanizm, ale najwidoczniej jeszcze takiego nie mamy. Dopisuję na moją TODO listę ;))

Refleksja umożliwia na przeglądanie i ewentualną edycję działania aplikacji w czasie trwania jej działania. Korzystając z niej możemy m.in.: pobrać listę pól zadeklarowanych w klasie, razem z ich wartościami i ich zamianę nawet jeśli są to pola prywatne. Tyle w skrócie. Po więcej informacji zapraszam do oficjalnego tutorialu [ANG].

public class Main {
 
 	public static void main(String[] args) {
 		Main main = new Main();
 		main.run();
 	}
 
 	public void run() {
 		User user = new User();
 
 		Field[] fields = user.getClass().getDeclaredFields();
 
 		for (Field field : fields) {
 			if(field.isAnnotationPresent(DatabaseField.class)) {
 				DatabaseField databaseField = field.getAnnotation(DatabaseField.class);
 				System.out.println("Field name: "+field.getName() + " | Column name: " + databaseField.columnName());
 			}
 		}
 	}
 
 }

W powyższym fragmencie pokazuję jak możemy użyć naszych adnotacji. Zaczynamy od utworzenia instancji klasy User. Następnie pobieramy wszystkie jej pola korzystając z getDeclaredFields(). Tutaj pragnę zaznaczyć, że ta metoda zwraca także pola prywatne. Jeśli takowe nas nie interesują to możemy skorzystać z *getFields().*Później tylko iterujemy po każdym polu, sprawdzamy czy jest to obiekt oznaczony interesującą nas adnotacją, a jeśli tak to odpowiednio go obsługujemy. Ograniczam się tylko do wyświetlenia wartości adnotacji, ale równie dobrze mógłbym stworzyć tutaj zapytanie do bazy danych tworzące odpowiednią kolumnę.

Kurs Java

Kod źródłowy

Pełny i aktualny kod źródłowy programu dostępny jest na GitHubie pod adresem: https://github.com/javastartpl/annotations. Jeśli nie macie doświadczenia z git, to na dole po prawej dostępna jest opcja "Download ZIP" pozwalająca pobrać cały projekt.

Podsumowanie

Osobiście długo zwlekałem zanim przyjrzałem się temu mechanizmowi. Moim zdaniem ciężko znaleźć dla niego zastosowanie w codziennych projektach, ale zdecydowanie warto go poznać. Jednym z ciekawszych projektów które go wykorzystują na wysoką skalę to AndroidAnnotations.

Opisałem tylko część możliwości. Jeśli wyrazicie takie zainteresowanie, to mogę spróbować przyjrzeć się także innym aspektom.

Dyskusja i komentarze

Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.

Poniżej znajdziesz archiwalne wpisy z czasów, gdy strona była jeszcze hobbystycznym blogiem.

Lolo

Szkoda, że strona została trochę zaniedbana i tak samo forum, bo miały moim zdaniem potencjał. A teraz już chyba trochę straciły.

Marcin Kunert

Nic się nie bój. Jeszcze będzie comeback :)

Lolo

Proponuję założyć jakieś antyBotowe zabezpieczenie na forum, bo ostatnio jak tam byłem to było pełno spamu. Chyba, że już to zrobiliście. Proponuję również jakiś newsletter zrobić, żeby były powiadomienia o nowych artykułach.

Marcin Kunert

Dostępny jest kanał RSS, a forum będzie trzeba się przyjrzeć.

Tomek

Jestem podobnego zdania. Mam nadzieję, że ten comeback się wydarzy. Trzymam kciuki

WsC

Ja również czekam na nowe materiały.Mam nadzieję że wkrótce pojawią się nowe materiały. Pozdrawiam.