Uvod u JavaPoet

1. Pregled

U ovom uputstvu istražit ćemo osnovne funkcionalnosti biblioteke JavaPoet.

JavaPoet razvija Square, koji pruža API-je za generiranje Java izvornog koda. Može generirati primitivne tipove, referentne tipove i njihove varijante (poput klasa, sučelja, nabrojanih tipova, anonimnih unutarnjih klasa), polja, metode, parametre, napomene i Javadocs.

JavaPoet automatski upravlja uvozom ovisnih klasa. Također koristi obrazac Builder za određivanje logike za generiranje Java koda.

2. Ovisnost Mavena

Da bismo koristili JavaPoet, možemo izravno preuzeti najnoviju JAR datoteku ili definirati sljedeću ovisnost u našoj pom.xml:

 com.squareup javapoet 1.10.0 

3. Specifikacija metode

Prvo, prođimo kroz specifikaciju metode. Da bismo generirali metodu, jednostavno pozivamo methodBuilder () metoda MethodSpec razred. Generirano ime metode navodimo kao Niz argument methodBuilder () metoda.

Možemo generirati bilo koji logički izraz koji završava sa zarezom koristiti addStatement () metoda. U međuvremenu možemo definirati jedan kontrolni tok ograničen kovrčavim zagradama, kao što je ako-drugo blok, ili za petlja, u kontrolnom toku.

Evo kratkog primjera - generiranje sumOfTen () metoda koja će izračunati zbroj brojeva od 0 do 10:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addStatement ("int sum = 0") .beginControlFlow ("for (int i = 0; i <= 10; i ++)") .addStatement ("sum + = i" ) .endControlFlow () .build ();

To će proizvesti sljedeći rezultat:

void sumOfTen () {int sum = 0; za (int i = 0; i <= 10; i ++) {zbroj + = i; }}

4. Blok koda

Možemo i mi zamotati jedan ili više kontrolnih tokova i logičkih izraza u jedan blok koda:

CodeBlock sumOfTenImpl = CodeBlock .builder () .addStatement ("int sum = 0") .beginControlFlow ("for (int i = 0; i <= 10; i ++)") .addStatement ("sum + = i") .endControlFlow () .build ();

Što generira:

int zbroj = 0; za (int i = 0; i <= 10; i ++) {zbroj + = i; }

Možemo pojednostaviti raniju logiku u MethodSpec pozivanjem addCode () i pružanje sumOfTenImpl objekt:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addCode (sumOfTenImpl) .build ();

Blok koda također je primjenjiv na druge specifikacije, kao što su vrste i Javadocs.

5. Specifikacija polja

Dalje - istražimo logiku specifikacije polja.

Da bismo generirali polje, koristimo graditelj() metoda FieldSpec razred:

FieldSpec name = FieldSpec .builder (String.class, "name") .addModifiers (Modifier.PRIVATE) .build ();

Ovo će generirati sljedeće polje:

privatni naziv niza;

Također možemo inicijalizirati zadanu vrijednost polja pozivajući inicijalizator () metoda:

FieldSpec defaultName = FieldSpec .builder (String.class, "DEFAULT_NAME") .addModifiers (Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) .inicializer ("\" Alice \ "") .build ();

Što generira:

privatni statički završni niz DEFAULT_NAME = "Alice";

6. Specifikacija parametra

Istražimo sada logiku specifikacije parametara.

U slučaju da metodi želimo dodati parametar, možemo pozvati addParameter () unutar lanca poziva funkcije u graditelju.

U slučaju složenijih vrsta parametara, možemo se poslužiti ParameterSpec graditelj:

ParameterSpec stringovi = ParameterSpec .builder (ParameterizedTypeName.get (ClassName.get (List.class), TypeName.get (String.class)), "stringovi") .build ();

Također možemo dodati modifikator metode, kao što je javnost i / ili statički:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addParameter (int.class, "number") .addParameter (stringovi) .addModifiers (Modifier.PUBLIC, Modifier.STATIC) .addCode (sumOfTenImpl) .build (build)).

Evo kako izgleda generirani Java kôd:

javna statička void sumOfTen (int broj, nizovi popisa) {int sum = 0; za (int i = 0; i <= 10; i ++) {zbroj + = i; }}

7. Specifikacija tipa

Nakon istraživanja načina generiranja metoda, polja i parametara, pogledajmo sada specifikacije tipa.

Da bismo deklarirali tip, možemo koristiti TypeSpec koji mogu graditi klase, sučelja i pobrojane tipove.

7.1. Generiranje razreda

Da bismo generirali klasu, možemo koristiti classBuilder () metoda TypeSpec razred.

Također možemo odrediti njegove modifikatore, na primjer, javnost i konačni modifikatori pristupa. Pored modifikatora klasa, također možemo odrediti polja i metode koristeći već spomenute FieldSpec i MethodSpec razreda.

Imajte na umu da addField () i addMethod () metode su također dostupne prilikom generiranja sučelja ili anonimnih unutarnjih klasa.

Pogledajmo sljedeći primjer graditelja klasa:

TypeSpec person = TypeSpec .classBuilder ("Person") .addModifiers (Modifier.PUBLIC) .addField (name) .addMethod (MethodSpec .methodBuilder ("getName") .addModifiers (Modifier.PUBLIC). Vraća (String.class). ("return this.name") .build ()) .addMethod (MethodSpec .methodBuilder ("setName") .addParameter (String.class, "name") .addModifiers (Modifier.PUBLIC) .vraća (String.class). addStatement ("this.name = name") .build ()) .addMethod (sumOfTen) .build ();

A evo kako izgleda generirani kod:

javni razred Osoba {ime privatnog niza; javni String getName () {return this.name; } javni String setName (ime niza) {this.name = name; } javna statička void sumOfTen (int broj, nizovi popisa) {int sum = 0; za (int i = 0; i <= 10; i ++) {zbroj + = i; }}}

7.2. Generiranje sučelja

Za generiranje Java sučelja koristimo interfaceBuilder () metoda TypeSpec.

Također možemo definirati zadanu metodu specificiranjem ZADANO vrijednost modifikatora u addModifiers ():

TypeSpec person = TypeSpec .interfaceBuilder ("Person") .addModifiers (Modifier.PUBLIC) .addField (defaultName) .addMethod (MethodSpec .methodBuilder ("getName") .addModifiers (Modifier.PUBLIC, Modifier.ABSTRACT) .build .addMethod (MethodSpec .methodBuilder ("getDefaultName") .addModifiers (Modifier.PUBLIC, Modifier.DEFAULT) .addCode (CodeBlock .builder () .addStatement ("return DEFAULT_NAME") .build ()) .build ()) .build ();

Generirat će sljedeći Java kôd:

javno sučelje Osoba {private static final String DEFAULT_NAME = "Alice"; void getName (); zadana void getDefaultName () {return DEFAULT_NAME; }}

7.3. Generiranje enuma

Da bismo generirali nabrojani tip, možemo koristiti enumBuilder () metoda TypeSpec. Da bismo odredili svaku nabrojanu vrijednost, možemo nazvati addEnumConstant () metoda:

TypeSpec gender = TypeSpec .enumBuilder ("Gender") .addModifiers (Modifier.PUBLIC) .addEnumConstant ("MALE") .addEnumConstant ("FEMALE") .addEnumConstant ("UNSPECIFIED") .build ();

Izlaz gore spomenutog enumBuilder () logika je:

javni popis Spol {MUŠKI, ŽENSKI, NESPUNJENI}

7.4. Generiranje anonimne unutarnje klase

Da bismo generirali anonimnu unutarnju klasu, možemo koristiti anonymousClassBuilder () metoda TypeSpec razred. Imajte na umu da moramo navesti roditeljsku klasu u addSuperinterface () metoda. U suprotnom, koristit će zadanu roditeljsku klasu, koja je Objekt:

TypeSpec comparator = TypeSpec .anonymousClassBuilder ("") .addSuperinterface (ParameterizedTypeName.get (Comparator.class, String.class)) .addMethod (MethodSpec .methodBuilder ("compare") .addModifiers (Modifier.PUBLIC) .addSuperinterface. , "a") .addParameter (String.class, "b"). vraća se (int.class) .addStatement ("return a.length () - b.length ()") .build ()) .build () ;

Ovo će generirati sljedeći Java kôd:

new Comparator () {public int compare (String a, String b) {return a.length () - b.length (); }});

8. Specifikacija bilješke

Da bismo dodali napomenu generiranom kodu, možemo nazvati addAnnotation () metoda u a MethodSpec ili FieldSpec graditeljska klasa:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addAnnotation (Override.class) .addParameter (int.class, "number") .addParameter (stringovi) .addModifiers (Modifier.PUBLIC, Modifier.STATIC) .addCen (ID) .izgraditi();

Što generira:

@Override public static void sumOfTen (int broj, nizovi popisa) {int sum = 0; za (int i = 0; i <= 10; i ++) {zbroj + = i; }}

U slučaju da trebamo navesti vrijednost člana, možemo nazvati addMember () metoda AnnotationSpec razred:

AnnotationSpec toString = AnnotationSpec .builder (ToString.class) .addMember ("izuzeti", "\" ime \ "") .build ();

Ovo će generirati sljedeću napomenu:

@ToString (izuzeti = "ime")

9. Generiranje Javadocs-a

Javadoc se može generirati pomoću CodeBlock, ili izravnom specifikacijom vrijednosti:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addJavadoc (CodeBlock .builder () .add ("Zbroj svih cijelih brojeva od 0 do 10") .build ()) .addAnnotation (Override.class) .addParameter (int. klasa, "broj") .addParameter (nizovi) .addModifiers (Modifier.PUBLIC, Modifier.STATIC) .addCode (sumOfTenImpl) .build ();

Ovo će generirati sljedeći Java kôd:

/ ** * Zbroj svih cijelih brojeva od 0 do 10 * / @ Prekrivaj javnu statičku prazninu sumOfTen (int broj, nizovi popisa) {int sum = 0; za (int i = 0; i <= 10; i ++) {zbroj + = i; }}

10. Oblikovanje

Ponovno provjerimo primjer FieldSpec inicijalizator u odjeljku 5 koji sadrži znak za bijeg koji se koristi za bijeg od "Alice" Niz vrijednost:

inicijalizator ("\" Alice \ "")

Također je sličan primjer u odjeljku 8 kada definiramo izuzeti član bilješke:

addMember ("izuzeti", "\" ime \ "")

Postaje nezgrapan kad naš JavaPoet kod raste i ima puno sličnih Niz pobjeći ili Niz izjave o spajanju.

Značajka formatiranja niza u JavaPoetu čini Niz formatiranje u beginControlFlow (), addStatement () ili inicijalizator () metode lakše. Sintaksa je slična String.format () funkcionalnost u Javi. Može vam pomoći u oblikovanju doslovnih riječi, nizova, vrsta i imena.

10.1. Doslovno oblikovanje

JavaPoet zamjenjuje $ L s doslovnom vrijednošću u izlazu. Možemo odrediti bilo koji primitivni tip i Niz vrijednosti u argumentima:

private MethodSpec generirajSumMethod (ime niza, int od, int do, operator niza) {return MethodSpec .methodBuilder (ime) .vraća (int.class) .addStatement ("int sum = 0") .beginControlFlow ("for (int i = $ L; i <= $ L; i ++) ", od, do) .addStatement (" sum = sum $ L i ", operator) .endControlFlow () .addStatement (" return sum ") .build (); }

U slučaju da nazovemo generirajSumMethod () sa navedenim sljedećim vrijednostima:

generirajSumMethod ("sumOfOneHundred", 0, 100, "+");

JavaPoet će generirati sljedeći izlaz:

int sumOfOneHundred () {int zbroj = 0; za (int i = 0; i <= 100; i ++) {zbroj = zbroj + i; } povratna suma; }

10.2. Niz Oblikovanje

Niz formatiranje generira vrijednost s navodnicima, koji se odnose isključivo na Niz upišite na Javi. JavaPoet zamjenjuje $ S s Niz vrijednost u izlazu:

privatni statički MethodSpec generiraStringSupplier (StringNaziv metode, StringNameName) {return MethodSpec .methodBuilder (methodName) .returns (String.class) .addStatement ("return $ S", fieldName) .build (); }

U slučaju da nazovemo generirajGetter () metodu i navedite ove vrijednosti:

generirajStringSupplier ("getDefaultName", "Bob");

Dobit ćemo sljedeći generirani Java kôd:

String getDefaultName () {return "Bob"; }

10.3. Oblikovanje tipa

JavaPoet zamjenjuje $ T s tipom u generiranom Java kodu. JavaPoet automatski obrađuje vrstu u izjavi o uvozu. Da smo umjesto toga dali tip kao doslovni, JavaPoet se ne bi bavio uvozom.

MethodSpec getCurrentDateMethod = MethodSpec .methodBuilder ("getCurrentDate") .vraća (Date.class) .addStatement ("return new $ T ()", Date.class) .build ();

JavaPoet će generirati sljedeći izlaz:

Datum getCurrentDate () {povratak novog datuma (); }

10.4. Oblikovanje imena

U slučaju da trebamo odnose se na naziv varijable / parametra, polja ili metode, koju možemo koristiti $ N u JavaPoet-u Niz oblikovač.

Možemo dodati prethodni getCurrentDateMethod () na novu metodu referenciranja:

MethodSpec dateToString = MethodSpec .methodBuilder ("getCurrentDateAsString"). Vraća (String.class) .addStatement ("$ T formatter = new $ T ($ S)", DateFormat.class, SimpleDateFormat.class, "MM / dd / gggg HH : mm: ss ") .addStatement (" return formatter.format ($ N ()) ", getCurrentDateMethod) .build ();

Što generira:

String getCurrentDateAsString () {DateFormat formatter = novi SimpleDateFormat ("MM / dd / gggg HH: mm: ss"); vratiti formatter.format (getCurrentDate ()); }

11. Generiranje Lambda izraza

Možemo se koristiti značajkama koje smo već istražili za generiranje Lambda izraza. Na primjer, blok koda koji ispisuje Ime polje ili varijabla više puta:

CodeBlock printNameMultipleTimes = CodeBlock .builder () .addStatement ("$ T names = new $ T ()", List.class, String.class, ArrayList.class) .addStatement ("$ T.range ($ L, $ L) .forEach (i -> names.add (name)) ", IntStream.class, 0, 10) .addStatement (" names.forEach (System.out :: println) ") .build ();

Ta logika generira sljedeći izlaz:

Imena popisa = new ArrayList (); IntStream.range (0, 10) .forEach (i -> names.add (ime)); names.forEach (System.out :: println);

12. Izrada rezultata pomoću JavaFile

The JavaFile class pomaže u konfiguriranju i stvaranju rezultata generiranog koda. Da bismo generirali Java kôd, jednostavno gradimo JavaFile, navedite naziv paketa i primjerak TypeSpec objekt.

12.1. Uvlačenje koda

Prema zadanim postavkama JavaPoet koristi dva razmaka za uvlačenje. Da bi se održala dosljednost, svi primjeri u ovom vodiču predstavljeni su s uvlačenjem od 4 razmaka, koje se konfigurira putem uvlaka () metoda:

JavaFile javaFile = JavaFile .builder ("com.baeldung.javapoet.person", osoba) .indent ("") .build ();

12.2. Statički uvoz

U slučaju da trebamo dodati statički uvoz, možemo definirati vrstu i specifično ime metode u JavaFile pozivom na addStaticImport () metoda:

JavaFile javaFile = JavaFile .builder ("com.baeldung.javapoet.person", osoba) .indent ("") .addStaticImport (Date.class, "UTC") .addStaticImport (ClassName.get ("java.time", " ZonedDateTime ")," * ") .build ();

Koji generira sljedeće statičke izjave o uvozu:

uvoz statičkog java.util.Date.UTC; uvezi statički java.time.ZonedDateTime. *;

12.3. Izlaz

The writeTo () metoda pruža funkcionalnost za pisanje koda u više ciljeva, kao što je standardni izlazni tok (System.out) i Datoteka.

Da bismo napisali Java kôd u standardni izlazni tok, jednostavno zovemo writeTo () metodu i pružite System.out kao argument:

JavaFile javaFile = JavaFile .builder ("com.baeldung.javapoet.person", osoba) .indent ("") .addStaticImport (Date.class, "UTC") .addStaticImport (ClassName.get ("java.time", " ZonedDateTime ")," * ") .build (); javaFile.writeTo (System.out);

The writeTo () metoda također prihvaća java.nio.file.Path i java.io.Datoteka. Možemo pružiti odgovarajuće Staza ili Datoteka objekt kako bi generirao datoteku Java izvornog koda u odredišnu mapu / put:

Put puta = Paths.get (destinationPath); javaFile.writeTo (put);

Za detaljnije informacije o JavaFile, molimo pogledajte Javadoc.

13. Zaključak

Ovaj je članak uvod u funkcionalnosti JavaPoet-a, poput generiranja metoda, polja, parametara, vrsta, napomena i Javadocs-a.

JavaPoet je dizajniran samo za generiranje koda. U slučaju da želimo raditi metaprogramiranje s Javom, JavaPoet od verzije 1.10.0 ne podržava kompajliranje i izvođenje koda.

Kao i uvijek, primjeri i isječci koda dostupni su na GitHubu.


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