Anotacije

Anotacije pridružuju meta-informacije definicijama.

Jednostavna anotacija ima formu @C ili @C(a1, .., an). Ovdje je C konstruktor klase C, koja mora naslijediti klasu scala.Annotation. Svi argumenti konstruktora a1, .., an moraju biti konstante (npr. izrazi ili numeričke primitive, stringovi, primitive klasa, Java enumeracije i jednodimenzionalni nizovi (Array) navedenih).

Anotacijska klauza (ili više njih) primjenjuje se na prvu definiciju ili deklaraciju koja slijedi nakon nje. Redoslijed anotacijskih klauza nije bitan.

Značenje anotacijskih klauza je implementacijski-nezavisno. Na Java platformi, sljedeće Scala anotacije imaju standardno značenje.

Scala Java
scala.SerialVersionUID serialVersionUID (polje)
scala.deprecated java.lang.Deprecated
scala.inline (od 2.6.0) nema ekvivalent
scala.native (od 2.6.0) native (ključna riječ)
scala.remote java.rmi.Remote
scala.throws throws (ključna riječ)
scala.transient transient (ključna riječ)
scala.unchecked (od 2.4.0) nema ekvivalent
scala.volatile volatile (ključna riječ)
scala.beans.BeanProperty Dizajn patern

U sljedećem primjeru dodajemo throws anotaciju definiciji metode read da bi uhvatili izuzetak (exception) u Java main programu.

Java kompajler provjerava da li program sadrži rukovatelje (handler) za provjereni izuzetak (checked exception) analizom koji se izuzeci mogu dobiti izvršenjem neke metode ili konstruktora. Za svaki mogući provjereni izuzetak throws klauza metodi ili konstruktora mora navesti klasu izuzetka ili neku nadklasu izuzetka. Pošto Scala nema provjerene izuzetke, Scala metode moraju imati jednu ili više throws anotacija kako bi Java kod mogao uhvatiti iste.

package examples
import java.io._
class Reader(fname: String) {
  private val in = new BufferedReader(new FileReader(fname))
  @throws(classOf[IOException])
  def read() = in.read()
}

Sljedeći Java program prikazuje sadržaj fajla s imenom koje je proslijeđeno kao prvi argument main metode.

package test;
import examples.Reader;  // Scala klasa !!
public class AnnotaTest {
    public static void main(String[] args) {
        try {
            Reader in = new Reader(args[0]);
            int c;
            while ((c = in.read()) != -1) {
                System.out.print((char) c);
            }
        } catch (java.io.IOException e) {
            System.out.println(e.getMessage());
        }
    }
}

Kada bi zakomentarisali throws anotaciju u klasi Reader dobili bi sljedeću grešku s porukom pri kompajliranju Java main programa:

Main.java:11: exception java.io.IOException is never thrown in body of
corresponding try statement
        } catch (java.io.IOException e) {
          ^
1 error

Java anotacije

Napomena: Pobrinite se da koristite -target:jvm-1.5 opciju sa Java anotacijama.

Java 1.5 je uvela korisnički definisane metapodatke u formi anotacija. Ključna sposobnost anotacija je da koriste parove ime-vrijednost za inicijalizaciju svojih elemenata. Naprimjer, ako nam treba anotacija da pratimo izvor neke klase mogli bismo je definisati kao

@interface Source {
  public String URL();
  public String mail();
}

I upotrijebiti je kao npr.:

@Source(URL = "http://coders.com/",
        mail = "support@coders.com")
public class MyClass extends HisClass ...

Primjena anotacije u Scali izgleda kao poziv konstruktora, dok se za instanciranje Javinih anotacija moraju koristiti imenovani argumenti:

@Source(URL = "http://coders.com/",
        mail = "support@coders.com")
class MyScalaClass ...

Ova sintaksa je ponekad naporna, npr. ako anotacija ima samo jedan element (bez podrazumijevane vrijednosti), pa po konvenciji, ako se koristi naziv value onda se u Javi može koristiti i konstruktor-sintaksa:

@interface SourceURL {
    public String value();
    public String mail() default "";
}

I upotrijebiti je kao npr.:

@SourceURL("http://coders.com/")
public class MyClass extends HisClass ...

U ovom slučaju, Scala omogućuje istu sintaksu:

@SourceURL("http://coders.com/")
class MyScalaClass ...

Element mail je specificiran s podrazumijevanom vrijednošću tako da ne moramo eksplicitno navoditi vrijednost za njega. Međutim, ako trebamo, ne možemo miješati dva Javina stila:

@SourceURL(value = "http://coders.com/",
           mail = "support@coders.com")
public class MyClass extends HisClass ...

Dok u Scali možemo:

@SourceURL("http://coders.com/",
           mail = "support@coders.com")
    class MyScalaClass ...