Cos’è l’annotation processing
L'annotation processing, da adesso AP, è uno strumento per la generazione di codice sorgente mediante l'uso delle annotazioni. Un processore di annotazione prende in input del codice java (o del byte code compilato) e genera in output dei file .java
. Questi ultimi vengono poi presi in carico dal compilatore come tutti gli altri sorgenti. Non è possibile manipolare il codice Java esistente, si possono generare soltanto nuovi file.
Le specifiche delle Annotation Processing API sono contenute nella Java Specification Request (JSR) 269 a partire dal 2006, quando furono introdotte con il JDK 1.5 mediante il tool apt
. Nella versione 7 del JDK il tool apt, e il package com.sun.mirror
, sono stati deprecati in favore di una integrazione diretta nel compilatore javac
e dei package javax.annotation.processing
e javax.lang.model
. L'AP è diventata molto popolare negli ultimi anni e viene usata in una moltitudine di contesti e di framework come ad esempio CXF, JPA, JAXB e molti altri ancora.
È bene precisare che non si sta parlando delle annotazioni usate a runtime, infatti l'AP entra in causa e ha luogo durante la fase di compilazione.
Prerequisiti
Il codice d'esempio che verrà presentato in questa serie di articoli è stato realizzato usando Maven, Eclipse ed il relativo plugin per la loro integrazione, m2e. Si richiede quindi una buona conoscenza di questi tool al fine di poter eseguire il codice che verrà allegato a fine guida. Per la realizzazione del codice d'esempio si è usato Eclipse 4.4.2 ("Luna Service Release 2"). Si farà riferimento anche allo sviluppo su Android, ma tale conoscenza non è necessaria al fine di comprendere l'esempio proposto.
Esempio d'uso di AP: realizzazione di un converter mediante AP
Per meglio comprendere e vedere in pratica i concetti base dell'AP si è deciso di utilizzare uno scenario in cui l'AP è realmente utile. Quando si lavora su Android e si ha la necessità di inserire un record in una tabella su database SQLite, si dovrà scrivere un codice simile a quello di seguito riportato:
Persona e=new Persona();
e.nome="Mario";
e.cognome="Rossi";
e.eta=25;
e.peso=70;
...
SQLiteDatabase db=mDbHelper.getWritableDatabase();
ContentValues vs=new ContentValues();
vs.put("nome",e.nome);
vs.put("cognome",e.cognome);
vs.put("eta",e.eta);
vs.put("peso",e.peso);
long newRowId=db.insert(DatabaseHelper.TABLE_PERSONE,null,vs);
db.close();
...
Come è possibile osservare dal codice riportato in precedenza, per poter inserire un oggetto di tipo Persona
nella relativa tabella del database SQLite db
è necessario convertire l'oggetto in questione in una struttura dati di tipo mappa denominata ContentValues
.
Ora, si vuole usare l'annotazione Convert
per marcare le classi per le quali l'AP deve generare l'apposito convertitore da classe a ContentValue
. Per rendere più chiaro l'obiettivo: a fronte della classe Persona
:
public class Persona {
public String nome;
public String cognome;
public int eta;
public String peso;
}
Si vuole quindi automatizzare la generazione di una classe di conversione tra la classe Persona
e la sua rappresentazione mediante un oggetto di tipo ContenvValues
:
public class PersonaConverter {
public static ContentValue convert(Persona value)
{
ContentValues result=new ContentValues();
result.set("nome",value.nome);
result.set("cognome",value.cognome);
result.set("eta",value.eta);
result.set("peso",value.peso);
return result;
}
}
Da notare che per ogni attributo della classe esiste una relativa voce aggiunta alla mappa result
. L'annotazione da usare sulla classe Persona
o su qualunque classe si desideri convertire in ContentValues
si chiamerà @Convert
.
Definizione dei progetti
Il codice d'esempio è suddiviso in tre progetti Maven utilizzabili da Eclipse:
Progetto | Descrizione |
---|---|
Annotation | Contiene l'annotazione @Convert . Nella fase di runtime sarà l'unica dipendenza necessaria ai progetti example per impiegare l'annotazione. |
Annotation-processor | Contiene l'AP. Serve in fase di compilazione in quanto conterrà il codice che genererà il converter a partire dall'annotazione. |
Example | Progetto client che usa l'annotazione ed l'AP. |
Il component diagram seguente illustra le relazioni tra i vari progetti che compongono il nostro esempio.
Differenziare il progetto Annotation
dal progetto Annotation-processor
consentirà di usare il processore solo nella fase di compilazione, senza doverlo necessariamente includere tra le dipendenze a runtime. In fase di runtime serve solo l'annotazione contenuta nel progetto Annotation
.
Progetto | Usato in fase di compilazione | Usato durante l'esecuzione |
---|---|---|
Annotation | si | si |
Annotation-processor | si | no |