Metaprogramozás Groovy-ban
1. Áttekintés
A Groovy egy dinamikus és erőteljes JVM nyelv, amely számos funkcióval rendelkezik, például bezárásokkal és tulajdonságokkal.
Ebben az oktatóanyagban a Metaprogramozás fogalmát tárjuk fel Groovy-ban.
2. Mi a metaprogramozás?
A metaprogramozás egy programozási technika, amellyel programot írhatnak saját vagy egy másik program metaadatokkal történő módosítására.
A Groovy-ban metaprogramozást futás közben és fordítási időben egyaránt lehet végrehajtani. A továbbiakban mindkét technika néhány figyelemre méltó tulajdonságát megvizsgáljuk.
3. Futásidejű metaprogramozás
A futásidejű metaprogramozás lehetővé teszi számunkra az osztály meglévő tulajdonságainak és módszereinek megváltoztatását. Ezenkívül új tulajdonságokat és módszereket is csatolhatunk; mind futás közben.
A Groovy néhány módszert és tulajdonságot nyújt, amelyek segítenek megváltoztatni az osztály viselkedését futás közben.
3.1. propertyMissing
Amikor megpróbálunk elérni egy Groovy osztály egy nem definiált tulajdonságát, akkor a MissingPropertyException. A kivétel elkerülése érdekében Groovy biztosítja a propertyMissing módszer.
Először írjunk egy Munkavállaló osztály néhány tulajdonsággal:
osztály Alkalmazott {String keresztnév String vezetékNév int age}
Másodszor létrehozunk egy Munkavállaló objektumot, és próbáljon meg egy meghatározatlan tulajdonságot megjeleníteni cím. Következésképpen meg fogja dobni a MissingPropertyException: Groovy biztosítja a propertyMissing módszer a hiányzó ingatlankérés befogására. Ezért elkerülhetjük a MissingPropertyException futás közben. A hiányzó tulajdonság getter metódushívásának megfogásához egyetlen argumentummal definiáljuk a tulajdonság nevét: Ugyanennek a metódusnak lehet a második argumentuma is, mint a tulajdonság értéke, hogy elkapja a hiányzó tulajdonság setter metódushívását: A methodMissing módszer hasonló propertyMissing. Azonban, methodMissing lehallgat minden hiányzó módszer hívását, elkerülve ezzel a MissingMethodException. Próbáljuk meg felhívni a getFullName módszer egy Munkavállaló tárgy. Mint getFullName hiányzik, a végrehajtás eldobja a MissingMethodException futás közben: Tehát ahelyett, hogy egy metódust hívna be a próbáld elkapni, meghatározhatjuk methodMissing: Groovy biztosítja a metaClass ingatlan minden osztályában. A metaClass tulajdonság a ExpandoMetaClass. A ExpandoMetaClass osztály számos módot kínál a meglévő osztály futás közbeni átalakítására. Hozzáadhatunk például tulajdonságokat, módszereket vagy konstruktorokat. Először tegyük hozzá a hiányzókat cím tulajdon a Munkavállaló osztály felhasználásával metaClass ingatlan: Tovább haladva tegyük hozzá a hiányzókat getFullName módszer a Munkavállaló osztály objektum futás közben: Hasonlóképpen hozzáadhatunk egy konstruktort a Munkavállaló osztály futás közben: Hasonlóképpen hozzátehetjük statikus módszerek felhasználásával metaClass.static. A metaClass tulajdonság nem csak a felhasználó által definiált osztályok módosítására szolgál, hanem a meglévő Java osztályokra is futás közben. Például tegyünk hozzá egy a-t nagybetűs módszer a Húr osztály: A kiterjesztés futás közben hozzáadhat egy módszert egy osztályhoz, és globálisan elérhetővé teheti azt. A kiterjesztésben definiált módszereknek mindig statikusaknak kell lenniük, a maga osztály objektum első argumentumként. Írjunk például egy BasicExtension osztály hozzáadni a getYearOfBirth módszer a Munkavállaló osztály: A BasicExtensions, hozzá kell adnunk a konfigurációs fájlt a META-INF / szolgáltatások projektünk könyvtárát. Tehát tegyük hozzá a org.codehaus.groovy.runtime.ExtensionModule fájl a következő konfigurációval: Ellenőrizzük a getYearOfBirth módszer a Munkavállaló osztály: Hasonlóképpen hozzá statikus módszereket, meg kell határoznunk egy külön kiterjesztési osztályt. Például tegyünk hozzá egy a-t statikus módszer getDefaultObj a miénknek Munkavállaló osztály meghatározásával StaticEmployeeExtension osztály: Ezután engedélyezzük a StaticEmployeeExtension a következő konfiguráció hozzáadásával a ExtensionModule fájl: Most csak arra van szükségünk, hogy teszteljük statikusgetDefaultObj módszer a Munkavállaló osztály: Hasonlóképpen, kiterjesztésekkel hozzáadhatunk egy módszert az előre lefordított Java osztályokhoz mint Egész szám és Hosszú: Konkrét annotációk segítségével könnyedén megváltoztathatjuk az osztály struktúráját fordítás idején. Más szavakkal, annotációkkal módosíthatjuk az osztály absztrakt szintaxisfáját az összeállításnál. Beszéljünk néhány olyan kommentárról, amelyek nagyon hasznosak a Groovy-ban a kazánlap kódjának csökkentése érdekében. Közülük sok elérhető a groovy.transzformáció csomag. Ha alaposan elemezzük, rájövünk, hogy néhány kommentár a Java Project Lombokhoz hasonló funkciókat kínál. A @ToString kommentár hozzáadja a Sztring módszer egy osztályhoz fordítási időben. Csak arra van szükségünk, hogy hozzáadjuk az annotációt az osztályhoz. Például tegyük hozzá a @ToString annotáció a mi Munkavállaló osztály: Most létrehozunk egy objektumot a Munkavállaló osztály és ellenőrizze a Sztring módszer: Deklarálhatunk olyan paramétereket is, mint kizárja, magába foglalja, includePackage és ignoreNulls val vel @ToString hogy módosítsa a kimeneti karakterláncot. Például zárjuk ki id és csomag az Employee objektum karakterláncából: Használat @TupleConstructor a Groovy-ban egy paraméterezett konstruktor hozzáadásához az osztályba. Ez a feljegyzés létrehoz egy konstruktort, amelynek paraméterei vannak az egyes tulajdonságokhoz. Például tegyük hozzá @TupleConstructor hoz Munkavállaló osztály: Most létrehozhatunk Munkavállaló az objektum átadásának paraméterei az osztályban meghatározott tulajdonságok sorrendjében. Ha objektumok létrehozása közben nem adunk meg értékeket a tulajdonságoknak, a Groovy az alapértelmezett értékeket veszi figyelembe: Hasonló @ToString, deklarálhatunk olyan paramétereket, mint kizárja, magába foglalja és includeSuperProperties val vel @TupleConstructor szükség szerint módosítsa a hozzá kapcsolódó konstruktor viselkedését. Tudjuk használni @EqualsAndHashCode generálja az alapértelmezett megvalósítását egyenlő és hash kód módszerek a fordítás idején. Ellenőrizzük a @EqualsAndHashCode hozzáadásával a Munkavállaló osztály: @Kánoni kombinációja @ToString, @TupleConstructor, és @EqualsAndHashCode annotációk. Csak hozzáadásával mindhármat könnyedén felvehetjük egy Groovy osztályba. Azt is kijelenthetjük @Kánoni mindhárom feljegyzés bármelyikének speciális paraméterével. Gyors és megbízható megvalósítási mód Klónozható interfész a @AutoClone annotáció. Ellenőrizzük a klón módszer hozzáadás után @AutoClone hoz Munkavállaló osztály: A naplózási támogatás hozzáadásához bármely Groovy osztályhoz csak annyit kell tennünk, hogy hozzáadjuk a groovy.util.logging csomag. Engedélyezzük a JDK által biztosított naplózást a @Log jegyzet a Munkavállaló osztály. Utána hozzáadjuk a logEmp módszer: Felhívás a logEmp módszer egy Munkavállaló Az objektum megmutatja a naplókat a konzolon: Hasonlóképpen a @Commons az Apache Commons naplózási támogatásának hozzáadásához annotáció áll rendelkezésre. @ Log4j elérhető az Apache Log4j 1.x naplózás támogatásához és @ Log4j2 az Apache Log4j 2.x-hez. Végül használja @ Slf4j az egyszerű naplózási homlokzat hozzáadása a Java támogatáshoz. Ebben az oktatóanyagban a Groovy-ban feltártuk a metaprogramozás fogalmát. Útközben láttunk néhány figyelemre méltó metaprogramozási funkciót mind a futás, mind a fordítás idejére vonatkozóan. Ugyanakkor további, a Groovy-ban elérhető praktikus jegyzeteket is feltártunk a tisztább és dinamikusabb kódokhoz. Szokás szerint a cikk kód implementációi elérhetők a GitHubon.Employee emp = new Employee (keresztnév: "Norman", vezetéknév: "Lewis") println emp.cím
groovy.lang.MissingPropertyException: Nincs ilyen tulajdonság: osztály címe: com.baeldung.metaprogramming.Employee
def propertyMissing (karakterlánc tulajdonságnév) {"tulajdonság '$ propertyName' nem érhető el"}
assert emp.address == "tulajdonság" cím "nem érhető el"
def propertyMissing (karakterlánc tulajdonságnév, tulajdonságValue) {println "nem állíthatja be a $ propertyValue értéket - a '$ propertyName' tulajdonság nem érhető el"}
3.2. methodMissing
próbáld meg az {emp.getFullName ()} catch (MissingMethodException e) {println "metódus nincs meghatározva"}
def methodMissing (karakterlánc metódusnév, def módszerArgs) {"metódus '$ methodName' nincs meghatározva"}
assert emp.getFullName () == "A 'getFullName' metódus nincs meghatározva"
3.3. ExpandoMetaClass
Employee.metaClass.address = ""
Employee emp = new Employee (keresztnév: "Norman", vezetéknév: "Lewis", cím: "US") állítja emp.cím == "US"
emp.metaClass.getFullName = {"$ vezetékNév, $ firstName"}
assert emp.getFullName () == "Lewis, Norman"
Employee.metaClass.constructor = {Karakterlánc keresztnév -> új alkalmazott (keresztnév: keresztnév)}
Munkavállaló norman = új Alkalmazott ("Norman") állítja norman.firstName == "Norman" állítja norman.lastName == null
String.metaClass.capitalize = {String str -> str.substring (0, 1) .toUpperCase () + str.substring (1)}
állítsd a "norman" -t. kapitalize () == "Norman"
3.4. Hosszabbítások
class BasicExtensions {static int getYearOfBirth (Employee self) {return Year.now (). value - self.age}}
moduleName = core-groovy-2 moduleVersion = 1.0-SNAPSHOT extensionClasses = com.baeldung.metaprogramming.extension.BasicExtensions
def age = 28 def várhatóYearOfBirth = Year.now () - age Employee emp = new Employee (age: age) állítsa emp.getYearOfBirth () == várhatóYearOfBirth.value
class StaticEmployeeExtension {static Employee getDefaultObj (Employee self) {return new Employee (firstName: "firstName", lastName: "vezetékNév", age: 20)}}
staticExtensionClasses = com.baeldung.metaprogramming.extension.StaticEmployeeExtension
állítsa Employee.getDefaultObj (). firstName == "keresztnév" assert Employee.getDefaultObj (). lastName == "lastName" állítsa Employee.getDefaultObj (). age == 20
public static void printCounter (Egész én) {while (self> 0) {println self self}} return self} állítás 5.printCounter () == 0
public static Hosszú négyzet (Long self) {return self * self} 40l.square () == 1600l
4. Fordítási idejű metaprogramozás
4.1. @ToString
@ToString osztály Alkalmazott {long id String firstName String vezetéknév int age}
Alkalmazott alkalmazott = új Alkalmazott () alkalmazott.id = 1 alkalmazott.névNév = "norman" alkalmazott.névNév = "lewis" alkalmazott.kor = 28 állítja alkalmazott.toString () == "com.baeldung.metaprogramming.Employee (1, norman, lewis, 28) "
@ToString (includePackage = hamis, kizárja = ['id'])
állítsd alkalmazott.toString () == "Alkalmazott (norman, lewis, 28)"
4.2. @TupleConstructor
@TupleConstructor osztály Alkalmazott {long id String firstName String vezetékNév int age}
Alkalmazott norman = új alkalmazott (1, "norman", "lewis", 28) állítja a norman.toString () == "Alkalmazott (norman, lewis, 28)"
Alkalmazott snape = new Employee (2, "snape") állítja a snape.toString () == "Alkalmazott (snape, null, 0)"
4.3. @EqualsAndHashCode
Alkalmazott normanCopy = new Employee (1, "norman", "lewis", 28) állítja, hogy norman == normanCopy állítja, hogy norman.hashCode () == normanCopy.hashCode ()
4.4. @Kánoni
4.5. @AutoClone
próbáld ki {Employee norman = new Employee (1, "norman", "lewis", 28) def normanCopy = norman.clone () assert norman == normanCopy} catch (CloneNotSupportedException e) {e.printStackTrace ()}
4.6. Naplózási támogatás @Log, @Commons, @ Log4j, @ Log4j2, és @ Slf4j
def logEmp () {log.info "Alkalmazott: $ lastName, $ firstName $ age éves korú"}
Alkalmazott alkalmazott = új alkalmazott (1, "Norman", "Lewis", 28) alkalmazott.logEmp ()
INFO: Alkalmazott: Lewis, Norman 28 éves
5. Következtetés