Login
Cerca all'interno di JavaPortal
Help
Home Page Documentazione Forum Progetti Partner Pubblica!
Documentazione > Tutorial > Java Annotations
Hide
Best Practices
EJB
Frameworks
Howto
J2EE
J2ME and Wireless
J2SE
JSP e Servlet
Java Application Server
Java IDE/Tools
Java Media
Java Security
Java Sys Admin
Java e XML
Java e SQL
OpenSource Java
Patterns
Repository
Tesi
UML
Web Services
Slide
White Paper di jws.it
project management
Eventi
Groovy

Hai una tesi in Java?
Tesine preparate
per esami?
Pubblica tutto su
JavaPortal!

Scrivi al nostro staff


5 trucchi da sapere sulle performance


Publio Cornelio Tacito
Tutte le cose che ora si credono antichissime furono nuove


WebSphere System Integration Bus (SIB) e i Web Services


Rss Feed
Home Page
Articoli
News
Forum
Classi

  Visualizza Commenti (0) Aggiungi Commento    
Add to Shortcuts
 
Vota l'articolo
Java Annotations
By Giuseppe Capodieci
16 agosto 2005
Valutazione Acquisita: 30

  Java Annotations
Program Annotations predefnite
Program Creazione di Annotations personalizzate
Program Conclusioni
Program Riferimenti

La Java 2 Platform, Standard Edition (J2SE) versione 5 (precedentemente conosciuta come 1.5) ha portato tante interessanti novità nel panorama della programmazione java; per chi fosse interessato, abbiamo fatto una carrellata di queste nuove features in un precedente articolo. Tra le tante novità, c’è ne una che io trovo particolarmente interessante, si tratta delle Java Annotations; ma vediamo in dettaglio di cosa si tratta.

Le Java Annotations sono metadati (data about data) associati a parti di codice (classi, interfacce, metodi e campi) e servono ad aggiungere informazioni reperibili successivamente e utilizzabili nei più svariati modi: dalla documentazione del codice alla generarazione di codice o ancora, a tempo di esecuzione, per gestioni avanzate della business logic .

Diciamo che java non è nuovo all’utilizzo di metadati, anche se in forma molto limitata, basti pensare a javadoc, il tool per la generazione della documentazione delle classi. Gli attributi (tag) che vengono associati alle classi e ai metodi sono metadati, solo che il loro utilizzo è limitato esclusivamente a tool come javadoc e non possono essere utilizzati a runtime. Un esempio di documentazione di un metodo di una classe con l’utilizzo di queste meta-informazioni è mostrato di seguito:

public class ExampleClass {
/**
* getMessage
*
* @param message String
* @return String
*/
public String getMessage(String message){
return “Il messaggio è :“+message;
}
}

I tag param e return ci danno rispettivamente informazioni sui parametri che il metodo getMessage prende in input e il tipo di dato restituito in output.

Nella versione 5 di java l’utilizzo delle annotazioni è molto più evoluto: oltre ad offrire delle Annotations predefnite, permette la creazione di Annotations personalizzate per “decorare”, classi, metodi e campi. La “visibilità” delle annotazioni è configurabile, come vedremo di seguito, e può essere relativa al codice sorgente, alle classi compilate oppure informazioni rese disponibili dalla JVM a tempo di esecuzione.



Annotations predefnite top

J2SE 5 mette a disposizione sei Annotations predefinite, ma prima di passare alle loro definizioni e descrizioni vediamo in breve la sintassi di definizione di una annotation.

La definizione di una annotation avviene in modo simile alla definizione di un’interfaccia, con le seguenti differenze:

  • Si usa la parola chiave @interface anzichè interface

  • La clausola extends non è ammessa

  • I “metodi” non hanno alcun parametro e possono ritornare solo tipi primitivi, String, Class, tipi enum e array dei tipi appena elencati.

Esistono anche altre limitazioni; per chi volesse approfondire maggiormente la sintassi di definizione può riferirsi alle specifiche ufficiali

Passiamo, adesso, alle Annotations predefinite. Una cosa interessante da notare è come le definizioni delle annotations siano a loro volta decorate con annotazioni!! Abbiamo quindi delle meta-annotazioni, in particolare queste sono: @Documented, @Target e @Retention.

java.lang.Overrides

@Target(ElementType.METHOD)
public @interface Overrides
{
}

Questa annotation è usata per indicare che una dichiarazione di un metodo di una classe vuole fare l’override dello stesso metodo presente nella sua diretta o indiretta superclasse. Se un metodo viene decorato con questa annotation ma non sovrascrive il metodo della superclasse, viene dato un errore a tempo di compilazione, ma vediamo un esempio per chiarire meglio la cosa:

class Pippo
{
@Overrides
    public String toString(int i)
    {
        return "";
    }
}

Quando questa classe viene compilata, viene dato il seguente messaggio di errore:

method does not override a method from its superclass
                @Overrides
                 ^

Questo avviene perchè l’annotation dichiara che si intende fare l’override del metodo toString() di Object e invece non viene fatto, in quanto la signature del metodo toString non prevede parametri di input. Per ovviare all’errore basta riscrivere il metodo senza alcun argomento in input. L’utilizzo di questa annotation permette un maggiore controllo sul codice quando magari si crede di aver fatto un ovverride e invece si è scritto un metodo nuovo.

java.lang.annotation.Documented

@Documented
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented
{
}

Documented indica che l’annotation a cui essa è applicata deve essere documentata.

Annotation di questo tipo, senza alcun campo, vengono chiamate Marker Annotation.

java.lang.annotation.Deprecated

@Documented
@Retention(RetentionPolicy.SOURCE)
public @interface Deprecated
{
}

Questa annotation indica al compilatore java di avvertire a tempo di compilazione, l’utente che utilizza classi, metodi o campi, decorati con questa annotation. E’ in pratica un metodo per segnalare classi o metodi “depreceted”, cioè metodi che sono stati riscritti o sostituiti da altri metodi “migliori” e il cui uso è quindi sconsigliato.

java.lang.annotation.Inherited

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited
{
}

Decorare una annotation che chiameremo A, con Inherited vuol dire che tutte le sottoclassi di una classe decorata con A, erediterà automaticamente la annotation A.

java.lang.annotation.Retention

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention
{
    RetentionPolicy value();
}

Questa annotation prende in input un singolo valore che definisce la “visibilità” delle annotations a cui è applicato, cioè dove queste si rendono disponibili e possono essere lette ed usate. I valori validi per il parametro in input sono elencati nella enumeration java.lang.annotation.RetentionPolicy e sono i seguenti:

  1. RetentionPolicy.SOURCE: L’annotation decorata è visibile a livello di codice sorgente.

  2. RetentionPolicy.CLASS: L’annotation decorata è visibile a livello di codice sorgente e nelle classi compilate

  3. RetentionPolicy.RUNTIME: L’annotation decorata è visibile a livello di codice sorgente, nelle classi compilate ed è possibile caricarle nella JVM a tempo di esecuzione

Di default tutte le annotations sono visibili a livello di codice sorgente.

java.lang.annotation.Target

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target
{
    ElementType[] value();
}

Questa annotation viene usata per indicare il tipo di elemento di programma (classe, metodo o campo) a cui l’annotation può essere applicata. Se Target non è presente in una annotation vuol dire che quest’ultima può essere usata in qualsiasi elemento di programma. I valori validi per il parametro di input sono elencati nella enumeration java.lang.annotation.ElementType e sono i seguenti:

  • TYPE : L’ annotation si applica a classi, interfacce (incluso il tipo annotation) e dichiarazioni di enum

  • FIELD: L’annotation si applica alle dichiarazioni di campi

  • METHOD: L’annotation si applica alle dichiarazioni di metodi

  • PARAMETER: L’annotation si applica alle dichiarazioni di parametri

  • CONSTRUCTOR: L’annotation si applica alle dichiarazioni di costruttori

  • LOCAL_VARIABLE: L’annotation si applica alle dichiarazioni di variabili locali

  • ANNOTATION_TYPE: L’annotation si applica alle dichiarazioni di annotazioni

  • PACKAGE: L’annotation si applica alle dichiarazioni di package



Creazione di Annotations personalizzate top

Dopo aver visto le annotations che la J2SE 5 ci mette a disposizione , vediamo adesso come si crea una, anzi due , come vedremo di seguito, annotations personalizzate, il loro uso per decorare le parti di programma che ci interessano e infine la lettura a tempo di esecuzione.

La prima annotation che andiamo a definire è la seguente:

@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSourceJNDIName {
String value();
}

Da questa definizione deduciamo che:

  1. L’annotation sarà documentata per essere trattata con tool come javadoc

  2. L’annotation può essere applicata alle sole classi (TYPE)

  3. L’annotation è disponibile a runtime

  4. il nome dell’annotation è DataSourceJNDIName

  5. L’annotation ha un unico campo di tipo stringa chiamato value ( “value” è il nome convenzionale, per annotation con singolo campo)

La seconda annotation è invece la seguente:

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SQL {
String value();
}

Dal questa seconda definizione deduciamo che:

  1. L’annotation sarà documentata per essere trattata con tool come javadoc

  2. L’annotation può essere applicata ai soli metodi

  3. L’annotation è disponibile a runtime

  4. il nome dell’annotation è SQL

  5. L’annotation ha un unico campo di tipo stringa chiamato value

Prima di andare avanti forse è il caso che vi dica “dove stiamo andando a parare….”  :

L’idea che stà dietro la definizione di queste due annotations è quella di usarle all’interno di classi DAO (Data Access Object) per leggere/scrivere dati su DB. L’utilità di queste due annotation è quello di poter specificare il nome del DataSource a cui ci vogliamo collegare e le query che verrano eseguite, collegate ciascuna ad un metodo. Ma vediamo l’esempio per capire meglio:

// Decoro la classe con l’annotation DataSourceJNDIName indicando il nome
// del DataSource che voglio reperire
@DataSourceJNDIName("nome_del_datasource")
public class AnnotatedDAO
{
public AnnotatedDAO() throws NamingException, SQLException
{
Class thisClass = this.getClass();
// Reperisco l’annotation DataSourceJNDIName dall’oggetto thisClass
DataSourceJNDIName dsa;
dsa =(DataSourceJNDIName)thisClass.getAnnotation(DataSourceJNDIName.class);
// Leggo il valore dell’annotation cioè il nome del DataSource
String dataSourceName = dsa.value();
// Reperimento DataSource e connessione al DB
DataSource ds = ………
connection = ds.getConnection();
}
// Decoro il metodo con l’annotation SQL per indicare la query che
// deve essere eseguita al momento dell’invocazione del metodo stesso.
// In questo caso si tratta di una SELECT
@SQL("SELECT name, surname FROM customers WHERE customer_id={customerId)")
public Customer getCustomerInfo(int customerId) throws SQLException
{
Class[] integer = {int.class};
Method thisMethod = null;
try {
// estraggo l’oggetto method che rappresenta il metodo
// getCustomerInfo mediante la reflection
thisMethod = this.getClass().getMethod("getCustomerInfo", integer);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// Reperisco l’annotation SQL dall’oggetto thisMethod
SQL sql = (SQL)thisMethod.getAnnotation(SQL.class);
// Leggo il valore dell’annotation, cioè la query che voglio eseguire.
String query = sql.value();
// Setting del parametro customerId nella query
// query = .................
// esecuzione query
ResultSet rs = connection.createStatement().executeQuery(query);
Customer customer = null;
// popolamento dell’oggetto customer dal ResultSet ottenuto
// ...............
return customer;
}
// Decoro il metodo con l’annotation SQL per indicare la query che
// deve essere eseguita al momento dell’invocazione del metodo stesso
// In questo caso si tratta di una INSERT
@SQL("INSERTO INTO customers VALUES ({customer.customer_id}, {customer.name}, {customer.surname} )")
public void insertNewCustomer(Customer customer) throws SQLException
{
Class[] cust = {Customer.class};
Method thisMethod = null;
try {
thisMethod = this.getClass().getMethod("InsertNewCustomer", cust);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// reperimento annotation e relativo valore
SQL sql = (SQL)thisMethod.getAnnotation(SQL.class);
String query = sql.value();
// setting dei parametri letti dall'oggetto customer nella query
// query = .................
// esecuzione query
connection.createStatement().execute(query);
// .................
}
}

Un ipotetico utilizzo della classe appena descritta, potrebbe essere il seguente:

public class TestAnnotatedDAO
{
public static void main(String[] args)
{
try {
AnnotatedDAO dao = new AnnotatedDAO();
// chiedo di reperirmi i dati del cliente con id 1000
Customer customer1 = dao.getCustomerInfo(1000);
// effettuo l’inserimento nel DB di un nuovo cliente
Customer customer2 = new Customer(2000, "Silvia", "Rossi");
dao.InsertNewCustomer(customer2);
} catch (NamingException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}



Conclusioni top

Abbiamo visto quanto sia semplice definire le proprie annotation ed usarle. Nel nostro caso ci hanno permesso di scrivere delle query SQL in maniera elegante, facilmente individuabili nel codice e di collegarle ai metodi specifici che le eseguono, niente di più; ma le possibilità offerte dall’utilizzo delle annotations sono veramente tante e sicuramente porteranno a grandi cambiamenti nel modo di programmare in java, basti pensare alle enormi semplificazioni che hanno già portato nella specifica degli EJB 3 con l’eliminazione di interfacce e descrittori permettendo di definire EJB come Plain Object.



Riferimenti top

Taming Tiger, Part 3 - Decorate your code with Java annotations (JavaWorld)

JavaTM 2 Platform Standard Edition 5.0 - API Specification

Il ruggito de tigre : J2SE 1.5 (JavaPortal)



Username:
Password:
To sign up for an account, click register... Register
Hide





Powered By



Campagna Anti-IF


Skin


PARTNER
Zio Budda
HostingJava


LICENZA



Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati sotto licenza Creative Commons

Sitemap  © 2002-2004 Copyright Information. Privacy . Today is domenica 1 agosto 2010