Jemný úvod do anotací

Petr Nekvinda | 28. 10. 2007 | Software | , | Přečteno: 9,534

Sun přišel ve verzi J2SE 1.5 se systemém zápisu metadat. Jedná se o systém anotací. A co vlastně anotace jsou? Jak už bylo řečeno, je to způsob zápisu metadat. Metadata by se dala vysvětlit jako data, která popisují data :) . Ve skutečnosti mohou mít anotace v pojetí JAVY jak čistě datový ráz, tak mohou ovlivňovat funkci logiky. Společně s možností vytvářet vlastní anotace, přinesla zmiňovaná verze i několik vlastních anotací, o kterých se zmíním ke konci.

Anotace mohou být přidány k jakémukoliv programovému elementu, jako jsou třídy, balíky, metody, globální a lokální proměnné a nakonec můžeme oanotovat i samotné anotace. Přístupné jsou pomocí reflexe, kde bylo přidáno rozhraní java.lang.reflex.AnnotatedElement nebo pomocí processingu podobnému XDocletu, o kterém toho však vím pramálo, proto radeji odkážu přimo na zdroj.

Když už můžeme vlastní anotace vytvářet, dali nám navrháři a vývojáří Sunu možnost specifikovat nějaké další detaily, jako třeba životnost anotace nebo cíl anotace, tj. k jakém jazykovému elementu se daná anotace zvtahuje. Pro vytvoření anotace nám stačí deklarovat typ @interface. Vše nejlépe osvětlí jednoduchoučký příklad, ve kterém si nadefinujeme vlastní anotaci.

package cz.haro.anotation.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for text of greeting.
* @author Petr Nekvinda
* @since 28.10.2007
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Greeting {
String text() default "Hello";
}

Tento fragment kódu ukazuje jak definování životnosti tak i element, ke kterému tato anotace náleží. Samotná anotace má jeden řetězcový parametr, který reprezentuje text pozdravu. V definované anotaci můžeme také specfikovat defaultní hodnotu daného parametru. To zařídíme uvedením výchozí hodnoty anotace za klíčové slovo default. Jako parametry anotace mohou být použity pouze primitivní typy, řetězce (String) a samozřejmě výčtový typ (Enum class). Životnost podle dokumentace může být nasledující:

  • CLASS – anotace jsou uloženy v class souboru pomoci kompilátoru, ale nejsou ponechané virtuálním strojem pro přístup runtime.
  • RUNTIME – to samé jako v předchozím případě, ale JVM tyto anotace poskytuje i pro potřeby runtime.
  • SOURCE – pokud je definována tato životnost, tak je daná anotace kompilátorem “zničena”, proto není ani v class souboru a nemůže být tudíž ani přitomna runtime.

o možných cílech, ke kterým se může daná anotace vztahovat říká dokumentace toto:

  • ANNOTATION_TYPE – deklarace anotace.
  • CONSTRUCTOR – deklarace konstruktoru.
  • FIELD – deklarace pole třídy.
  • LOCAL_VARIABLE – deklarace lokální proměnné.
  • PACKAGE – deklarace balíku.
  • METHOD – deklarace metody.
  • PARAMETER – deklarace parametru.
  • TYPE – deklarace typu, tj. deklarace třídy, rozhraní a to včetně anotace nebo deklarace výčtového typu (Enum).

Když už máme svojí anotaci nadefinovanou, tak bychom asi chtěli také umět přistoupit k jejím parametrům, pokud ji programátor použije. Následující velmi jednoduchá třída používá uvedenou anotaci k definování textu pozdravu, který je potom vytisknut na standartní výstup.

/**
* package for examples.
*/
package cz.haro.anotation.example;
/**
* Main class
* @author Petr Nekvinda
* @since 28.10.2007
* */
@Greeting(text="Hello everyone")
public class Main {
/**
* Main method. Print greeting according value of annotation Greeting.
* @author Petr Nekvinda
* @since 28.10.2007
*
* @param args no params
*/
public static void main(String[] args) {
System.out.println(new Main().getClass().getAnnotation(Greeting.class).text()); }
}

Jak je vidět tak anotace a jejich použití je velice snadné a může pomoci při vytváření vlastních aplikací. Stačí jen dostat nápad, jak takovou anotaci vhodně využít. Jedno z použití může být ke generování metody toString(). Nebo můžeme být tvůrci vlastní knihovny, která definuje rozhraní třídy, která reaguje na nějaký druh událostí. Programátor potom může s knihovnou dostat nejen dané rozhraní, ale také danou množinu anotací, kterou může specifikovat detaily chování jím implemetovaných metod rozhraní.

Jak už jsem uvedl na začátku, tak společně s možností vytváření vlastních anotací, máme možnost využívat i anotací definovaných v JAVA API. Jsou to:

  • @Deprecated – touto anotací máme možnost označit typ jako deprecated, tzn.že by neměl být už dále používán. Typem se rozumí, třída, metoda, field, konstruktor, interface. Tato anotace ale nezastupuje tag JavaDocu @deprecated, takže by vždy mělo být v dokumentaci uvedeno, proč je daný element označen jako deprecated.
  • @Override – tato anotace říká kompilátoru, že daný element je překrytím elementu z nadřazené třídy (rodiče).
  • @SupressWarning – pomocí této anotace můžeme kompilátoru říci, že pro daný element nemá generovat specifický warning. Můžeme tak např. potlačit vygenerování varování o tom, že používáme metodu nebo třídu, která je označena jako deprecated.

Doufám, že se mi aspoň částečně povedlo ukázat, že anotace nejsou nic složitého a jejich použití může pomoci při psaní kódu. O jejich použitelnosti svědčí možná i to, že se používají v různých projektech jako je třeba Spring, hibernate, EJB 3, Seam a jiné. Berte to pouze jako stručný výčet u kterého nezáleží na pořadí :) . Anotace nejsou ale samospásné a člověk by se při jejich deklaraci a následném použití měl zamyslet, jestli bylo na daný problém vhodné anotace použít, nebo by bylo efektivnější použít něco jiného a oželet tím punc „namakané aplikace“, protože už přece nepoužijeme takovou supr vec jako jsou anotace :) . Pokud se k návrhu anotací v projektu dostane někdo „nebezpečný“, může se zdrojový kód podobat mnohem více anotačnímu peklu a javu by tam člověk musel hledat. Takže zavěrečná rada zní: Používat anotace s rozumem.

Odkazy

Sdílení:
  • Facebook
  • Google Bookmarks
  • Linkuj.cz

Komentáře

Komentář od Jarda
Datum: 10. 3. 2008, 19:18

Člověče, kdybych si nepřečetl origilál vysvětlení Sunu (aspoň díky za ten odkaz), vůbec bych z vašeho „výkladu“ nevěděl, k čemu se anotace používají!
:-/

p.s.
„Ovlivňovat funkci logiky“ asi mohou ve vašem případě nejen anotace….
:-)

Komentář od Petr Nekvinda
Datum: 10. 3. 2008, 19:27

Jsem rád, že vám pomohl aspoň ten odkaz, doufám jen, že jste v tomto případě nestrávil nad tímto blogpostem, zbytečně mnoho času.

S pozdravem Petr Nekvinda

Komentář od Jarda
Datum: 10. 3. 2008, 22:38

Omlouvám se za svoji příkrost, přecházím na javu z jiného prostředí, Vaše mluva mi připadá nesrozumitelná – kontextově je nejasná formulace „čistě datový ráz“ (poznámky vývojáře? informace, které mohou být mimo program? proč s ním tedy jsou?), implicite zaměňovat „funkci logiky“ (jakou? mluvíte o nějaké univerzální?) za vytvořený programový kód je nešťastné, vysvětlovat něco tím samým (v anotaci máte anotaci) je pro toho, kdo tomu nerozumí nesrozumitelné. Já vím, že vám to vše připadá jasné a ve vaší zaběhnuté komunitní hantýrce s tím asi problémy nemáte, ale já jo :-)

Komentář od Petr Nekvinda
Datum: 10. 3. 2008, 22:59

Myslím si, ze se nemáte za co omlouvat, věřím, že moje formulace mohou být mnohdy nesrozumitelné. Čistě datovým rázem bylo myšleno, že pomocí anotací můžete definovat data, která jsou podstatná pro konkrétní použití anotací. Například anotací řeknete, že nějaká kontextová proměnná může nabývat právě tu hodnotu kterou definujete v anotaci. Uznávám, že v textu to nebylo vysvětleno dostatečně.
Fuknční logikou myslím obecnou logiku programu, tj. můžete anotací ovlivnit chování daného algoritmu. Teď mě nenapdá lepší příklad (aby nebyl až moc syntetický), než vypůjčit si ze Springu možnost pomocí anotace definovat, že daná operace se provádí v transakci. Nebo můžete na interface pomocí anotace definovat preferovanou implementaci. Daná service factory, pokud s touto anotací bude počítat, ji poté vezme v potaz.
Máte pravdu, že v definici anotace používám další anotace. Možná je v textu nedostatečně zmíněno, že se jedná o anotace definovane už v JDK a slouží k definování toho, jak se daná anotace bude zpracovávat.

Komentář od Petr Nekvinda
Datum: 10. 3. 2008, 23:19

Ještě mě napadlo, to jak byl myšlen datový ráz je naivně ukázáno v příkladu, kdy ztejnou metodou akorát změnou anotace můžete definovat jakýkoli pozdrav. Uznávám, že to jde udělat i pomocí prametru metody, ale tady je to ukázáno za použití anotací.
Příklad dalších anotací ovlivňujících logiku může být vzat z JUnit testů (verze 4.x), kdy pomocí anotace @test definujete, že daná metoda je dílčím testem, nebo pomocí anotace @ignore, říkáte, že se daný test má ignorovat atd.

Komentář od Jarda
Datum: 11. 3. 2008, 0:23

Díky.