V dnešním článku bych vám rád představil zajímavou knihovnu, která přináší do nynější verze Javy takové techniky, kterých se nejspíše dočkáme v dalším vydání tohoto programovacího jazyka. Pojďme si tedy ukázat, co nám knihovna Lombok nabízí.
Seznámení
Jak bylo v úvodu naznačeno, Lombok nám má práci především urychlit. V čem tedy toto urychlení spočívá? Především v odstranění rutinní práce, kterou musí každý programátor dělat skoro každý den. Vzpomeňte si, kolikrát jste museli generovat get a set metody, kolikrát jste museli ošetřovat výjimky a kolikrát jste museli vytvářet metody toString, hashCode a equals. U všech těchto činností vám Lombok nabízí pomoc v podobě anotací, které vám tyto činnosti usnadní.
Pojďme si nejprve ukázat možnosti Lomboku na jednoduchém příkladě:
@ToString(includeFieldNames=true, exclude={"name"}) @EqualsAndHashCode(exclude={"name"}) public class ExamplePojo3 { @Getter private String name; @Getter @Setter private String surname; @Getter(AccessLevel.PROTECTED) @Setter(AccessLevel.PROTECTED) private String middleName; }
Na ukázce je vidět použití anotací ToString, EqualsAndHashCode, Getter a Setter. Poslední zmíněné anotace není třeba více představovat – slouží k automatickému vygenerování get a set metod. Pomocí modifikátorů lze měnit viditelnost těchto metod – viz modifikátor accessLevel u fieldu middleName.
ToString anotace pak slouží k vygenerování toString metody z fieldů třídy. Tento přístup má výhodu především tehdy, pokud často danou třídu měníme – nemusíme myslet na doplňování toString metody. Pomocí modifikátorů lze měnit chování této anotace – především vyjmutí některých fieldů z metody (exclude) a začlenění jmen fieldů do textové informace metody (includeFieldNames).
Poslední anotací, která je použita v tomto příkladu je anotace EqualsAndHashCode – ta slouží k vygenerování metod equals a hashCode z fieldů třídy. Pomocí modifikátoru exlude můžeme opět nějaké fieldy vyjmout z výběru.
Instalace
Instalaci knihovny provedete stažením ze stránek projektu, kde najdete i instruktážní video a veškerou dokumentaci. Poté si knihovnu naimportujte do projektu a můžete ji začít používat.
Pokud jako vaše vývojové prostředí používáte Eclipse, pak jednoduchým spuštěním souboru lombok.jar nainstalujete plugin, který usnadní používání knihovny. Generování veškerého kódu, který knihovna vytváří, se totiž provádí až při kompilaci, tudíž metody nejsou do té doby vidět – tento nedostatek odstraňuje právě zmiňovaný plugin.
Další anotace
Z předchozího příkladu je jasné, že by vypisování všech anotací trvalo poměrně dlouhou dobu u jednoduchých POJO. Proto Lombok myslí na tyto třídy a přináší anotaci Data. Ta v sobě schraňuje všechny zmiňované anotace z našeho prvního příkladu. Její použití je snadné:
@Data public class ExamplePojo1 { private String name; private String surname; }
Mezi další zajímavé funkcionality této knihovny patří usnadnění ošetření výjimek, automatické uzavírání streamů a zajímavé vyřešení synchronizace vláken. Nejprve opět ukázka:
public class Main { private static Object exampleLock = new Object(); @SneakyThrows(Exception.class) public static void main(String[] args) { @Cleanup InputStream in = new FileInputStream("aaa.txt"); @Cleanup OutputStream out = new FileOutputStream("bbb.txt"); } @Synchronized public static void synch1() { System.out.println("aaa"); } @Synchronized("exampleLock") public static void synch2() { System.out.println("bbb"); } }
Jako první zmíníme anotaci SneakyThrows. Tato anotace obalí celou metodu, nad kterou je uvedena, klasickým try catch blokem, který bude reagovat na výjimku uvedenou v anotaci. S touto anotací je třeba zacházet opatrně a vždy si ověřit, že dělá přesně to, co potřebujete.
Dále následuje Cleanup. Tato anotace slouží k automatickému ošetření streamů a jiných objektů, které potřebují být uzavřeny i při jejich neúspěšném použití. Typicky se tedy jedná o zavolání metody close() v finally bloku, která bezpečně uzavře v tomto případě stream. Zde je potřeba podotknout, že podle dokumentace nedojde k vypsání žádné chybové hlášky do logu při zachycení vyjímky. Metoda, která bude zavolána v finally bloku, lze specifikovat a samotné anotaci (viz dokumentace).
Poslední anotací je Synchronized. Ta slouží k obalení kódu metody do synchronized bloku, přičemž dojde také k vytvoření LOCK objektu, který bude k synchronizaci použit. Pokud si daný objekt chceme vytvořit sami, poté ho stačí jako parametr uvést v dané anotaci.
Jak sami vidíte, knihovna Lombok nabízí zajímavé možnosti, které usnadní vytváření především POJO tříd, které jsou rutinou na skoro každém projektu. Dejte ji proto šanci a podělte se s námi v komentářích o vaše zkušenosti.
9.11.2009 at 06:54
nazvy anotaci by mohly byt lepsi, dela to svym zpusobem to same co groovy, ale i tak to vypada celkem slibne. problem s vecnym pregenerovanim equals a to string v eclipse jsem uz taky nekolikrat resil a radsi jsem nakonec dal sanci groovy. diky za tip, urcite to nekdy vyzkousim
9.11.2009 at 08:22
Otazkou je, co toto udela s prehlednosti kodu… Napr. odchyceni vyjimky – pouzivat misto try/catch anotaci @SneakyThrows(Exception.class) ??? Tak toto si neumim moc predstavit…
Druha vec, ktera se mi na tom vsem nelibi – vytvorim POJO pomoci anotace @Data. To zajisti, ze mohu pouzivat gettery/settery, ktere ale nikde nevidim (jak je psano, vytvori se az pri kompilaci). Pak muze byt dost matouci narazit na metodu pojo.getXY(), ktera prakticky neexistuje – jak bude uvazovat clovek, ktery nema Eclipse???
9.11.2009 at 08:54
Snad se to autora nedotkne, ale ta knihovna se mi nelibi. Duvody jsou dva: 1) nic neresi, protoze pridani getteru a setteru umi kazde IDE, 2) hlavne: nelibi se mi, ze anotace meni semantiku programu. Je zvykem, ze semantika je vyjadrena klicovymi slovy. Anotace obvykle pridavaji ke zdrojovemu kodu dodatecne informace, ktere lze zpracovavat napr. nejakym nastrojem pro statickou analyzu.
Jinak je to ale hezky napsany clanek.
9.11.2009 at 10:19
ja v tehle knihovne nevidim moc prinos, nez natukam dvacetkrat @Getter a @Setter anotace tak uz to budu mit od IDE vygenerovane, jde pouzit @Data, v te ale zase vidim potiz protoze automaticky zahrnuje @EqualsAndHashCode a implementace techto metod muze byt v ruznych pripadech ruzna, takze si to potrebuju naimplementovat sam
na
@Synchronized
public static void synch1()
nevidim uz vubec nic, podle me je to jeste o jeden napsany znak vic nez
public synchronized void …
a @Synchronized(„exampleLock“) se zda na prvni pohled fajn, ale nakonec je podle me lepsi mit to primo v kodu a ne jako string, protoze potom mi bude spolehlive fungovat refactoring
podotykam, ze reaguji jenom na tento clanek, na feature list jsem se nedival takze je mozne, ze je ten projekt mnohem zajimavejsi, nez si myslim
blaf
9.11.2009 at 15:36
O anotacích pro automatické generování getterů a setterů jsem taky přemýšlel. Ale když jsem se začal zajímat, jak by se daly implementovat, narazil jsem na dvě věci:
1. Anotační procesor nesmí modifikovat třídu, ve které jsou anotace uvedeny.
2. Mirror API neposkytuje dostatek prostředků k popsání těla metody.
Přinejmenším na Suní Javě jsou oba problémy řešitelné (přetypováním na příslušné Suní třídy), ale do toho už se mi nechtělo vrtat. Každopádně pohled do javadocu Lomboku napovídá, že chtě nechtě taky museli zvolit tuhle cestu :-)
9.11.2009 at 18:56
Děkuji za Vaše reakce a názory – musím říci, že se všemi komentáři více méně souhlasím. Použití této knihovny s sebou nese určitá omezení a také nutnost používat jednotné IDE. Nemluvě o snížené čitelnosti díky anotacím.
Já na něm oceňuji především rychlost vytváření jednoduchých POJO a také nazančení budoucího vývoje vytváření těchto tříd (za pár let nám tento přístup bude možná připadat naprosto normální).
Projekt Lombok je pro mne zajímavou zkušeností a rozšířením obzoru Java technologií – i s tímto cílem jsem článek psal – upozornit na nevšední řešení, která nám Java nabízí.
10.11.2009 at 09:44
No napad je to zajimavej, ale muselo by se to stat soucasti Javy, tj. misto anotaci by to byly klicove slova, treba jako property/synthetise, ktere pouziva Objective-C. Ale dokazu se bez toho obejit. Mne mnohem vic vadi zavislost Javy na Stringu, i v pripadech kdy by bylo lepsi pouzit typove bezpecnou konstrukci. Viz treba : http://incubator.apache.org/empire-db/empiredb/stringfree.htm
10.11.2009 at 09:53
Vyzera to urcite zaujimavo, ale napada ma par pripadov, kde moze nastat problem pri praci s IDE.
Je nejaka podpora anotaciam @Getter a @Setter zo strany IDE?
Teda, ci sa tie metody rovno zobrazuju aj v auto completion?
Takisto call hierarchy – v IDE sa asi nebude dat vyhladat miesto volania tychto metod, kedze tam ziadna metoda nie je.
toString, hashCode, cleanup a ostatne su naopak velmi slubne a tiez to rad vyskusam.
11.11.2009 at 16:58
Pro Eclipse je podpora bezproblémová – tedy funguje jak auto completion tak vyhledávání volání. V ostaních IDE je to bohužel problém – nevím jestli by to byl problém doprogramovat jako nějaký plugin.
10.11.2009 at 11:39
Já osobně, možná puristům navzdory :-), bych rozhodně přinejmenším anotace pro generování getterů a setterů chtěl. A to jednak pro hloupá DTO (pánové! Opravdu si je necháváte generovat od IDE? A jak to pak řešíte, když chcete beanu měnit? Podle mě to je pěkný opruz.), a jednak pro setterovou dependency injection.
Tohle je takový triviální příklad metaprogramování, které je mezi javisty pohříchu neznámé až nepopulární. Škoda toho :-)
10.11.2009 at 21:08
A proc by se mely gettery a settery delat anotaci? Proc by to nemelo byt klicove slovo? Navrh na doplneni Javy o klicove slovo property existuje nekolik let. Nejsem sice jeho skalnim priznivcem, nicmene je to lepsi nez anotace. Ta je podle meho nazoru jako dratem do oka.
11.11.2009 at 10:34
To je jednoduché: protože anotace jsou samostatná obecná konstrukce, zatímco klíčová slova se do jazyka přidávají velmi těžko. Přidání klíčových slov jako property, getter nebo setter by rozbilo tuny programů. Osobně jsem zastáncem toho, že i věci jako private, protected, public nebo final, volatile, synchronized, strictfp atd. by měly být anotace (což je samozřejmě dneska nemožné, ale tak ňák v principu :-) ). Nakonec to jsou data o datech, žeáno. Ale to jsem odbočil. Klidně ať to jsou klíčová slova, pokud k tomu někdo najde odvahu :-)
11.11.2009 at 11:36
Zpetna kompatibilita je samozrejme dulezita. Ovsem tim, ze bys spoustu veci delal anotacemi, preneses problem jen nekam jinam. Je pridani anotace @Getter zpetne kompatibilni? Bohuzel neni. I kdyz tech „rozbitych“ programu bude podstatne mene nez pri pridani klicoveho slova property, tak casem se i jmenny prostor anotaci muze zaplnit a pak bude pridani nove anotace problematicke.
11.11.2009 at 15:37
Nastesti u anotaci mame jmeny prostor a jsou uvozeny specialnim znakem @. Takze tam tu hrozbu nevidim.
11.11.2009 at 22:39
Ani ne, jmenný prostor anotací je totožný se jmenným prostorem tříd, tedy je hierarchický. Opovažuju se tvrdit, že nikdo na světě dneska nemá anotaci java.lang.Getter, zato proměnných getter bude jak naseto (ve spojitosti s reflexí). Ono to jde někdy řešit tím, že případná nová klíčová slova budou mít svůj význam pouze na určitých místech programu (zrovna v tomhle případě by to fungovalo), ale stejně…
12.11.2009 at 16:28
To bys musel zakazat import pkg.*;
Jinak to, ze by nova klicova slova mohla byt v nekterych mistech pouzita jako identifikator (chapu spravne, to co pises?) snad ani nemuzes myslet vazne.
12.11.2009 at 16:54
Nemusel, vždycky jde použít FQN. Tohle už je v podstatě vyřešené, zkus si vytvořit někde ve vlastním projektu třídu String :-) (Dobře, tak já to řeknu: explicitní import nebo přítomnost ve stejném balíku má přednost před implicitním importem java.lang.*.)
Jasně že to můžu myslet vážně, a nejsem v tom sám, například, pokud se dobře pamatuju, v rámci Project Coin se objevil návrh, který měl za cíl zjednodušit psaní „vázaných“ typových parametrů (bounded type parameters) použitím klíčových slov in a out. Jako že namísto ? extends String by se psalo in String, a namísto ? super String by se psalo out String. Ale mimo deklarace typových parametrů by šlo slova in a out normálně používat jako identifikátory. Tuším to navrhoval Neal Gafter :-) Je to vcelku přímočarý způsob, jak přidávat do jazyka klíčová slova a omezit přitom dopad na existující kód. Nelíbí se mi, o tom žádná, zesložití to parsování, ale způsob to je.
Omlouvám se, že reaguju sám na sebe, ale pod tvým příspěvkem není odkaz „odpovědět“. Korektóóór!! :-)
12.11.2009 at 21:29
Ok, tak jsem to zkusil:
package xxx;
public class String { }
package test;
import xxx.*;
public class X {
String s;
}
A vysledek? „reference to String is ambigous“
Jinak tim, ze jsi na me vytahl navrh Neala Gaftera jsi me dostal, takze vyhravas na body. :)
13.11.2009 at 18:31
Máš pravdu, s import xxx.* to nefunguje. S import xxx.String naprosto bez problémů. Mně importy řeší IDEA sama, takže o nich vlastně ani nevím — můžeš dát link na nějaké vysvětlení? Hm, nebo bych mohl zabrousit do JLS. Vlastně mne to docela překvapuje, I should have known better :-)
20.11.2009 at 01:36
Podle me je to presne jako by v kazdym souboru stalo
import java.lang.*;
Paxamozrejme nestaci importovat cely xxx.* ale je treba konkretni import.
15.11.2009 at 21:21
kravina;
same nezmyselne veci, navyse znizujuce citatelnost kodu (nie kazdy tuto kniznicu musi poznat a hoci @getter je pomerne jednoznacne, @data uz nie), mimochodom a co ked chcem nie public ale private getteR? ten si napisem sam?
okrem toho,
anotacie su mor a som zvedavy, kedy si to konecne ludia uvedomia; ja osobne mojim podriadenym anotacie zakazujem a naveky budem
17.11.2009 at 16:24
K první části komentáře – stačí si pořádně článek přečíst, o změně viditelnosti generovaných metod je v něm řeč (např.: @Getter(AccessLevel.PRIVATE)).
A co říci k druhé části? Jen asi toliko, že je mi líto vašich podřízených, když je jejich nadřízený nemotivuje k poznávání nových technologií a postupů ;-) . Netvrdím, že anotace jsou odpovědí na všechny problémy Javy, ale jejich úplná ignorace je myslím ke škodě každého vývojáře.
20.11.2009 at 01:51
Neda mi to abych nepridal muj nazor:
SneakyThrows: Tvrzeni ze „obalí celou metodu, nad kterou je uvedena, klasickým try catch blokem“ odporuje „code generated by lombok will not ignore, wrap, replace, or otherwise modify the thrown checked exception“ tedy je spatne. SneakyThrows je jen takovy „podvod na prekladaci“.
Generovani kodu: Jasneze mi ide vygeneruje tuny getru a setru za par milisekund, ale pak je tam budu mit a programy se vice ctou nez pisou. Proto se mi neco jako @Data libi.
Klicova slova: Vzdyt by stacilo napsat neco jako
package 8 cz.ja.neco;
a tim by bylo dany ze se pouzivaji syntaxy javy 8, tj. plati vsecky klicovy slova az do verze 8 vcetne a zadny jiny. Zpetna kompatibilita je dana, ze to nezkousne starsi prekladac nevadi, kdyz jsou tam ficurky quli kterym se udelal novy.
Anotace: Aby se vylezlo z xml hell, zavadi se annotation hell, rozsiruje se aby se nahradily chybejici veci jako properties. Anotace jsou dobry i spatny v tom, ze je narozdil od jazyka muze vyvijet kazdy (dobry bo neni treba cekat roky na dalsi verzi; spatny bo se tim vyvoj forkuje).