Programmering

Kodegenerering ved hjælp af Javadoc

Automatisk kodegenerering bliver mere og mere almindelig i softwareudvikling, et resultat af behovet for at skjule kompleksitet for softwareudvikleren og accept af forskellige standard- og de facto-standardprogrammeringsgrænseflader til applikationer. Skjuling af kompleksitet fra udvikleren kan demonstreres ved at oprette stub- og skeletklasser i CORBA fra deres definitioner af interface-definitionssprog og af nogle objektorienterede databaser, der opretter den nødvendige adapterkode til at vedvare og hente objekter fra databasen.

Java indeholder mange API'er, som Java-udviklere betragter som de facto-standarder. Kompleksiteten af ​​disse API'er spænder fra dem, der udgør "kernen" i Java-sproget til dem, der findes i Java 2 Platform, Enterprise Edition. For eksempel præsenterer Java Database Connectivity API en samlende grænseflade til interaktion med databaser fra forskellige virksomheder. Antag at du vil have et Java-objekt til at være i stand til at fastholde sig selv til en database ved at implementere en simpel Gemme() metode, der kortlægger objektets attributter til en databasetabel. Denne metode udtrækker attributterne fra objektet og bruger JDBC API til at opbygge en JDBC-sætning, der udføres mod databasen. Efter implementering af Gemme() metode til et par klasser, begynder du at se lighederne i kodestrukturen og den gentagne karakter af implementeringen af ​​denne metode. Ofte skal de grundlæggende attributter for et objekt translitereres og "tilsluttes" til det relevante Java API. Det er da en kodegenerator kan være et nyttigt værktøj at have i din programmeringsværktøjskasse.

Ved at bruge en kodegenerator kan du automatisere processen med nogle kedelige, gentagne og fejlbehæftede kodningsopgaver. Det faktum, at du tilslutter til kendte API'er, øger nytten af ​​et sådant værktøj, da det gælder for et bredt publikum af udviklere. Desuden kan nogle typisk "interne" domænespecifikke rammer også betragtes som faste API-mål for kodegeneratorer.

En kodegenerator kan være et tidsbesparende værktøj, der øger kodekvaliteten og introducerer en mere formel og automatiseret tilgang til en del af udviklingscyklussen. En anden fordel ved automatiseret kodegenerering er synkronisering af objektdefinitioner på tværs af forskellige programmeringssprog. I mange tæt bundne applikationer skal det samme forretningsobjekt (for eksempel en ordre om at købe en aktie) være repræsenteret konsekvent i C ++, Java og SQL. Evnen til at sende forskellige repræsentationer fra en fælles model er tilgængelig i forskellige modelleringsværktøjer; dog har jeg fundet det akavet at bruge disse værktøjer til at opnå det krævede niveau af tilpasning. En dedikeret brugerdefineret kodegenerator er enkel nok til at oprette og binder dig ikke til et specifikt modelleringsværktøj.

Stien til Javadoc

Den vej, mit team tog for at vælge Javadoc til kodegenereringsformål, var noget lang og sandsynligvis almindelig. I tidlige implementeringer brugte vi Perl-scripts til at analysere brugerdefineret metadata-grammatik i en tekstfil. Dette var en ad hoc-løsning, og det var svært at tilføje yderligere outputformater. Vores andet kortvarige forsøg var at ændre en eksisterende Java-baseret IDL-kompilator. Vi indså snart, at der skulle introduceres yderligere IDL-nøgleord for at sende tip til kodegeneratoren. At lave en udvidelse til IDL eller endda starte fra bunden med værktøjer som lex og yacc (som opdeler en kildefil i tokens og definerer kode, der påberåbes for hvert anerkendt token) var ikke personligt velsmagende. (Se ressourcer for mere information.)

En tredje mere lovende løsning var at beskrive klassemetadataene ved hjælp af XML. Definition af et XML DTD-skema og oprettelse af XML-dokumenter til beskrivelse af klasser syntes at være en naturlig pasform. Filen kunne derefter verificeres og let parses. For at undgå at starte fra bunden regnede jeg med, at nogen måtte have forsøgt at oprette en lignende XML DTD, og ​​jeg stødte snart på XMI. XMI er en fuldstændig beskrivelse af UML ved hjælp af XML, og den bruges nu som et udvekslingsformat mellem UML-værktøjer. (Se ressourcer for mere information.)

Imidlertid var XML-dokumenterne, der beskrev klasser, ekstremt detaljerede og vanskelige at redigere manuelt. Der er simpelthen for mange tilsyneladende overflødige tags og beskrivelser til at luge igennem for at du kan ændre en klasseattribut. Det kan også være ret kedeligt at manipulere XML-filer på applikationsdomæneniveau. IBM alphaWorks producerer et XMI-værktøjssæt, der gør behandlingen af ​​XMI-baserede XML-dokumenter meget lettere, men XMI-værktøjssæt-API til manipulation af klassebeskrivelser ligner meget Java Reflection eller Doclet API. Med det i tankerne besluttede min organisation at bruge doclet-metoden, som har været en succes.

Introduktion til Javadoc

Javadoc er det program, der bruges til at oprette HTML-API-dokumentationen til Java API. Det distribueres som en del af Java SDK, og dets outputtrin er designet til at være udvideligt gennem oprettelse af dokler. Doclet API giver infrastrukturen til at få adgang til alle aspekter af en Java-kildekodefil, der er blevet parset af Javadoc. Ved at bruge Doclet API, der ligner Reflection API, kan du gå gennem en Java-klassebeskrivelse, få adgang til brugerdefinerede Javadoc-tags og skrive output til en fil. Standarddoklen, der bruges til at producere HTML-dokumentationen, gør netop det; det skriver ud HTML-filer, når det krydser al Java-kildekoden. Mere detaljerede oplysninger om Javadoc findes i Ressourcer.

Ved at oprette enkle Java-klasser, der indeholder attributter og nogle brugerdefinerede Javadoc-tags, tillader du disse klasser at fungere som en simpel metadatabeskrivelse til kodegenerering. Javadoc analyserer disse metadata-klasser, og brugerdefinerede doclets får adgang til metadata-klassens information for at skabe konkrete implementeringer af metadata-klassen i bestemte programmeringssprog som Java, C ++ eller SQL. Du kan også oprette variationer af standarddokletten, der producerer enkle HTML-tabeller, der beskriver metadataklassen, hvilket ville være passende at medtage i et tekstbehandlingsdokument. Disse metadata Java-klasser tjener det samme formål som en IDL-beskrivelse, hvis syntaks svarer til C ++.

Brug af Javadoc som et kodegenereringsværktøj har flere fordele:

  • Du behøver ikke at skrive nogen parsingskode; parsing af metadataklasser udføres af Javadoc og præsenteres i et brugervenligt API.
  • Ved at bruge tilpassede Javadoc-tags tilføjer du lige nok fleksibilitet til at definere specielle kroge under kodegenerering.
  • Da Java-typer er veldefinerede, er int int 32 bits; Derfor behøver du ikke introducere flere primitive nøgleord for at opnå dette klarhedsniveau.
  • Du kan kontrollere Java-metadataklasser for syntaks og andre fejl ved kompilering.

Introduktion til doclets

Før jeg hopper ind i den doclet, der bruges til kodegenerering, præsenterer jeg et simpelt "Hello World" -eksempel, der afslører de relevante dele af, hvordan man opretter, kører og spiller med Doclet API. Eksempelkoden til SimpleDoclet er angivet nedenfor. (Du kan få kildekoden til denne artikel i Ressourcer.) Hvis du finder denne kode noget langvarig til et ægte "Hello World" -program, præsenterer Sun-webstedet en endnu enklere doklet til at hjælpe dig i gang. (Se ressourcer.)

pakke codegen.samples; import com.sun.javadoc. *; importer java.text. *; offentlig statisk boolsk start (RootDoc-rod) {// itererer over alle klasser. ClassDoc [] klasser = root.classes (); for (int i = 0; i <klasser.længde; i ++) {// gentages over alle metoder og udskriver deres navne. MethodDoc [] metoder = klasser [i] .metoder (); ud ("Metoder"); ud("-------"); for (int j = 0; j

Ovenstående doklet udskriver beskrivende information om klasser, metoder, felter og nogle Javadoc-tagoplysninger om klassen SimpleOrder.java anført nedenfor:

public class SimpleOrder {public SimpleOrder () {} public String getSymbol () {return Symbol; } public int getQuantity () {{escriptive return Quantity; } / ** * Et gyldigt aktiesymbol. * * @se En stor bog med gyldige symboler for mere information. * / privat streng symbol; / ** * Den samlede ordremængde. * * @mytag Min brugerdefinerede tag. * / privat int Mængde; privat streng ordretype; private flyde Pris; privat strengvarighed privat int Kontotype; privat int TransactionType; } 

Efter kompilering af disse filer påberåber du Javadoc-værktøjet ved hjælp af denne kommando:

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

Det -privat indstilling beder Javadoc om at eksponere private felt- og metodeoplysninger og -doktor mulighed fortæller Javadoc, hvilken doktor der skal påberåbes. Den sidste parameter er den fil, der skal parses. Programmets output er følgende:

Indlæser kildefil SimpleOrder.java ... Konstruerer Javadoc-oplysninger ... Metoder ------- Metode: navn = getSymbol Metode: navn = getQuantity Felter ------ Felt: navn = Symbol, kommentar = A gyldig aktiesymbol., type = java.lang.String; Field Tag Name = @see Field Tag Value = En stor bog med gyldige symboler for mere information. Felt: navn = Mængde, kommentar = Den samlede ordrevolumen., Type = int; Field Tag Name = @mytag Field Tag Value = Mit brugerdefinerede tag. Felt: navn = OrderType, comment =, type = java.lang.String; Felt: navn = pris, kommentar =, type = float; Felt: navn = Varighed, kommentar =, type = java.lang.String; Felt: navn = Kontotype, kommentar =, type = int; Felt: navn = Transaktionstype, kommentar =, type = int; 

Eksempelkoden viser, at Doclet API er indeholdt i pakken com.sun.javadoc. Da du tilslutter til Javadoc-værktøjet og ikke opretter et enkeltstående program, kalder Javadoc din doclet fra metoden offentlig statisk boolsk start (RootDoc-rod).

En gang Start metoden udføres, RootDoc har alle de oplysninger, der er analyseret af Javadoc. Du kan derefter begynde at gå gennem alle de parsede klasser ved at påkalde metoden klasser ()RootDoc. Denne metode returnerer a ClassDoc array, der beskriver alle de parsede klasser. ClassDoc indeholder igen metoder som f.eks felter() og metoder(). Disse metoder vender tilbage FieldDoc og MetodeDok arrays, der beskriver alle felter og metoder i den parsede klasse. Alle "Doc" -klasser indeholder metoden tags, som returnerer en Tag array, der beskriver både brugerdefinerede og standard Javadoc tags. Standardmærket, der bruges i dette eksempel, er @se.

Det ud() metoden blot indpakker standard output, og MessageFormat klasse hjælper med at formatere output i henhold til en fast skabelon.

Genanvendelige klasser til generering af kode

I lyset af ovenstående eksempel håber jeg, at du er enig i at det er let at oprette dine egne doclets og udtrække klasseoplysninger ved hjælp af Doclet API. Det næste trin til at analysere Java-klasser og generere kode til en fil er relativt ligetil. For at gøre det lettere at oprette kodegenereringsdoketter udviklede jeg et lille sæt grænseflader og abstrakte baseklasser. Klassediagrammet for disse hjælpeklasser er vist nedenfor.

Grænsefladen Maker definerer metodesignaturen offentligt ugyldigt mærke (ClassDoc classdoc) som du vil bruge til at interagere med dine kodegeneratorer. Den abstrakte klasse CodeMaker giver standardimplementeringer til manipulation af filer og indention, som er fælles for alle kodegeneratorer. Specifikke kodegeneratorer arver fra den abstrakte basisklasse og giver en implementering af lave metode. Det lave metoden har klassen ClassDoc som et argument, ikke RootDoc. Det forårsager Maker for at indtaste kodegenerationslogikken på klasseniveau.

Alle klasser, der er analyseret af Javadoc, overføres i plugin-metoden til doclets Start. Et eksempel på hvordan det gøres (beskrevet i filen SimpleMakerDoclet.java) er vist nedenfor:

offentlig statisk boolsk start (RootDoc-rod) {ClassDoc [] klasser = root.classes (); // Opsæt CodeMakers til at køre Maker simplemaker = ny SimpleCodeMaker ("Description Maker"); // Iterér gennem alle klasser og udfør "make" -metoden, som Maker til (int i = 0; i <klasser.længde; i ++) {ClassDoc classdoc = klasser [i]; simplemaker.make (classdoc); } returner sandt } 

Følgende er dele af koden fra en simpel kodegenerator kaldet SimpleCodeMaker, der udfører den samme opgave som SimpleDoclet tidligere nævnt. I stedet for at sende output til skærmen, SimpleCodeMaker gemmer det i en fil i underkataloget genklasser. Gennemførelsen af lave Metoden bliver også mere struktureret med separate metoder til at behandle felter og metoder. Kun metoderne lave og processMethods er angivet her for kortfattethed.