In questo articolo saranno spiegate le regole della sintassi JavaDoc e la corretta modalità di approccio alla creazione di documentazione HTML tramite l'utilizzo del parser JavaDoc Tool.
Aggiungere commenti nel codice sorgente di ogni classe Java, ma anche di routines COBOL o di sorgenti C ecc., è sempre stata un'attività molto importante per ogni sviluppatore.
Aver documentato bene il codice sorgente dei propri programmi, per esempio, risulta essere stata un mossa fondamentale ed efficace nel momento in cui torneremo a modificare, o implementare, quel progetto; diviene, invece, necessario ricorrere ad un tipo diverso di documentazione, cioè al di fuori dei sorgenti, quando si stanno realizzando delle API che successivamente saranno utilizzate da altri sviluppatori in altri progetti, a meno che non si voglia rendere pubblico il codice sorgente delle proprie API.
E' in questo secondo ambito che il JavaDoc Tool esprime le sue potenzialità perchè parsando l'intera struttura di packages di un progetto Java è in grado di estrapolare i commenti aggiunti al codice sorgente e, creando la documentazione HTML, di organizzarli in una fitta rete di link HTML.
Nota
Questo documento, esclusi i riferimenti storici, è il riassunto in Italiano dell'articolo How to Write Doc Comments for the Javadoc Tool.
Terminologia
Per facilitarmi la scrittura del documento utilizzerò alcuni termini senza tradurli:
- Doc Comment: indica un commento all'interno di un file .java utile alla creazione di JavaDoc.
- JDTool: è un riferimento al tool di creazione dei JavaDoc, il JavaDoc Tool
Un po' di Storia
JavaDoc nacque come strumento interno utilizzato dai ricercatori della Sun che stavano lavorando alla creazione del linguaggio Java e delle sue librerie; la grande mole di sorgenti spinse alcuni membri del team a creare un programma per la generazione automatica di documentazione HTML.
Questo formato infatti consente una navigazione molto efficace e veloce, è molto conosciuto dai programmatori ed è facilmente indicizzabile dai motori di ricerca. Tuttavia, la creazione e manutenzione di una tale mole di pagine web non sarebbe stata pensabile senza l'aiuto di un sistema automatico: basti pensare alla quantità di riferimenti incrociati che ci sono fra le classi (ereditarietà fra classi, firme dei metodi, riferimenti a package solo per citarne alcuni) e agli inevitabili errori di battitura a cui si va incontro scrivendo documentazione.
JavaDoc nacque quindi per permettere ai programmatori di inserire dei frammenti HTML nei commenti (ignorati quindi dal compilatore): già con le prime versioni si potevano inserire le descrizioni di ogni classe e dei suoi metodi, nonché il significato dei parametri e delle variabili membro.
Con il progredire delle versioni JavaDoc diventò sempre più sofisticato e ricco di funzioni:
- inserimento di link, anche a JavaDoc esterni;
- inserimento dell'indicazione @deprecated per segnalare classi e/o metodi destinati a scomparire in future versioni del software;
- opzioni per la formattazione avanzata;
- possibilità di creare le proprie Doclet: estensioni di JavaDoc che permettono di gestire a piacimento le varie fasi di generazione della documentazione;
Le Doclet in particolare permisero ad altre case produttrici di software e ad altri sviluppatori (soprattutto open source) di creare strumenti molto diversificati:
- generazione di schemi UML, grafici di dipendenze fra classi e package, analizzatori di codice (molto utilizzati nell'ingegneria del software);
- generazione di documentazione in formato PDF, Word, RTF, Microsoft Help, LaTeX, ecc.
Il grande successo di JavaDoc è dovuto alla possibilità di poter creare con facilità una documentazione dall'aspetto professionale, del tutto simile a quella ufficiale, anche da parte del principiante, che impara a valorizzare un aspetto spesso sottovalutato della programmazione, cioè la gestione dei documenti relativi ai propri programmi.
I file HTML che vengono generati dalla doclet standard infatti hanno la stessa organizzazione grafica e logica della documentazione che Sun fornisce per le API che essa distribuisce.
Formato di un Doc Comment
Lo strumento per la creazione di documentazione in formato JavaDoc, ossia il Javadoc tool, esegue il parsing dei file .java alla ricerca di speciali Token dai quali leggere le informazioni che desideriamo pubblicare all'interno della nostra documentazione.
Il primo di questi token ad essere cercato è: /** ........ */
A prima vista appare essere un commento multilinea qualunque, ma in realtà ha due asterischi anziché uno nel token di apertura, cioè quanto basta perché qualunque informazione all'interno di questi delimitatori sia processata dal JDTool.
Un doc comment è scritto in HTML e deve precedere le dichiarazioni di classi, proprietà, metodi e costruttori.
Solitamente è composto da 2 aree: una descrizione seguita da delle parti più specifiche marchiate con token particolari che prendono il nome di Tags. Per esempio:
/**
* Restituisce un'immagine che deve essere visualizzata.
* Il parametro url deve essere una {@link URL}
* in formato assoluto.
*
* @author Mirko Agrati
* @version %I%, %G%
* @since 1.0
* @param URL dove risiede l'immagine
* @param Nome del File Immagine
* @return l'immagine corrispondente,
* null se non esiste alcuna immagine
*/
public Image getImage(String url, String filename){..}
Questo facile esempio serve per introdurre le prime regole per la generazione di JavaDoc corretti. Si può affermare che:
- tutto quello contenuto tra /** e */ è l'oggetto del processo di generazione dei JavaDoc;
- ogni riga deve iniziare con un asterisco * (dalla versione 1.4 è possibile ometterli);
- E' possibile utilizzare il tag {@link NOME_CLASSE} per creare un link alla classe NOME_CLASSE;
- E' possibile separare i paragrafi con il tag HTML <p>;
- E' d'obbligo separare la descrizione dalla lista degli altri tag con una riga bianca;
- la prima occorrenza del carattere @ fa si che il JDTool termina l'elaborazione della descrizione;
- può esistere un solo blocco descrittivo, da collocare obbligatoriamente prima della lista dei tag;
La risultante documentazione HTML sarà fedele alla formattazione data ai commenti (unico limite è costituito da paragrafi di 80 colonne).
N.B.: Il JDTool tratta la prima frase del commento descrittivo in maniera particolare, in modo da fare apparire subito a fianco del metodo o classe o proprietà. Quindi è molto importante scrivere la prima frase in maniera concisa ma completa. Questa prima frase termina al primo "." seguito da uno spazio bianco.
Formato di un Doc Comment
Seguono una lista di trucchi e convenzioni per la scrittura di descrizioni nei doc comments.
Utilizzare il tag <code> per nomi e parole chiavi:
E' buona norma enfatizzare keywords e nomi nelle descrizioni racchiudendoli all'interno del tag <code>...</code>.
Questo tag può contenere: Java Keywords (ES: null), nomi di package, di interfacce, di classi, di metodi, di proprietà, di argomenti. E' utilizzato anche per esporre codice Java di esempio.
Non eccedere nell'utilizzo in-line del tag @link:
E' buona norma aggiungere links alle API Java utilizzando il tag {@link}, sebbene non sia obbligatorio. A causa della modalità grafica con cui i link vengono visualizzati (sottolineati e colorati) la documentazione risultante potrebbe essere poco chiara al colpo d'occhio, quindi il tag @link dovrebbe essere utilizzato:
- se si pensa che sia meglio indirizzare l'utente ad approfondire le API utilizzate dalla nostra classe;
- solo per linkare la prima occorrenza dell'API a cui ci si vuole riferire;
- solo per collegare API poco conosciute (ES: inutile linkare il pakage java.lang.String);
Omettere le parentesi per i prototipi di metodi e costruttori:
Quando ci si riferisce ad un metodo o costruttore che ha diversi prototipi e vogliamo riferirci particolarmente ad uno di essi, allora si utilizzano le parentesi ed i Tipi degli argomenti.
Se invece il riferimento è a tutti i prototipi del metodo (o costruttore) allora è buona norma, oltre che convenzione, non utilizzare le parentesi.
Per comprendere meglio si pensi al metodo add della classe ArrayList:
essa espone due metodi add: add(Object) e add(int, Object).
Il primo aggiunge un oggetto in coda alla lista, il secondo metodo
offre la possibilità di scegliere la posizione dove collocare l'oggetto.
Quindi se nella documentazione si vuole descrivere come aggiungere un oggetto alla lista si scriverà: add aggiunge un oggetto alla lista.
Utilizzare lo stile descrittivo:
E' convenzione preferire uno stile breve e descrittivo piuttosto che narrativo. Questo perchè è essenziale avere una documentazione breve, concisa e che metta subito in luce gli aspetti chiave dell'oggetto della nostra descrizione.
Usare la terza persona:
E' buona norma scrivere le descrizioni utilizzando la terza persona singolare in quanto dona un effetto descrittivo a differenza della seconda persona singolare che ha sfumature imperative.
ES:
/** * add Aggiunge un oggetto (corretto). * add Aggiungi un oggetto (sbagliato da evitare). */
Descrivere i metodi iniziando con un verbo:
Un metodo descrive un'operazione, un'azione, quindi solitamente la sua descrizione inizia con un verbo qualificante. ES:
/** * add Aggiunge un oggetto (corretto). * add Il Metodo add aggiunge un oggetto (da evitare). */
Omettere il soggetto nelle descrizioni di Classi, interfacce e Proprietà.
ES:
/** * Bottone di conferma (corretto). * * Questa proprietà rappresenta * un bottone di conferma (da evitare). */
Convenzioni nell'utilizzo dei Tag
Segue l'ordine di utilizzo dei Tag:
- @param (solo classi, interfacce, metodi e costruttori);
- @return (solo metodi);
- @exception (dalla versione 1.2 esiste anche il sinonimo @throws);
- @author (solo classi ed interfacce. OBBLIGATORIO);
- @version (solo classi ed interfacce. OBBLIGATORIO);
- @see
- @since
- @serial
- @deprecated
Ordinare liste di Tag uguali
Capita molto spesso che metodi abbiano in input molteplici argomenti o che si voglia fare più di un riferimento ad API diverse. Il risultato è che si devono ordinare in modo logico liste di tag uguali.
- Molteplici tag @author dovrebbero apparire ordinati cronologicamente, con il creatore della classe in cima alla lista.
- Molteplici tag @param dovrebbero apparire nell'ordine in cui sono dichiarati nel prototipo del metodo o costruttore.
- Molteplici tag @exception dovrebbero apparire ordinati alfabeticamente in base al Nome delle eccezioni che potrebbero essere sollevate.
- Molteplici tag @see dovrebbero essere ordinati in base al punto di accesso più vicino della classe, dall'utilizzo meno qualificato al più specializzato.
Quando è richiesto l'utilizzo dei Tag?
Gli unici Tag il cui utilizzo è obbligatoriamente richiesto a prescindere da ogni situazione sono @author e @version.
Tutti gli altri Tag diventano necessari in base alla situazione che si sta documentando.
- Il Tag @param è richiesto necessariamente per ogni argomento che riceve il metodo o costruttore descritto, anche se la sua descrizione appare ovvia.
- Il Tag @return è richiesto per ogni metodo che restituisce qualcosa di diverso da void, anche se la descrizione risultasse ridondante.
Descrizione dei singoli Tag
@param:
Deve essere seguito dal nome del parametro (e non dal suo Tipo) e completato con una descrizione del parametro. Per convenzione il primo sostantivo presente nella descrizione deve riferirsi al Tipo di dato rappresentato dal parametro, eccezione fatta per i tipi primitivi (interi, boolean ecc....).
Non deve essere utilizzato nessun carattere di punteggiatura prima della descrizione, in quanto il JDTool aggiunge della punteggiatura durante il processo di creazione dei JavaDocs.
Il nome del parametro deve essere scritto in minuscolo, come il tipo da lui rappresentato, in quanto indica un riferimento ad un oggetto piuttosto che ad una classe. ES:
@param ch carattere da testare @param x Coordinata X. Misurata in pixel
@return:
Il Tag deve essere omesso solo per i metodi che non restituiscono niente (void) e per i costruttori. Deve essere presente in ogni altra casistica ed è preferibile documentare eventuali casi limite o speciali.
@throws:
Sostituisce @exception e dovrebbe essere utilizzato per documentare ogni eccezione gestita dal codice e per tutte quelle che ragionevolmente il chiamante si prepara a gestire (per esempio un'istanza della classe java.lang.NullPointerException).ES:
/**
* @throws IOException In caso di errori
* sul byte-streaming
*/
public void open() throws IOException{ ............ }@since:
Dovrebbe essere utilizzato a livello di package, classe o interfaccia.
Non dovrebbe essere utilizzato per i metodi o proprietà, tranne per le successive aggiunte di codice che non erano presenti alla nascita del package, classe o interfaccia.
@deprecated:
La descrizione fornita dovrebbe essere minima, cioè deve giusto notificare che le API in questione non sono da utilizzare ed eventualmente indicare cosa utilizzare in sostituzione tramite il Tag {@link}. Se non vi sono API in sostituzione, la descrizione dovrebbe indicare solo qualcosa del tipo "Non Ancora Rimpiazzate".
Documentare i costruttori di default
Le regole della Buona Programmazione prevedono che non si dovrebbe mai fare uso di costruttori public di default: tutti i costruttori dovrebbero essere espliciti.
Questo perchè solo creando prototipi di costruttori espliciti avremo la possibilità di documentarli e prima ancora, rendendo esplicita la dichiarazione di un costruttore, si impedirebbe un istanziamento non corretto ed utile della classe.
Commenti a livello di package
Con l'avvento di JavaDoc 1.2 è possibile inserire doc comments anche a livello di package. Ogni package può avere il suo file di commento che il JDTool fonderà insieme alla documentazione durante il processo di creazione dei JavaDoc.
Il file per documentare i package deve chiamarsi package.html.
Il nome non cambia mai, rimane lo stesso per ogni package e deve essere posizionato nella cartella madre del package.
Contenuto del file package.html
Questo file dovrebbe fornire tutte le informazioni necessarie per facilitare i programmatori nell'uso del package. Questo file può essere molto importante perchè è il primo punto di accesso alla documentazione per tutti gli utilizzatori delle API.
Lo scopo fondamentale dell'esistenza di questo file è quello di descrivere
i propositi ed i compiti che il package si propone di svolgere, quindi dovrebbe contenere una breve e chiara descrizione delle potenzialità offerte.
Il seguente è il codice sorgente del template che in Sun utilizzano per la creazione dei commenti a livello di package:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!-- @(#)package.html 1.60 98/01/27
CopyrightVersion 1.2 -->
</head>
<body bgcolor="white">
# THIS IS THE TEMPLATE FOR THE PACKAGE DOC COMMENTS. #
# TYPE YOUR PACKAGE COMMENTS HERE. BEGIN WITH A #
# ONE-SENTENCE SUMMARY STARTING WITH A VERB LIKE: #
Provides for....
<h2>Package Specification</h2>
# FILL IN ANY SPECS NEEDED BY JAVA COMPATIBILITY KIT #
<ul>
<li>
<a href="">
# REFER TO ANY FRAMEMAKER SPECIFICATION HERE #
</a></li>
</ul>
<h2>Related Documentation</h2>
For overviews, tutorials, examples, guides,
and tool documentation, please see:
<ul>
<li>
<a href="">
# REFER TO NON-SPEC DOCUMENTATION HERE #
</a></li></ul>
<!-- Put @see and @since tags down here. -->
</body>
</html>
Come si può notare, il Template contiene due sezioni specifiche oltre ad una breve descrizione introduttiva.
La prima sezione, chiamata Package Specification, dovrebbe includere specifiche descrizioni e chiarimenti che non sono presenti nei restanti JavaDoc creati ed eventuali riferimenti a tutte quelle specifiche descritte in documenti esterni.
La seconda sezione, chiamata Related Documentation, può includere riferimenti e/o link a documentazione esterna tipo Tutorial, guide o esempi, materiale che comunque non contiene specifiche ma che può completare la documentazione a supporto degli sviluppatori.
Documentare la classi anonime
Attualmente il JDTool non documenta le classi anonime che incontra nel processo di scansione del codice sorgente, o meglio ignora completamente i doc comments. Quindi, se si vuole fornire una documentazione per queste classi, si è costretti ad aggiungerla alla classe o metodo esterno che le contiene.
Per esempio, se all'interno di un metodo dichiariamo una classe anonima, per documentarla dovremo fornirne una descrizione assieme a quella del metodo
che la contiene.
Un esempio completo di Doc Comments
/**
* Graphics is the abstract base class for all
* graphics contexts which allow an application
* to draw onto components realized on various
*devices or onto off-screen images.
* A Graphics object encapsulates the state
* information needed for the various rendering
* operations that Java supports.
* This state information includes:
* <ul>
* <li>The Component to draw on</li>
* <li>
* A translation origin for rendering and
* clipping coordinates</li>
* <li>The current clip</li>
* <li>The current color</li>
* <li>The current font</li>
* <li>The current logical pixel operation
* function (XOR or Paint)</li>
* <li>The current XOR alternation color
* (see <a href="#setXORMode">setXORMode</a>)</li>
* </ul>
* <p>
* Coordinates are infinitely thin and lie between
* the pixels of the output device.
* Operations which draw the outline of a figure
* operate by traversing along the infinitely thin
* path with a pixel-sized pen that hangs down and
* to the right of the anchor point on the path.
* Operations which fill a figure operate by filling
* the interior of the infinitely thin path.
* Operations which render horizontal text render
* the ascending portion of the characters entirely
* above the baseline coordinate.
* <p>
* Some important points to consider are that drawing
* a figure that covers a given rectangle will occupy
* one extra row of pixels on the right and bottom edges
* compared to filling a figure that is bounded by that
* same rectangle.
* Also, drawing a horizontal line along the same y
* coordinate as the baseline of a line of text will
* draw the line entirely below the text except for
* any descenders.
* Both of these properties are due to the pen hanging
* down and to the right from the path that it traverses.
* <p>
* All coordinates which appear as arguments to the
* methods of this Graphics object are considered relative
* to the translation origin of this Graphics object prior
* to the invocation of the method.
* All rendering operations modify only pixels which lie
* within the
* area bounded by both the current clip of the graphics
* context and the extents of the Component used to create
* the Graphics object.
*
* @author Sami Shaio
* @author Arthur van Hoff
* @version %I%, %G%
* @since 1.0
*/
public abstract class Graphics {
/**
* Draws as much of the specified image as is currently
* available with its northwest corner at the specified
* coordinate (x, y).
* This method will return immediately in all cases,
* even if the entire image has not yet been scaled,
* dithered and converted for the current output device.
* <p>
* If the current output representation is not yet
* complete then the method will return false and the
* indicated {@link ImageObserver} object will be notified
* as the conversion process progresses.
*
* @param img the image to be drawn
* @param x the x-coordinate of the northwest corner
* of the destination rectangle in pixels
* @param y the y-coordinate of the northwest corner
* of the destination rectangle in pixels
* @param observer the image observer to be notified as
* more of the image is converted. May be
* <code>null</code>
* @return <code>true</code> if the image is
* completely loaded and was painted successfully;
* <code>false</code> otherwise.
* @see Image
* @see ImageObserver
* @since 1.0
*/
public abstract boolean drawImage(Image img, int x, int y,
ImageObserver observer);
/**
* Dispose of the system resources used by this graphics
* context. The Graphics context cannot be used after
* being disposed of.
* While the finalization process of the garbage
* collector will also dispose of the same system
* resources, due to the number of Graphics objects that
* can be created in short time frames it is preferable
* to manually free the associated resources using this
* method rather than to rely on a finalization process
* which may not happen for a long period of time.
* <p>
* Graphics objects which are provided as arguments to
* the paint and update methods of Components are
* automatically disposed by the system when those methods
* return.
* Programmers should, for efficiency, call the dispose
* method when finished using a Graphics object only if
* it was created directly from a Component or another
* Graphics object.
*
* @see #create(int, int, int, int)
* @see #finalize()
* @see Component#getGraphics()
* @see Component#paint(Graphics)
* @see Component#update(Graphics)
* @since 1.0
*/
public abstract void dispose();
/**
* Disposes of this graphics context once it is no
* longer referenced.
*
* @see #dispose()
* @since 1.0
*/
public void finalize() {
dispose();
}
}
Personalmente utilizzo spesso la sintassi JavaDoc per documentare classi e metodi dei miei progetti Java e J2EE, sicuramente però non la curo in modo così preciso e minuzioso come sopra descritto.
Alla prossima,
MA