Programmering

Kodegenerering ved bruk av Javadoc

Automatisk kodegenerering blir stadig mer vanlig i programvareutvikling, et resultat av behovet for å skjule kompleksitet for programvareutvikleren og aksept av forskjellige standard og de facto standard applikasjonsprogrammeringsgrensesnitt. Skjuling av kompleksitet fra utvikleren kan demonstreres ved å opprette stub- og skjelettklasser i CORBA fra deres grensesnittdefinisjonsspråkbeskrivelser og av noen objektorienterte databaser som lager den nødvendige adapterkoden for å vedvare og hente gjenstander fra databasen.

Java inneholder mange API-er som Java-utviklere anser som de facto-standarder. Kompleksiteten til disse API-ene varierer fra de som utgjør "kjernen" i Java-språket til de som finnes i Java 2 Platform, Enterprise Edition. For eksempel presenterer Java Database Connectivity API et samlende grensesnitt for samhandling med databaser fra forskjellige selskaper. Anta at du vil at et Java-objekt skal kunne vedvare seg til en database ved å implementere en enkel lagre() metode som tilordner objektets attributter til en databasetabell. Denne metoden vil trekke ut attributtene fra objektet og bruke JDBC API for å bygge opp en JDBC-setning som kjøres mot databasen. Etter å ha implementert lagre() metode for noen få klasser, begynner du å se likhetene i kodestrukturen og den gjentatte karakteren av å implementere den metoden. Ofte trenger de grunnleggende egenskapene til et objekt å bli omskrevet og "plugget inn" til riktig Java API. Det er da en kodegenerator kan være et nyttig verktøy å ha i programmeringsverktøykassen.

Ved å bruke en kodegenerator kan du automatisere prosessen med noen kjedelige, repeterende og feilutsatte kodingsoppgaver. Det at du kobler til kjente API-er øker nytten av et slikt verktøy, siden det gjelder for et bredt publikum av utviklere. Videre kan noen typisk "interne" domenespesifikke rammer også betraktes som faste API-mål for kodegeneratorer.

En kodegenerator kan være et tidsbesparende verktøy som øker kodekvaliteten og introduserer en mer formell og automatisert tilnærming til en del av utviklingssyklusen. En annen fordel med automatisk kodegenerering er synkronisering av objektdefinisjoner på tvers av forskjellige programmeringsspråk. I mange tettbundne applikasjoner må det samme forretningsobjektet (for eksempel en ordre om å kjøpe en aksje) være representert konsekvent i C ++, Java og SQL. Evnen til å sende forskjellige representasjoner fra en felles modell er tilgjengelig i forskjellige modelleringsverktøy; Imidlertid har jeg funnet det vanskelig å bruke disse verktøyene for å oppnå ønsket tilpasningsnivå. En dedikert tilpasset kodegenerator er enkel nok til å lage og knytter deg ikke til et bestemt modelleringsverktøy.

Stien til Javadoc

Veien teamet mitt tok for å velge Javadoc for kodegenereringsformål var noe lang og sannsynligvis vanlig. I de tidlige implementeringene brukte vi Perl-skript for å analysere tilpasset metadata-grammatikk i en tekstfil. Dette var en ad hoc-løsning, og det var vanskelig å legge til flere utdataformater. Vårt andre kortvarige forsøk var å endre en eksisterende Java-basert IDL-kompilator. Vi innså snart at flere IDL-nøkkelord måtte innføres for å sende hint til kodegeneratoren. Å lage en utvidelse til IDL, eller til og med starte fra bunnen av med verktøy som lex og yacc (som deler en kildefil i tokens og definerer kode som påkalles for hvert anerkjent token) var ikke personlig velsmakende. (Se Ressurser for mer informasjon.)

En tredje mer lovende løsning var å beskrive klassemetadataene ved hjelp av XML. Å definere et XML DTD-skjema og lage XML-dokumenter for å beskrive klasser virket som en naturlig passform. Filen kan deretter bekreftes og enkelt analyseres. For å unngå å starte fra bunnen av, skjønte jeg at noen måtte ha prøvd å lage en lignende XML DTD, og ​​jeg kom snart over XMI. XMI er en fullstendig beskrivelse av UML ved bruk av XML, og den brukes nå som et utvekslingsformat mellom UML-verktøy. (Se Ressurser for mer informasjon.)

Imidlertid var XML-dokumentene som beskrev klassene ekstremt omfattende og vanskelige å redigere manuelt. Det er rett og slett for mange tilsynelatende overflødige koder og beskrivelser å lukke igjennom for at du skal kunne endre en klasseattributt. Å manipulere XML-filer på applikasjonsdomenenivå kan også være kjedelig. IBM alphaWorks produserer en XMI-verktøykasse som gjør behandlingen av XMI-baserte XML-dokumenter mye enklere, men XMI toolkit API for å manipulere klassebeskrivelser ligner ekstremt Java Reflection eller Doclet API. Med det i bakhodet bestemte organisasjonen min seg for å bruke doklettilnærmingen, som har vært vellykket.

Vi presenterer Javadoc

Javadoc er programmet som brukes til å lage HTML-format Java API-dokumentasjon. Den distribueres som en del av Java SDK, og utgangstrinnet er designet for å være utvidbart gjennom opprettelse av dokler. Doclet API gir infrastrukturen for å få tilgang til alle aspekter av en Java-kildekodefil som er blitt analysert av Javadoc. Ved å bruke Doclet API, som ligner på Reflection API, kan du gå gjennom en Java-klassebeskrivelse, få tilgang til tilpassede Javadoc-koder og skrive utdata til en fil. Standard dokletten som brukes til å produsere HTML-dokumentasjonen gjør nettopp det; den skriver ut HTML-filer når den krysser all Java-kildekoden. Mer detaljert informasjon om Javadoc finner du i Resources.

Ved å lage enkle Java-klasser som inneholder attributter og noen tilpassede Javadoc-koder, lar du disse klassene fungere som en enkel metadatabeskrivelse for kodegenerering. Javadoc analyserer disse metadataklassene, og egendefinerte doclets får tilgang til informasjonen om metadataklassen for å lage konkrete implementeringer av metadataklassen i spesifikke programmeringsspråk som Java, C ++ eller SQL. Du kan også lage varianter av standarddokletten som produserer enkle HTML-tabeller som beskriver metadataklassen, noe som vil være hensiktsmessig å inkludere i et tekstbehandlingsdokument. Disse metadata-Java-klassene tjener samme formål som en IDL-beskrivelse hvis syntaks ligner på C ++.

Å bruke Javadoc som et kodegenereringsverktøy har flere fordeler:

  • Du trenger ikke skrive noen analysekode; analysering av metadataklassene utføres av Javadoc, og presenteres i et brukervennlig API.
  • Ved å bruke tilpassede Javadoc-koder, legger du til akkurat nok fleksibilitet til å definere spesielle kroker under kodegenerering.
  • Siden Java-typer er veldefinerte, er int 32 bits; Derfor trenger du ikke å introdusere flere primitive søkeord for å oppnå dette klarhetsnivået.
  • Du kan sjekke Java-metadataklassene for syntaks og andre feil ved kompilering.

Vi introduserer dokler

Før jeg hopper inn i docleten som brukes til kodegenerering, skal jeg presentere et enkelt "Hello World" -eksempel som avslører de relevante delene av hvordan du lager, kjører og spiller med Doclet API. Eksempelkoden for SimpleDoclet er gitt nedenfor. (Du kan få kildekoden til denne artikkelen i Resources.) Hvis du anser denne koden noe langvarig for et ekte "Hello World" -program, presenterer Sun-nettstedet en enda enklere fil for å hjelpe deg i gang. (Se ressurser.)

pakke codegen.samples; importer com.sun.javadoc. *; importer java.text. *; offentlig statisk boolsk start (RootDoc-rot) {// iterere over alle klasser. ClassDoc [] klasser = root.classes (); for (int i = 0; i <klasser.lengde; i ++) {// itererer over alle metoder og skriver ut navnene deres. MethodDoc [] metoder = klasser [i] .metoder (); ut ("Metoder"); ute("-------"); for (int j = 0; j

Dokumentet ovenfor skriver ut beskrivende informasjon om klassene, metodene, feltene og noe Javadoc-taginformasjon for klassen SimpleOrder.java oppført nedenfor:

offentlig klasse SimpleOrder {offentlig SimpleOrder () {} offentlig String getSymbol () {retur Symbol; } public int getQuantity () {{escriptive return Quantity; } / ** * Et gyldig aksjesymbol. * * @see En stor bok med gyldige symboler for mer informasjon. * / privat streng symbol; / ** * Det totale ordrevolumet. * * @mytag Min egendefinerte tag. * / private int Mengde; privat streng ordretype; privat flyter Pris; privat strengvarighet; private int AccountType; privat int TransactionType; } 

Etter å ha samlet disse filene, påkaller du Javadoc-verktøyet ved hjelp av denne kommandoen:

javadoc -private -doclet codegen.samples.SimpleDoclet SimpleOrder.java 

De -privat alternativet ber Javadoc om å avsløre privat felt- og metodeinformasjon, og doktor alternativet forteller Javadoc hvilken dokumentasjon som skal påberopes. Den siste parameteren er filen som skal analyseres. Resultatet av programmet er følgende:

Laster inn kildefilen SimpleOrder.java ... Konstruerer Javadoc-informasjon ... Metoder ------- Metode: navn = getSymbol Metode: navn = getKvantitetsfelt ------ Felt: navn = Symbol, kommentar = A gyldig aksjesymbol., type = java.lang.String; Field Tag Name = @see Field Tag Value = En stor bok med gyldige symboler for mer informasjon. Felt: navn = Antall, kommentar = Det totale ordrevolumet., Type = int; Field Tag Name = @mytag Field Tag Value = Min egendefinerte tag. Felt: navn = OrderType, comment =, type = java.lang.String; Felt: navn = Pris, kommentar =, type = flyt; Felt: navn = Varighet, kommentar =, type = java.lang.String; Felt: navn = Kontotype, kommentar =, type = int; Felt: navn = Transaksjonstype, kommentar =, type = int; 

Eksempelkoden viser at Doclet API er inneholdt i pakken com.sun.javadoc. Siden du kobler til Javadoc-verktøyet og ikke oppretter et frittstående program, kaller Javadoc docleten din fra metoden offentlig statisk boolsk start (RootDoc ​​root).

Først når start metoden kjøres, RootDoc har all informasjon analysert av Javadoc. Du kan da begynne å gå gjennom alle de analyserte klassene ved å påkalle metoden klasser ()RootDoc. Den metoden returnerer a ClassDoc matrise som beskriver alle de analyserte klassene. ClassDoc inneholder igjen metoder som Enger() og metoder (). Disse metodene kommer tilbake FieldDoc og MetodeDok arrays som beskriver alle felt og metoder i den analyserte klassen. Alle "Doc" -klassene inneholder metoden koder, som returnerer a stikkord array som beskriver både tilpassede og standard Javadoc-koder. Standard koden som brukes i dette eksemplet er @se.

De ute() metoden bare vikler standard utdata, og MessageFormat klasse hjelper deg med å formatere utdataene i henhold til en fast mal.

Gjenbrukbare klasser for kodegenerering

I lys av eksemplet ovenfor håper jeg at du er enig i at det er enkelt å lage dine egne doclets og trekke ut klasseinformasjonen ved hjelp av Doclet API. Det neste trinnet for å analysere Java-klassene og generere kode til en fil er relativt grei. For å gjøre det lettere å lage kodegenereringsdokler, utviklet jeg et lite sett med grensesnitt og abstrakte baseklasser. Klassediagrammet for disse bruksklassene er vist nedenfor.

Grensesnittet Maker definerer metodesignaturen offentlig ugyldig merkevare (ClassDoc classdoc) som du vil bruke til å samhandle med kodegeneratorene dine. Den abstrakte klassen CodeMaker gir standardimplementeringer for manipulering av filer og innrykk, som er felles for alle kodegeneratorer. Spesifikke kodegeneratorer arver fra den abstrakte baseklassen og gir en implementering av gjøre metode. De gjøre metoden har klassen ClassDoc som argument, ikke RootDoc. Det forårsaker Maker for å legge inn loggen for kodegenerering på klassenivå.

Alle klasser som er analysert av Javadoc, sløyfes i plugin-metoden for doclets start. Et eksempel på hvordan det gjøres (beskrevet i filen SimpleMakerDoclet.java) er vist nedenfor:

offentlig statisk boolsk start (RootDoc-rot) {ClassDoc [] klasser = root.classes (); // Sett opp CodeMakers til å kjøre Maker simplemaker = ny SimpleCodeMaker ("Description Maker"); // Iterer gjennom alle klasser og utfører "make" -metoden Maker for (int i = 0; i <class.length; i ++) {ClassDoc classdoc = class [i]; simplemaker.make (classdoc); } returner sant; } 

Følgende er deler av koden fra en enkel kodegenerator kalt SimpleCodeMaker, som utfører samme oppgave som SimpleDoclet tidligere oppført. I stedet for å sende utdataene til skjermen, SimpleCodeMaker lagrer den i en fil i underkatalogen genklasser. Gjennomføringen av gjøre metoden blir også mer strukturert med separate metoder for å behandle felt og metoder. Bare metodene gjøre og prosessMetoder er oppført her for kortfattethet.

$config[zx-auto] not found$config[zx-overlay] not found