Úvod do JavaPoet

1. Prehľad

V tomto tutoriáli preskúmame základné funkcie knižnice JavaPoet.

JavaPoet je vyvinutý spoločnosťou Square, ktorá poskytuje API na generovanie zdrojového kódu Java. Môže generovať primitívne typy, referenčné typy a ich varianty (napríklad triedy, rozhrania, vymenované typy, anonymné vnútorné triedy), polia, metódy, parametre, anotácie a Javadocs.

JavaPoet riadi import závislých tried automaticky. Používa tiež vzor Builder na určenie logiky na generovanie kódu Java.

2. Závislosť od Maven

Aby sme mohli používať JavaPoet, môžeme si priamo stiahnuť najnovší súbor JAR alebo definovať nasledujúcu závislosť v našom pom.xml:

 com.squareup javapoet 1.10.0 

3. Špecifikácia metódy

Najskôr si prejdime špecifikáciu metódy. Na vygenerovanie metódy jednoducho zavoláme methodBuilder () metóda MethodSpec trieda. Vygenerovaný názov metódy určíme ako a String argument methodBuilder () metóda.

Môžeme vygeneruje akýkoľvek jednotlivý logický príkaz končiaci bodkočiarkou pomocou addStatement () metóda. Medzitým môžeme definovať jeden riadiaci tok ohraničený zloženými zátvorkami, ako napr keby-inak blokovať, príp pre slučka, v riadiacom toku.

Tu je rýchly príklad - generovanie súboru sumOfTen () metóda, ktorá vypočíta súčet čísel 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 ();

Toto vyprodukuje nasledujúci výstup:

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

4. Blok kódu

Môžeme tiež zabaliť jeden alebo viac riadiacich tokov a logických príkazov do jedného bloku kódu:

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

Čo generuje:

int suma = 0; pre (int i = 0; i <= 10; i ++) {sum + = i; }

Môžeme zjednodušiť predchádzajúcu logiku v MethodSpec volaním addCode () a poskytnutie sumOfTenImpl objekt:

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

Blok kódu je použiteľný aj pre ďalšie špecifikácie, ako sú typy a Javadocs.

5. Špecifikácia poľa

Ďalej - preskúmajme logiku špecifikácie poľa.

Na vygenerovanie poľa používame staviteľ () metóda FieldSpec trieda:

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

Toto vygeneruje nasledujúce pole:

súkromné ​​meno reťazca;

Predvolenú hodnotu poľa môžeme tiež inicializovať volaním znaku inicializátor () metóda:

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

Čo generuje:

private static final String DEFAULT_NAME = "Alice";

6. Špecifikácia parametra

Poďme teraz preskúmať logiku špecifikácie parametrov.

V prípade, že chceme do metódy pridať parameter, môžeme zavolať znak addParameter () v reťazci volaní funkcií v nástroji Builder.

V prípade zložitejších typov parametrov môžeme využiť ParameterSpec staviteľ:

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

Môžeme pridať aj modifikátor metódy, ako napr verejné a / alebo statický:

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

Takto vyzerá generovaný kód Java:

public static void sumOfTen (int cislo, list strings) {int sum = 0; pre (int i = 0; i <= 10; i ++) {sum + = i; }}

7. Špecifikácia typu

Po preskúmaní spôsobov generovania metód, polí a parametrov sa teraz pozrime na špecifikácie typov.

Na deklaráciu typu môžeme použiť TypeSpec ktoré môžu vytvárať triedy, rozhrania a vymenované typy.

7.1. Vytvára sa trieda

Na vygenerovanie triedy môžeme použiť znak classBuilder () metóda TypeSpec trieda.

Môžeme tiež určiť jeho modifikátory, napríklad verejné a konečné modifikátory prístupu. Okrem modifikátorov tried môžeme pomocou už spomenutých určiť aj polia a metódy FieldSpec a MethodSpec triedy.

Poznač si to addField () a addMethod () metódy sú k dispozícii aj pri generovaní rozhraní alebo anonymných vnútorných tried.

Pozrime sa na nasledujúci príklad nástroja na tvorbu triedy:

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

Takto vyzerá generovaný kód:

public class Osoba {private String name; public String getName () {return this.name; } public String setName (názov reťazca) {this.name = name; } public static void sumOfTen (int cislo, list strings) {int sum = 0; pre (int i = 0; i <= 10; i ++) {sum + = i; }}}

7.2. Generuje sa rozhranie

Na generovanie rozhrania Java používame interfaceBuilder () metóda TypeSpec.

Môžeme tiež definovať predvolenú metódu zadaním VÝCHODNÉ hodnota modifikátora v addModifiers ():

TypeSpec person = TypeSpec .interfaceBuilder ("Osoba") .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 ();

Vygeneruje nasledujúci kód Java:

verejné rozhranie Osoba {private static final String DEFAULT_NAME = "Alice"; void getName (); default void getDefaultName () {return DEFAULT_NAME; }}

7.3. Generuje sa výčet

Na vygenerovanie vymenovaného typu môžeme použiť enumBuilder () metóda TypeSpec. Ak chcete určiť každú vymenovanú hodnotu, môžeme zavolať addEnumConstant () metóda:

TypeSpec gender = TypeSpec .enumBuilder ("Pohlavie") .addModifikátory (Modifier.PUBLIC) .addEnumConstant ("MALE") .addEnumConstant ("FEMALE") .addEnumConstant ("UNSPECIFIED") .build ();

Výstup z vyššie uvedeného enumBuilder () logika je:

verejné enum Pohlavie {MALE, DÁMSKE, NEODVEDENÉ}

7.4. Generuje sa anonymná vnútorná trieda

Na vygenerovanie anonymnej vnútornej triedy môžeme použiť znak anonymousClassBuilder () metóda TypeSpec trieda. Poznač si to musíme určiť rodičovskú triedu v addSuperinterface () metóda. V opačnom prípade použije predvolenú nadradenú triedu, ktorá je Objekt:

TypeSpec comparator = TypeSpec .anonymousClassBuilder ("") .addSuperinterface (ParameterizedTypeName.get (Comparator.class, String.class)) .addMethod (MethodSpec .methodBuilder ("porovnávať"). AddModifiers (Modifier.PUBLIC) .addPareter. , "a") .addParameter (String.class, "b") .returns (int.class) .addStatement ("return a.length () - b.length ()") .build ()) .build () ;

Takto sa vygeneruje nasledujúci kód Java:

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

8. Špecifikácia anotácie

Ak chcete do generovaného kódu pridať anotáciu, môžeme zavolať addAnnotation () metóda v a MethodSpec alebo FieldSpec trieda staviteľa:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addAnnotation (Override.class) .addParameter (int.class, "number") .addParameter (strings) .addModifiers (Modifier.PUBLIC, Modifier.STATIC) .addCodeI) .build ();

Čo generuje:

@Override public static void sumOfTen (int číslo, zoznam reťazcov) {int sum = 0; pre (int i = 0; i <= 10; i ++) {sum + = i; }}

V prípade, že potrebujeme určiť hodnotu člena, môžeme zavolať addMember () metóda AnnotationSpec trieda:

AnnotationSpec toString = AnnotationSpec .builder (ToString.class) .addMember ("vylúčiť", "\" meno \ "") .build ();

Toto vygeneruje nasledujúcu anotáciu:

@ToString (vylúčiť = "meno")

9. Generovanie Javadocs

Javadoc je možné generovať pomocou CodeBlock, alebo priamym zadaním hodnoty:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addJavadoc (CodeBlock .builder () .add ("súčet všetkých celých čísel od 0 do 10") .build ()) .addAnnotation (Override.class) .addParameter (int. trieda, "číslo") .addParameter (reťazce) .addModifiers (Modifier.PUBLIC, Modifier.STATIC) .addCode (sumOfTenImpl) .build ();

Takto sa vygeneruje nasledujúci kód Java:

/ ** * Súčet všetkých celých čísel od 0 do 10 * / @Override public static void sumOfTen (int číslo, zoznam reťazcov) {int sum = 0; pre (int i = 0; i <= 10; i ++) {sum + = i; }}

10. Formátovanie

Zopakujme si príklad FieldSpec inicializátor v časti 5, ktorý obsahuje únikový znak použitý na únik z „Alice“ String hodnota:

inicializátor ("\" Alice \ "")

Podobný príklad existuje aj v časti 8, keď definujeme vylúčený člen anotácie:

addMember ("vylúčiť", "\" meno \ "")

Keď náš kód JavaPoet rastie a má veľa podobných, stáva sa to nepraktickým String uniknúť resp String zreťazovacie vyhlásenia.

Funkcia formátovania reťazcov v JavaPoet umožňuje String formátovanie v beginControlFlow (), addStatement () alebo inicializátor () metódy jednoduchšie. Syntax je podobná ako v String.format () funkčnosť v Jave. Môže pomôcť pri formátovaní literálov, reťazcov, typov a mien.

10.1. Doslovné formátovanie

JavaPoet nahrádza $ L s doslovnou hodnotou na výstupe. Môžeme určiť akýkoľvek primitívny typ a String hodnoty v argumentoch:

private MethodSpec generateSumMethod (názov reťazca, int od, int do, operátor reťazca) {return MethodSpec .methodBuilder (name) .returns (int.class) .addStatement ("int sum = 0") .beginControlFlow ("for (int i = $ L; i <= $ L; i ++) ", od, do) .addStatement (" sum = suma $ L i ", operátor) .endControlFlow () .addStatement (" návratná suma ") .build (); }

V prípade, že zavoláme generateSumMethod () s týmito zadanými hodnotami:

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

JavaPoet vygeneruje nasledujúci výstup:

int sumOfOneHundred () {int sum = 0; pre (int i = 0; i <= 100; i ++) {sum = suma + i; } vratna suma; }

10.2. String Formátovanie

String formátovanie vygeneruje hodnotu s úvodzovkou, ktorá odkazuje výlučne na String zadajte v jazyku Java. JavaPoet nahrádza $ S s String hodnota na výstupe:

private static MethodSpec generateStringSupplier (String methodName, String fieldName) {return MethodSpec .methodBuilder (methodName) .returns (String.class) .addStatement ("return $ S", fieldName) .build (); }

V prípade, že zavoláme generateGetter () metódou a uveďte tieto hodnoty:

generateStringSupplier ("getDefaultName", "Bob");

Dostaneme nasledujúci vygenerovaný kód Java:

Reťazec getDefaultName () {návrat "Bob"; }

10.3. Typ Formátovanie

JavaPoet nahrádza $ T s typom vygenerovaného kódu Java. JavaPoet narába s typom vo výkaze na import automaticky. Keby sme namiesto toho poskytli typ ako doslovný, súbor JavaPoet by import nespracoval.

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

JavaPoet vygeneruje nasledujúci výstup:

Date getCurrentDate () {return new Date (); }

10.4. Formátovanie mien

Pre prípad potreby odkazuje na názov premennej / parametra, poľa alebo metódy, ktorú môžeme použiť $ N v prostredí JavaPoet String formátovač.

Môžeme pridať predchádzajúci getCurrentDateMethod () k novej metóde odkazovania:

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

Čo generuje:

Reťazec getCurrentDateAsString () {DateFormat formatter = nový SimpleDateFormat ("MM / dd / rrrr HH: mm: ss"); return formatter.format (getCurrentDate ()); }

11. Generovanie lambda výrazov

Na generovanie výrazu Lambda môžeme využiť funkcie, ktoré sme už preskúmali. Napríklad blok kódu, ktorý vytlačí názov pole alebo premenná viackrát:

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 ();

Táto logika generuje nasledujúci výstup:

Názvy zoznamu = new ArrayList (); IntStream.range (0, 10) .forEach (i -> names.add (name)); names.forEach (System.out :: println);

12. Produkcia výstupu pomocou JavaFile

The JavaFile trieda pomáha konfigurovať a produkovať výstup generovaného kódu. Na vygenerovanie kódu Java jednoducho zostavíme JavaFile, uveďte názov balíka a inštanciu TypeSpec objekt.

12.1. Odsadenie kódu

V predvolenom nastavení používa JavaPoet na odsadenie dve medzery. Z dôvodu zachovania konzistencie boli všetky príklady v tomto výučbe prezentované so 4 odsadeniami medzier, ktoré sú konfigurované pomocou zarážka () metóda:

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

12.2. Statický dovoz

V prípade, že potrebujeme pridať statický import, môžeme definovať typ a konkrétny názov metódy v JavaFile zavolaním na addStaticImport () metóda:

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

Čo generuje nasledujúce statické príkazy na import:

import statickej java.util.Date.UTC; importovať statický java.time.ZonedDateTime. *;

12.3. Výkon

The Písať() metóda poskytuje funkcie na zápis kódu do viacerých cieľov, napríklad do štandardného výstupného toku (System.out) a Súbor.

Na napísanie kódu Java do štandardného výstupného toku jednoducho zavoláme Písať() metódou a poskytnúť System.out ako argument:

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

The Písať() metóda tiež akceptuje java.nio.file.cesta a java.io.Súbor. Môžeme poskytnúť zodpovedajúce Cesta alebo Súbor objekt za účelom vygenerovania súboru zdrojového kódu Java do cieľového priečinka / cesty:

Path path = Paths.get (destinationPath); javaFile.writeTo (cesta);

Podrobnejšie informácie týkajúce sa JavaFile, pozrite si Javadoc.

13. Záver

Tento článok predstavuje úvod do funkcií JavaPoet, ako je generovanie metód, polí, parametrov, typov, anotácií a Javadocs.

JavaPoet je určený iba na generovanie kódu. V prípade, že by sme chceli robiť metaprogramovanie pomocou Javy, JavaPoet od verzie 1.10.0 nepodporuje kompiláciu a spustenie kódu.

Príklady a útržky kódu sú ako vždy k dispozícii na GitHub.


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