Anotacija ir Javadocs

M.Gžegoževskis ... 2021-10-01 Java
  • Programavimas
  • Java
About 5 min

Skyrelyje yra apžvelgiamos anotacijos jų rūšys ir paskirtis. Taip pat pateikiami įvairūs pavyzdžiai su Anotacijomis bei Java (opens new window) dokumentacijos rengimu.

Anotacijų palyginimas su Java (opens new window) kalbos įprastiniais komentarais. Pagrindinis skirtumas jog komentarai yra tik pagalbinė priemonė pažymėti papildomą informaciją programinio kodo rašymo metu, bet įvykdžius programą jos vykdymo metu visi komentarai yra ignoruojami ir pašalinami. Skirtingai nei anotacijos (meta-duomenys), kurios įgalina galimybę pažymėti bet, kurią programinę dalį pvz: metodą, kintamajį, klasę ir kt. laukus ir suteikti tam tikrą funkcionalumą automatizuoti tam tikrą užduotį: Pavyzdžiui sugeneruoti naują turinį, sukonfigūruoti, aprašyti unikalų karkasą pvz. Web serviso metodų: get, post, put, delete ir kt. aprašymas, testų rašymo biblioteka yra paremta anotacijų naudojimų, kur metodai yra pažymimi anotacija @test.

Aprašant savo unikalias anotacijas anotacijas taip reikia anotuoti, priklausomai pagal, kuriamos anotacijos paskirtį. Nurodyti anotacijos paskirtį Java (opens new window) programavimo kalboje naudojama @Retention anotacija.

Anotacija @Retention tipai:

RetentionPolicy.SOURCE - nurodo jog anotacija bus įtraukta į programinį išeities tekstą (angl. source code) ir ignoruojama kompiliatoriaus.

RetentionPolicy.CLASS - nurodo jog anotacija bus naudojama kompiliatoriaus kompiliavimo metu, bet bus įgnoruojama JVM (opens new window).

RetentionPolicy.RUNTIME - nurodo jog anotacija bus apdorojama JVM (opens new window), taigi šis anotacijos tipas gali būti taikomas programos vykdymo metu.

Anotacijų paskirtis:

Informacija kompiliatoriui - anotacijos gali būti kompiliatoriaus pagalbininkas nustatyti klaidas/problemas bei paslėpti įspėjamuosius pranešimus.

Kompiliavimo ir diegimo metu - programinės įrangos įrankiai gali apdoroti anotacijų informaciją ir sugeneruoti kodą pvz: XML dokumentus, Java (opens new window) klases ir kitus dokumentus.

Vykdymo metu - kai kurios anotacijos yra apdorojamos JVM (opens new window) vykdymo metu.

Kada nepatartina naudoti anotacijų:

Kaip ir kiekvienas iš tvarkingo kodo rašymo taisyklių neužkišti savo programinio kodo anotacijomis jeigu tai nėra būtina. Ir nėra geresnių būdų pasiekti tam pačiam rezultatui.

Neapsunkinti programos, kadangi anotacijos yra tik meta-duomenys, kuriuos papildomai reikia apdoroti, o programinis kodas, kurį įprastai rašote yra reali programa.

Vengti situacijų, kai aprašote anotacijas nenaudoti informacijos, kuri yra jautri arba gyvybiškai svarbi ir be, kurios jūsų programa nustos veikti. Pavyzdžiui informacija susiijusi su duomenų bazės slaptažodžiais, aplikacijos konfigūracija ar kokio nors įrankio svarbi informacija ir pan.

Kaip sukurti savo anotacija reikia žinoti nedaug jeigu jau teko naudoti Java (opens new window) kalbos raktinį žodį interface. Žemiau yra pateikiamas minimalus pavyzdys skirtas sukurti @ManoAnotacija unikalią anotaciją. Kaip ir įprasta reikia sukurti atskirą ManoAnotacija.java (opens new window) dokumentą ir jame pateiktį šį programinį kodą.

@Documented // Programos elementai, kurie yra pažymėti šia anotacija privalo būti dokumentuoti JavaDoc (opens new window).
@Target(ElementType.METHOD) // Anotaciją galima naudoti tik ant metodų.
@Inherited // Anotaciją bus paveldima t.y. jeigu klasė turės anotacija vaikinė klasės paveldės visas anotacijas iš tėvinės klasės.
@Retention(RetentionPolicy.RUNTIME) // Bus naudojama vykdymo metu.

@interface ManoAnotacija{ // Unikalios anotacijos aprašymas.
  int studentAge() default 18;
  String studentName();  
  String stuAddress();   
  String stuStream() default "CSE";
}
1
2
3
4
5
6

Panaudoti sukurtą anotaciją galėsite tik ant metodų, nes prieš tai nurodėme @Target(ElementType.METHOD).

// Leistinas veiksmas.
@ManoAnotacija(studentName="Chaitanya", stuAddress="Agra, India")
void metodas(){....} 
// Neleistinas veiksmas. 
@ManoAnotacija(studentName="Chaitanya", stuAddress="Agra, India")
class Klase {...}
1
2
3
4
5
6

Naudojame aprašymą su reikšmėmis pagal nutylėjimą. Kaip matome pagal nutylėjimą nėra jokių apribojumų, šią anotaciją galimą nurodyti bet kur: ant klasės, metodo, kintamojo, metodo parametro ir t.t.

@interface KitaAnotacija {
 int skaicius();
 String[] knygos();
}
@KitaAnotacija(skaicius=3, knygos={"C++", "Java"})
class Klase {...}
1
2
3
4
5
6

Prieš tai panagrinėjome keletą pavyzdžių, kurioje buvo minima @Target anotacija. Jeigu šios anotacijos nenurodome reiškia jog sukurta anotacija yra naudojama bet kur. Štai sarąšas kaip galima apriboti, kurioje vietoje leisime anotuoti:

ElementType.METHOD
ElementType.PACKAGE
ElementType.PARAMETER
ElementType.TYPE
ElementType.ANNOTATION_TYPE
ElementType.CONSTRUCTOR
ElementType.LOCAL_VARIABLE
ElementType.FIELD
1
2
3
4
5
6
7
8

Keletas pavydžių kaip apriboti anotacijų naudojimą taikant @Target anotaciją.

@Target({ElementType.METHOD})
@interface ManoAnotacijaMetodams{}
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
@interface AnotacijaKeliemsTipams{} // Galima naudoti metodams, tipams, konstruktoriuose
1
2
3
4

Kaip objektiškai orientuotos kalbos neturės galimybės paveldėti. Štai ir anotacija @Inherited skirta Java (opens new window) paveldėjimui, tai reišikia kai paveldėsite klasę paveldėsite ir visas @Inherited anotacijas.

@Inherited
@interface PaveldekAnotacija {...}
@PaveldekAnotacija
class Tevine{...} // Tevine klasė, kuri yra anotuota paveldės klasė Vaikine. 
class Vaikine extends Tevine {...}
1
2
3
4
5

Kadangi anotacijas sukurti galime, bet kaip nuskaityti jas ir jų duomenis? Yra paprasčiausias būdas tai naudoji Java (opens new window) Reflection API (opens new window). Pateiksime vieną iš galimų aprašymo būdų nuskaityti anotacijos duomenims. Tarkim sukuriame anotacija, kurią nuskaitysime JVM (opens new window) vykdymo metu.

@Retention(RetentionPolicy.RUNTIME)
@interface Anotacija {
 String zinute();
 int reiksme();
}
1
2
3
4
5

Pavyzdys naudojant Reflection API (opens new window) nuskaityti anotacijuos duomenis.

class Meta {
  @Anotacija(zinute = "Laba diena", reiksme = 55)
  public static void metodas(String str, int i) {
    Meta ob = new Meta();
    try {
      Class c = ob.getClass();
      Method m = c.getMethod("metodas", String.class, int.class);
      Anotacija anno = m.getAnnotation(Anotacija.class);
      System.out.println(anno.zinute() + " " + anno.reiksme());
    } catch (NoSuchMethodException exc) {
        System.out.println("metodas nerastas");
    }
  }
  public static void main(String args[]) {
    metodas("test", 10);
  }
} // REZULTATAS : Laba diena 55 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Pavyzdys naudojant Reflection API (opens new window) nuskaityti visas anotacijas, iš konkrečios klasės.

 Method[] methods = Meta.class.getMethods();
    for (Method m : methods){
      if (m.isAnnotationPresent(Anotacija.class)){
        Anotacija ta = m.getAnnotation(Anotacija.class);
        System.out.println(ta.zinute() +" "+ ta.reiksme());
      }
    }
1
2
3
4
5
6
7

Kas yra Javadoc (opens new window). Turint anotacijų mechanizmą Java (opens new window) kalboje tai yra vienas iš svarbių mechanizmų, kurio pagalba yra sukurtas įrankis skirtas programinio kodo dokumentacijai rengti. Žemiau bus išvardinti skirtumai su pavyzdžiais tarp įprasto Java (opens new window) komentaro ir Javadoc (opens new window) dokumentacijos rengimo įrankio aprašymo programiniame kode. Vienos eilutės Java (opens new window) kalbos komentaras

/*
 * Įprastinis Java kalbos kelių eilučių komentaras
 */

/**
 * Čia yra Javadoc komentaras skirtas programinio kodo dokumentacijai rengti
 */

Pagrindinės anotacijos skirtos Javadoc dokumento rengimui: 
@param provides any useful description about a method’s parameter or input it should expect 
@return provides a description of what a method will or can return 
@see will generate a link similar to the {@link} tag, but more in the context of a reference and not inline 
@since specifies which version the class, field, or method was added to the project 
@version specifies the version of the software, commonly used with %I% and %G% macros 
@throws is used to further explain the cases the software would expect an exception 
@deprecated gives an explanation of why code was deprecated, when it may have been deprecated, and what the alternatives are
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Javadoc (opens new window) pavyzdys kaip naudoti dokumentacijai rengti.

/**
* Hero is the main entity we'll be using to . . .
*
* Please see the {@link com.baeldung.javadoc.Person} class for true identity
* @author Captain America
*
*/
public class SuperHero extends Person {
 /**
 * The public name of a hero that is common knowledge
 */
 private String heroName;
 /**
 * <p> simple description of the method...</p>
 * <a href="eif-courses.github.io">eif-course</a>
 * @param incomingDamage the amount of incoming damage
 * @return the amount of health hero has after attack
 * @see HERO-402
 * @since 1.0
 */
 public int successfullyAttacked(int incomingDamage) {
    // do things
    return 0;
 }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Last update: September 20, 2021 06:35
Contributors: Marius Gžegoževskis