Bevezetés a JavaPoet-be

1. Áttekintés

Ebben az oktatóanyagban megvizsgáljuk a JavaPoet könyvtár alapvető funkcióit.

JavaPoet a Square fejlesztette ki, amely API-kat biztosít a Java forráskód előállításához. Létrehozhat primitív típusokat, referenciatípusokat és azok változatait (például osztályok, interfészek, felsorolt ​​típusok, névtelen belső osztályok), mezőket, módszereket, paramétereket, annotációkat és Javadocs-okat.

A JavaPoet automatikusan kezeli a függő osztályok importálását. A Builder mintát használja a Java kód előállításának logikájának megadására is.

2. Maven-függőség

A JavaPoet használatához közvetlenül letölthetjük a legújabb JAR fájlt, vagy meghatározhatjuk a következő függőséget a fájlunkban pom.xml:

 com.squareup javapoet 1.10.0 

3. A módszer specifikációja

Először nézzük át a módszer specifikációját. Egy módszer előállításához egyszerűen hívjuk a methodBuilder () a metódusa MethodSpec osztály. A létrehozott módszer nevét a-ként adjuk meg Húr érvelése methodBuilder () módszer.

Tudunk generáljon egyetlen, a pontosvesszővel végződő logikai utasítást használni a addStatement () módszer. Eközben meghatározhatunk egy göndör zárójelekkel határolt vezérlő áramlást, mint pl ha más blokkolja, vagy mert hurok, vezérlő áramlásban.

Itt egy gyors példa - a sumOfTen () módszer, amely kiszámítja a 0 és 10 közötti számok összegét:

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

Ez a következő kimenetet eredményezi:

void sumOfTen () {int összeg = 0; mert (int i = 0; i <= 10; i ++) {összeg + = i; }}

4. Kódblokk

Azt is megtehetjük csomagoljon egy vagy több vezérlési folyamatot és logikai utasítást egy kódblokkba:

CodeBlock sumOfTenImpl = CodeBlock .builder () .addStatement ("int összeg = 0") .beginControlFlow ("for (int i = 0; i <= 10; i ++)") .addStatement ("összeg + = i") .endControlFlow () .épít();

Ami generálja:

int összeg = 0; mert (int i = 0; i <= 10; i ++) {összeg + = i; }

Leegyszerűsíthetjük a korábbi logikát a MethodSpec hívással addCode () és a sumOfTenImpl tárgy:

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

A kódblokk alkalmazható más specifikációkra is, például típusokra és Javadocs-okra.

5. A mező specifikációja

Következő - vizsgáljuk meg a mező specifikációs logikáját.

Egy mező előállításához a építész() módszere FieldSpec osztály:

FieldSpec név = FieldSpec .builder (String.osztály, "név") .addModifiers (Módosító.PRIVÁT) .build ();

Ez a következő mezőt hozza létre:

privát karakterlánc neve;

A mezõ alapértelmezett értékét inicializálhatjuk a inicializáló () módszer:

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

Ami generálja:

privát statikus végleges karakterlánc DEFAULT_NAME = "Alice";

6. Paraméter specifikáció

Most vizsgáljuk meg a paraméterek specifikációjának logikáját.

Abban az esetben, ha hozzá akarunk adni egy paramétert a metódushoz, meghívhatjuk a addParameter () a függvény láncolatán belül meghívja az építőt.

Bonyolultabb paramétertípusok esetén felhasználhatjuk ParameterSpec építész:

ParameterSpec karakterláncok = ParameterSpec .builder (ParameterizedTypeName.get (OsztályNév.get (Lista.osztály), TípusNév.get (Karakterlánc.osztály)), "húrok") .build ();

Hozzáadhatjuk a módszer módosítóját is, mint pl nyilvános és / vagy statikus:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addParameter (int.osztály, "szám") .addParameter (karakterláncok) .addModifiers (Módosító.PUBLIC, Módosító.STATIC) .addCode (sumOfTenImpl) .build (építés)

Így néz ki a létrehozott Java-kód:

public static void sumOfTen (int szám, Lista húrok) {int összeg = 0; mert (int i = 0; i <= 10; i ++) {összeg + = i; }}

7. Típus specifikáció

Miután megvizsgálta a módszerek, mezők és paraméterek előállításának módjait, most nézzük meg a típusspecifikációkat.

Típus deklarálásához használhatjuk a TypeSpec amely osztályokat, interfészeket és felsorolt ​​típusokat képes felépíteni.

7.1. Osztály létrehozása

Osztály előállításához használhatjuk a classBuilder () módszere TypeSpec osztály.

Megadhatjuk módosítóit is, például nyilvános és végső hozzáférés módosítók. Az osztálymódosítók mellett a már említett mezőket és módszereket is megadhatjuk FieldSpec és MethodSpec osztályok.

Vegye figyelembe, hogy addField () és addMethod () metódusok is rendelkezésre állnak interfészek vagy névtelen belső osztályok létrehozásakor.

Vessünk egy pillantást a következő osztályépítő példára:

TypeSpec person = TypeSpec .classBuilder ("Person") .addModifiers (Modifier.PUBLIC) .addField (name) .addMethod (MethodSpec .methodBuilder ("getName") .addModifiers (Modifier.PUBLIC) .returns (String.class). ("return this.name") .build ()) .addMethod (MethodSpec .methodBuilder ("setName") .addParameter (String.osztály, "név") .addModifiers (Módosító.PUBLIC) .returns (String.osztály). addStatement ("ez.név = név") .build ()) .addMethod (sumOfTen) .build ();

És így néz ki a létrehozott kód:

public class Személy {private String név; public String getName () {adja vissza ezt a nevet; } public String setName (karakterlánc neve) {this.name = név; } public static void sumOfTen (int szám, Lista húrok) {int összeg = 0; mert (int i = 0; i <= 10; i ++) {összeg + = i; }}}

7.2. Interfész létrehozása

Java felület előállításához a interfaceBuilder () módszere TypeSpec.

Definiálhatunk egy alapértelmezett módszert is ALAPÉRTÉK módosító értéke a 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 ();

A következő Java kódot generálja:

nyilvános felület Személy {private static final String DEFAULT_NAME = "Alice"; void getName (); alapértelmezett void getDefaultName () {return DEFAULT_NAME; }}

7.3. Enum generálása

Egy felsorolt ​​típus előállításához használhatjuk a enumBuilder () módszere TypeSpec. Az egyes felsorolt ​​értékek megadásához meghívhatjuk a addEnumConstant () módszer:

TypeSpec gender = TypeSpec .enumBuilder ("Nem") .addModifiers (Módosító.PUBLIC) .addEnumConstant ("MALE") .addEnumConstant ("FEMALE") .addEnumConstant ("NEM MEGHATÁROZOTT") .build ();

A fentiek kimenete enumBuilder () logika:

public enum Nem {FÉRFI, NŐ, NEM MEGHATÁROZOTT}

7.4. Névtelen belső osztály létrehozása

Anonim belső osztály létrehozásához használhatjuk a anonymousClassBuilder () módszere TypeSpec osztály. Vegye figyelembe, hogy meg kell adnunk a szülő osztályt a addSuperinterface () módszer. Ellenkező esetben az alapértelmezett szülő osztályt fogja használni, ami Tárgy:

TypeSpec Comparator = TypeSpec .anonymousClassBuilder ("") .addSuperinterface (ParameterizedTypeName.get (Comparator.class, String.class)) .addMethod (MethodSpec .methodBuilder ("összehasonlítás") .addModifiers (Módosító.PUBLIC) (AddPPclam). , "a") .addParameter (Karakterlánc.osztály, "b") .visszatérés (osztályrész) .addStatement ("visszatérés a.hossz () - b.hossz ()") .build ()) .build () ;

Ez a következő Java kódot generálja:

új Összehasonlító () {public int összehasonlítás (a, String b) {return a.hossz () - b.hossz (); }});

8. Annotation Specification

Annotáció hozzáadásához a létrehozott kódhoz felhívhatjuk a addAnnotation () módszer a MethodSpec vagy FieldSpec építő osztály:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addAnnotation (Override.class) .addParameter (int.osztály, "szám") .addParameter (húrok) .addModifiers (Módosító.PUBLIC, Módosító.STATI). .épít();

Ami generálja:

@Orride public static void sumOfTen (int number, List strings) {int sum = 0; mert (int i = 0; i <= 10; i ++) {összeg + = i; }}

Abban az esetben, ha meg kell adnunk a tag értékét, felhívhatjuk a addMember () módszere AnnotationSpec osztály:

AnnotationSpec toString = AnnotationSpec .builder (ToString.class) .addMember ("kizárás", "\" név \ "") .build ();

Ez a következő jegyzetet generálja:

@ToString (kizárás = "név")

9. Javadocsok generálása

Javadoc lehet generálni CodeBlock, vagy az érték közvetlen megadásával:

MethodSpec sumOfTen = MethodSpec .methodBuilder ("sumOfTen") .addJavadoc (CodeBlock .builder () .add ("Az összes szám 0 és 10 közötti összege") .build ()) .addAnnotation (Felülírás.osztály) .addParameter (int. osztály, "szám") .addParameter (karakterláncok) .addModifiers (Módosító.PUBLIC, Módosító.STATIC) .addCode (sumOfTenImpl) .build ();

Ez a következő Java kódot generálja:

/ ** * Az összes egész szám 0-tól 10-ig * / @ Nyilvános statikus érvénytelenítés void sumOfTen (int szám, Lista karakterláncok) {int összeg = 0; mert (int i = 0; i <= 10; i ++) {összeg + = i; }}

10. Formázás

Ellenőrizzük újra a FieldSpec inicializáló az 5. szakaszban, amely az „Alice” elől menekülésre használt menekülési szenet tartalmaz Húr érték:

inicializáló ("\" Alice \ "")

Van egy hasonló példa a 8. szakaszban is, amikor meghatározzuk az annotáció kizárt tagját:

addMember ("kizárás", "\" név \ "")

Akkor válik nehézkessé, amikor a JavaPoet kódunk növekszik, és sok hasonlóval rendelkezik Húr menekülni vagy Húr összefűző nyilatkozatok.

A JavaPoet karakterlánc-formázási szolgáltatása Húr formázás beginControlFlow (), addStatement () vagy inicializáló () módszerek könnyebbek. A szintaxis hasonló String.format () funkcionalitás a Java-ban. Segíthet a literálok, karakterláncok, típusok és nevek formázásában.

10.1. Szó szerinti formázás

A JavaPoet helyettesíti $ L szó szerinti értékkel a kimenetben. Megadhatunk bármilyen primitív típust és Húr értékek az argumentum (ok) ban:

privát MethodSpec geneSumMethod (Karakterlánc neve, int tól, int-ig, String operátor) {return MethodSpec .methodBuilder (név) .returns (int.osztály) .addStatement ("int összeg = 0") .beginControlFlow ("for (int i = $ L; i <= $ L; i ++) ", tól, ig) .addStatement (" összeg = összeg $ L i ", operátor) .endControlFlow () .addStatement (" visszatérő összeg ") .build (); }

Ha felhívjuk a generálniSumMethod () a következő értékekkel:

generálniSumMethod ("sumOfOneHundred", 0, 100, "+");

A JavaPoet a következő kimenetet generálja:

int sumOfOneHundred () {int összeg = 0; for (int i = 0; i <= 100; i ++) {összeg = összeg + i; } visszatérési összeg; }

10.2. Húr Formázás

Húr a formázás idézőjeles értéket generál, amely kizárólag erre utal Húr írja be a Java-t. A JavaPoet helyettesíti $ S val,-vel Húr érték a kimenetben:

privát statikus MethodSpec generálStringSupplier (String metódusnév, String mezőnév) {return MethodSpec .methodBuilder (metódusnév) .returns (String.osztály) .addStatement ("return $ S", mezőnév) .build (); }

Ha felhívjuk a generálniGetter () módszer, és adja meg ezeket az értékeket:

generatorStringSupplier ("getDefaultName", "Bob");

A következő generált Java kódot kapjuk:

String getDefaultName () {return "Bob"; }

10.3. Írja be a Formázás parancsot

A JavaPoet helyettesíti $ T típussal a létrehozott Java kódban. A JavaPoet automatikusan kezeli az importálási utasítás típusát. Ha a típust literálként írtuk volna elő, akkor a JavaPoet nem kezelte az importálást.

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

A JavaPoet a következő kimenetet generálja:

Dátum getCurrentDate () {return new Date (); }

10.4. Név formázása

Ha arra szükségünk lenne hivatkozhatunk egy változó / paraméter, mező vagy módszer nevére, használhatjuk $ N a JavaPoet-ben Húr formázó.

Hozzáadhatjuk az előzőt getCurrentDateMethod () az új hivatkozási módszerhez:

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

Ami generálja:

String getCurrentDateAsString () {DateFormat formatter = new SimpleDateFormat ("HH / nn / éééé ÓÓ: h: ss"); return formatter.format (getCurrentDate ()); }

11. Lambda kifejezések generálása

Használhatjuk azokat a funkciókat, amelyeket már felfedeztünk a Lambda kifejezés előállításához. Például egy kódblokk, amely kinyomtatja a név mező vagy változó többször:

CodeBlock printNameMultipleTimes = CodeBlock .builder () .addStatement ("$ T nevek = új $ T ()", List.class, String.class, ArrayList.class) .addStatement ("$ T.tartomány ($ L, $ L) .forEach (i -> names.add (név)) ", IntStream.class, 0, 10) .addStatement (" names.forEach (System.out :: println) ") .build ();

Ez a logika a következő kimenetet generálja:

Listanevek = new ArrayList (); IntStream.range (0, 10) .forEach (i -> nevek.add (név)); names.forEach (System.out :: println);

12. Kimenet előállítása JavaFile

A JavaFile osztály segít a generált kód kimenetének konfigurálásában és előállításában. Java kód előállításához egyszerűen felépítjük a JavaFile, adja meg a csomag nevét és a TypeSpec tárgy.

12.1. Kód behúzás

Alapértelmezés szerint a JavaPoet két szóközt használ a behúzáshoz. A konzisztencia megőrzése érdekében az oktatóanyag összes példáját 4 szóközzel ellátott behúzással mutattuk be, amelyet a következő segítségével konfigurálunk: francia bekezdés () módszer:

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

12.2. Statikus behozatal

Abban az esetben, ha statikus importot kell hozzáadnunk, meghatározhatjuk a típust és a specifikus módszer nevét a JavaFile felhívásával a addStaticImport () módszer:

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

Ami a következő statikus import kimutatásokat generálja:

statikus import: java.util.Date.UTC; statikus java.time.ZonedDateTime. * importálása;

12.3. Kimenet

A írj neki() A módszer funkciót kínál arra, hogy a kódot több célba írja be, például a standard kimeneti adatfolyamba (System.out) és File.

Java kód beírásához egy normál kimeneti adatfolyamba egyszerűen hívjuk a írj neki() módszert, és adja meg a System.out érvként:

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

A írj neki() módszer is elfogadja java.nio.file.Path és java.io.Fájl. Meg tudjuk adni a megfelelőt Pálya vagy File objektumot a Java forráskód fájl létrehozásához a célmappába / elérési útba:

Elérési útvonal = Paths.get (destinationPath); javaFile.writeTo (elérési út);

További információkért a JavaFile, kérjük, olvassa el a Javadoc-ot.

13. Következtetés

Ez a cikk bevezette a JavaPoet funkcióit, például metódusok, mezők, paraméterek, típusok, kommentárok és Javadocsok létrehozása.

A JavaPoet csak kódgenerálásra készült. Ha Java-val szeretnénk metaprogramozni, akkor a JavaPoet az 1.10.0 verziótól kezdve nem támogatja a kód fordítását és futtatását.

Mint mindig, a példák és a kódrészletek is elérhetők a GitHubon.


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