Introduzionetorna su
Con oltre un centinaio di nuove funzionalità introdotte, la tecnologia J2SE 5.0 consente agli sviluppatori di essere più produttivi, permette agli amministratori di sistema di monitorare e gestire le applicazioni più efficacemente ed assicura agli utenti finali di PC desktop un maggior numero di funzionalità d'utilizzo.
Gli aggiornamenti al linguaggio introdotti nella nuova versione consentono agli sviluppatori di essere più efficienti e produttivi grazie alla drastica riduzione della stesura di codice ripetitivo. Tra le nuove funzionalità figurano tipi di dato generic, enumerated, metadata e autoboxing. I miglioramenti prestazionali che contraddistinguono la nuova versione riguardano l'abbreviazione del tempo di startup, un minor consumo di memoria e l'ottimizzazione automatica delle prestazioni a seconda del tipo di computer.
I metadati - (Annotazioni)torna su
L'annotazione dei metadati è stata standardizzata secondo JSR 175 e fa parte di J2SE 5.0.
La piattaforma Java ha sempre avuto vari meccanismi di annotazioni creati "ad hoc". Per esempio il transient modifier è una annotazione "ad hoc" ed indica che il campo "annotato" dovrebbe essere ignorato durante il processo di "serialization subsystem". Altro esempio è il tag @deprecated: indica che il metodo annotato non dovrebbe più essere usato. Così dalla release 5.0, la piattaforma Java implementa le Annotazioni (conosciute come metadata) general purpose permettendo al programmatore di crearne di nuove senza troppa fatica. Le agevolazioni introdotte consistono in una sintassi per dichiarare i tipi di annotazioni, una sintassi per usarle, delle API per leggerle, una classe che rappresenta l'annotazione stessa e un annotation processing tool.
Molte API Java richiedono la realizzazione di una grossa quantità di codice ad hoc che, nonostante segua un preciso standard descritto da rigorose specifiche, deve per forza essere adattato ad ogni particolare caso anche se con minime varianti. Le classi d'appoggio create per questi scopi potrebbero essere ricavate automaticamente a partire dalla classe principale se solo questa contenesse le informazioni necessarie. Le annotazioni possono permettere di risolvere anche questo problema senza influire sulla semantica del programma modificata solamente a run time.
Così è ora possibile espandere la gamma dei modificatori Java con delle proprie “annotazioni”. Non sono particolarmente difficili da usare, ma per loro natura sono riservate a pochi casi concreti d'utilizzo.
Come dichiarare una nuova annotazionetorna su
Dichiarare un nuovo tipo di annotazione è come implemetare una normale dichiarazione di interfaccia:
- un simbolo at (@) precede la keyword interface
- ogni metodo della dichiarazione definisce un elemento del tipo di annotazione
- la dichiarazione non deve avere parametri o la clausola throws
- i tipi di ritorno possono essere solo primitivi: String, Class, enums, annotations, o array dei tipi precedenti
- i tipi di ritorno possono avere valori di default.
Ecco un esempio di annotazione:
package annotation;
public @interface Persona{
String nome();
String cognome();
int età();
String indirizzo() default "unassigned";
}
La dichiarazione deve essere salvata in un file con lo stesso nome ed estensione .java.
Verrà poi compilata in un comune file .class (eventualmente in un particolare package, usando la direttiva package come si farebbe in una qualsiasi classe).
Una volta definita la potremo inserire prima di un metodo nel nostro codice riferendoci ad essa con il simbolo @ seguito dal nome ed eventuali parametri.
Ecco un esempio di utilizzo:
@Persona(nome="Mario", cognome="Rossi", età=35)
I due tipi principali di meta-annotazioni sono:
- @Retention: indica a quale istante di vita del codice l’annotazione deve essere applicata.
I valori possibili sono:
- RetentionPolicy.SOURCE // no JVM e compiler
- RetentionPolicy.CLASS // solo compiler
- RetentionPolicy.RUNTIME // solo JVM
- @Target: indica a quale porzione di codice una annotazione si riferisce.
I valori possibili sono:
- ElementType.TYPE // class, interface, enum
- ElementType.FIELD
- ElementType.METHOD
- ElementType.PARAMETER
- ElementType.CONSTRUCTOR
- ElementType.LOCAL_VARIABLE
- ElementType.ANNOTATION_TYPE
- ElementType.PACKAGE
e possono essere inserite nella definizione dell'annotazione stessa:
package annotation;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Persona{
String nome();
String cognome();
int età();
String indirizzo() default "unassigned";
}
Come intercettare l'annotazione con gli strumenti forniti da javatorna su
Per controllare se in un metodo è presente o meno un'annotazione si utilizza la funzione “isAnnotationPresent” (presente nella libreria “java.lang.reflect.AccessibleObject”), la cui sintassi è:
boolean isAnnotationPresent (annotationClass.class)
Per intercettare l'annotazione posso utilizzare le seguenti funzioni (tutte presenti nella libreria “java.lang.reflect.Method”):
public annotationClass getAnnotation (annotationClass.class)
Questa fuzione ritorna il contenuto dell'annotazione intercettata.
Annotation[] getAnnotations ()
questa funzione ritorna tutte le annotazioni presenti nel relativo metodo annotato.
Nel seguente esempio scorro tutti i metodi presenti in una classe (classES.class) e, per ognuno, controllo se sono presenti 2 annotazioni (Pre.class e Post.class), nel caso in cui fossero presenti una o tutte e due le annotazioni ne stampo il contenuto.
for (Method met : Class.forName (classES.class).getMethods ()) {
if (met.isAnnotationPresent (Pre.class))
{
met.invoke (null);
Pre ann_pre = met.getAnnotation (Pre.class);
System.out.println (ann_pre.value ());
}
if (met.isAnnotationPresent (Post.class))
{
met.invoke (null);
Post ann_post = met.getAnnotation (Post.class);
System.out.println (ann_post.value ());
}
}
Per chiarire questo concetto, si possono analizzare i file sorgenti presenti in:
Java_annotation.zip;
in essi viene usata una classe principale (test), che ha il compito di lanciare, per ogni sotto-classe, TestingTool.java, necessario per scandire il file alla ricerca delle annotazioni specificate.
APT (Annotation Processing Tool) da riga di comandotorna su
L'utility a riga di comando “apt”, per definizione, trova ed esegue i processori di annotazioni, basandosi sulle annotazioni presenti nel set di file da esaminare.
Per prima cosa l‘”apt”, determina che tipo di annotazioni sono presenti nel pezzo di codice su cui si stà operando. Successivamente cerca l'implementazione personalizzata che stabilisca cosa deve fare quello specifico processore di annotazione. Quindi l'”apt” chiede al processore personalizzato, di svolgere il suo compito sul pezzo di codice in esame. Questa operazione è ripetuta fin tanto che non vi è più alcun codice nuovo (o “auto-generato”), su cui effettuare lo “scanning”.
Il grande vantaggio che si riscontra nell'utilizzo di questo “tool”, è che invece di gestire manualmente la i file e le classi base con i loro derivati, si lascia questo compito all'“apt” che in automatico assolve il compito di processare file e classi, alla ricerca di annotazioni indicanti la modalità di manutenzione dei nuovi pezzi di codice da “auto-generare”.
Per sviluppare o comunque conoscere meglio l'“apt” occorrono quattro package principali:
- com.sun.mirror.apt: per l'interazione con l'utility;
- com.sun.mirror.declaration: per interpretare, nel codice sorgente, le dichiarazioni di metodi, classi, ecc....;
- com.sun.mirror.type: per poter uilizzare le dichiarazioni, precedentemente interpretate;
- com.sun.mirror.utility: utility varie per perfezionare "ad hoc" l'utilizzo dell' APT.
E' importante sottolineare che, se il comando “javac”, è invocato prima dell'ultimo giro di “scanning” dell'”apt”, quest'ultimo restituisce il codice da lui processato, per essere a sua volta nuovamente compilato da “javac”.
Ecco qui di seguito riportati i comandi più importanti da riga di comando che permettono di usare al meglio l'”apt”. Prima di tutto và specificato che valgono tutte le opzioni e i comandi validi per “javac”, ed in più valgono i seguenti comandi specifici:
-s dir : specifica il percorso della directory in cui andranno salvati i file generati dal processore delle annotazioni;
-nocompile: non compila i file sorgente in .CLASS;
-print: si limita a stampare una rappresentazione testuale dei tipi specificati;
-A [ key [ = val ]]: opzioni varie da passare alle annotazioni. Non sono interpretate direttamente da “apt”, ma singolarmente da ogni processore specifico;
-factorypath path: dà le informazioni su dove trovare le specifiche per la creazione di un processore di annotazioni;
-factory classname : è il nome dell' AnnotationProcessorFactory da usare di default.
E ora andiamo più nello specifico, spiegando come è stata realizzata e come usare, la nostra libreria, per essere eseguita da riga di comando.
Prima di tutto c'è da dire che lo scheletro principale è lo stesso che è stato dato per il plugin di Eclipse, solo che, naturalmente, è stato dovuto aggiustare per permetterne l'utilizzo da riga di comando, senza la veste grafica tipica dell'edito Eclipse.
I cinque componenti principali di questa parte di progetto sono: ConditionStatement.java, che riveste lo stesso ruolo della parte di progetto per Eclipse; MyAnnotation.java, che include solamente la definizione per l'interfaccia dell'annotazione; MyAnnotationProcessorFactory.java, che definisce le specifiche per poter processare correttamente l'annotazione MyAnnotation; MyAnnotationProcessor.java, che è il fulcro centrale per lo svolgimento “ad hoc” delle operazione lanciate dall'“apt”; ed infine i pacchetti com e sun , necessari per la corretta compilazione dei .java in .class.
Andiamo ora a descrivere per passi, cosa è stato dovuto fare per creare la libreria “myAnnotation.jar”, e come fare per usarla da riga di comando.
Inanzitutto è stato necessario compilare il file ConditionStatement.java, perchè viene utilizzato nel passo successivo per compilare gli altri file sorgente:
apt (o javac) ConditionStatement.java
successivamente, nella stessa directory dove vi è il file già compilato, ConditionStatement.class, vanno compilati i restanti file necessari per la lbreria, ovvero:
apt MyAnnotation.java MyAnnotationProcessor.java MyAnnotationProcessorFactory.java
a questo punto sono stati creati tutti i file .class, che saranno necessari per creare la nostra libreria. Quindi si crea, col comando jar cvf, il file myAnnotation.jar, contenente tutti i .class, nonché i pacchetti com e sun e una cartella MET-INF, con il file MANIFEST e la cartella services oppurtunamente personalizzati e modificati, al fine di evitare all'utente di digitare per intero tutte le opzioni di compilazione da utilizzare.
A questo punto resta solo da svolgere il lavoro di testing.
Il file .jar, và messo in una directory chiamata lib, all'interno della directory principale contenente i sorgenti da processare con l'”apt”.
Quindi il comando unico da dare sarà:
apt -cp ./lib/myAnnotation.jar FileClassName.java
Il programma darà due messaggi: il primo che avvertirà quando l'”apt” stà generando i file .java e .class, creati specificatamente in base ai metodi e alle annotazioni presenti nel file FileClassName.java; il secondo che avvertirà del corretto funzionamento del programma e indicherà il path dove trovare i file auto-generati.
Per il resto il funzionamento e la logica del programma è la stessa che è stata utilizzata nella realizzazione del plugin per Eclipse, ovvero le operazioni e i processi svolti sui file sono gli stessi, l'unica cosa che è cambiata è il modo di lanciare l'esecuzione di questi processi, che in questo caso sono innescati in automatico da riga di comando con l'”apt”.
Per scaricare quest'esempio, semplice, ma esauriente, cliccare sul link qui sotto:
MyAnnotation.zip ;
esso svolge le operazioni descritte sopra.
|