Lekce 1 - Annotation processor v Javě - Úvod do anotací
Vítejte u první lekce kurzu, ve kterém se seznámíme s anotacemi
v Javě. Porozumíme tak označením jako @Deprecated
,
@FunctionalInterface
a dalším "zavináčům" v kódu.
Vysvětlíme si, co to anotace je, jak se používá a proč může být
přínosné vytvořit si svou vlastní. Dále se podíváme, jak se dají
anotace zpracovat i jiným způsobem - již ve fázi kompilace kódu. Řeč bude
o Java Annotation Processor. Říkáte si, k čemu je vlastně
taková věc dobrá? Možná o tom ani nevíte, ale Java Annotation
Processor je součástí běžné praxe u enterprise
projektů. Je dost možné, že tuto technologii využíváte a ani o tom
nevíte. Pojďme se společně ponořit do tajů světa
anotací.
Motivační příklad
V komerčním světě se používají pro komunikaci mezi dvěma samostatnými systémy (nejčastěji) zprávy ve formátu XML. Každé XML lze generovat z jeho předpisu, tzv. XSD souboru. Z XSD souboru lze také vygenerovat Java třídy, které budou obsahovat stejné atributy, jako XML. Toto generování lze provést buď odpovídajícím Maven pluginem, nebo právě pomocí Java Annotation Processor.
Předpoklady
Než začnete číst, je dobré se ujistit, že rozumíte níže uvedené problematice:
Bez těchto znalostí se budete kurzem prokousávat jen velmi těžko, proto si případně prvně projděte výše uvedené kurzy.
Java Anotace
Anotace by se dala chápat jako doprovodná informace k určitému elementu v kódu. Takový element může být například: balíček, třída, metoda, třídní proměnná, parametr metody, nebo jiná anotace.
To je sice hezká definice, ale stále nám to neříká k čemu je dobré
elementy v kódu nějak dodatečně popisovat. Každý správný Java
programátor jistě zná anotaci @Override
, která se používá u
metod tříd, které jsou definovány v jejím předkovi, nebo v rozhraní.
Anotací říkáme, že metodu budeme přepisovat, resp.
implementovat.
Zamýšleli jste se někdy nad tím, co by se stalo, kdybyste tuto anotaci
nepřidali? K překvapení mnohých nic závažného. Kód by šel stále
přeložit, dokonce i spustit. Proč ji tedy vlastně píšeme? Odpověď je
jednoduchá: kvůli lepší čitelnosti kódu. Anotace @Override
patří do skupiny Information for the compiler. To znamená,
že tato anotace nebude nijak obsažena ve výsledném kódu. Ve stejném duchu
je v Javě v základu přítomna anotace @Deprecated
, sloužící k
označení zastaralých metod, které budou v novějších verzích odebrány.
Dále zde můžeme nalézt anotace @SuppressWarnings
pro
potlačení varování a @FunctionalInterface
pro označení
funkcionálního rozhraní (z lekce Úvod do
StreamAPI a lambda výrazů v Javě víme, že se jedná o zaručení, že
rozhraní bude obsahovat pouze jednu abstraktní metodu).
Tyto anotace mají společnou jednu věc: lze je zpracovat Java
Annotation Processorem. Pokud například použijeme metodu označenou
anotací @Deprecated
, dostaneme od kompilátoru vyhubováno, že
používáme zastaralé API. Kód ale bude stále možné přeložit a
spustit.
Vlastní anotace
Když jsme si řekli, co to vlastně anotace je, pojďme si ukázat, jak takovou anotaci vytvořit. Syntaxe vypadá následovně:
[@DoplnujiciAnotace]
[ModifikatorPristupu] @interface<NazevAnotace> {
DatovyTyp <nazevVlastnosti>() [vychoziHodnota];
}
Taková definice je sice hezká, ale jen málokomu pochopitelná. Vše si proto vysvětlíme na příkladu.
Příklad
Řekněme, že chceme anotaci, která označí třídu jako že reprezentuje tabulku v databázi. Taková anotace by pak vypadala asi takto:
public @interface Table { String name() default "Tabulka"; }
Anotaci deklarujeme tedy jako rozhraní. V tom nehledejte žádný vyšší smysl, něco se pro jejich definici vybrat muselo, aby se nemusela zbytečně definovat nová gramatika jazyka Jak jste si výše možná všimli, k anotaci lze přiřazovat další anotace. To jsme zatím u té naší neudělali, pojďme to napravit.
Anotace pro anotace
Určitě se nenechte zmást tím, že k anotacím přiřazujeme jiné anotace Je to logické, protože ji potřebujeme definovat ještě několik věcí a jelikož je deklarovaná jako rozhraní, tak čím přidáme nějakou dodatečnou informaci k rozhraní... no čím jiným, než anotací.
U anotace zpravidla dospecifikováváme 2 věci a je třeba uvádět vždy obě příslušné anotace, abychom si byli jistí, že se nepoužije nesprávná.
@Retention
Tato anotace definuje v jaké úrovni bude námi definovaná anotace dostupná. K dispozici jsou 3 úrovně:
RetentionPolicy.SOURCE
- Naše anotace bude dostupná pouze na úrovni zdrojového kódu. Kompiler ji bude ignorovat.RetentionPolicy.CLASS
- Naše anotace půjde použít během překladu. Do bajtkódu se ale nedostane.RetentionPolicy.RUNTIME
- Naše anotace bude dostupná za běhu programu.
@Target
Tato anotace definuje u jakého elementu půjde naše anotace použit. Jsou k dispozici následující elementy:
ElementType.ANNOTATION_TYPE
- Naše anotace bude použitelná pro další anotace.ElementType.CONSTRUCTOR
- Naše anotace bude použitelná na konstruktor.ElementType.FIELD
- Naše anotace bude použitelná na třídní proměnné.ElementType.LOCAL_VARIABLE
- Naše anotace bude použitelná na proměnné.ElementType.METHOD
- Naše anotace bude použitelná na metody.ElementType.PACKAGE
- Naše anotace bude použitelná na balíčky.ElementType.PARAMETER
- Naše anotace bude použitelná na parametry metod.ElementType.TYPE
- Naše anotace bude použitelná na třídy.
Pro účely našeho kurzu se zaměříme hlavně na takové anotace, které
budou označeny RetentionPolicy.SOURCE
a
ElementType.TYPE
. Kompletní ukázku vytvoření vlastní anotace
si ukážeme hned příště.
Java Annotation Processor
Po divokém seznámení s anotacemi se v závěru konečně dostáváme k
hlavnímu tématu. Java Annotation Processor. Ten, jak jsme si
již řekli, slouží k předzpracování anotací, které jsou
označeny RetentionPolicy.SOURCE
, tedy které se do
výsledné aplikace nedostanou.
Ze začátku budeme generovat výsledné Java soubory přímým psaním struktury ve zdrojovém kódu. Na pokročilejší věci si vezmeme na pomoc Apache Velocity.
V další lekcí, Annotation processor v Javě - Tvorba Maven projektu, si vytvoříme kostru projektu, na které budeme s Java Annotation Processor dále pracovat.