Project Lombok (from now on, Lombok) is an annotation-based Java library that allows you to reduce boilerplate code. Lombok offers various ...
DevelopersIdentity&SecurityBusinessLeadershipCultureEngineeringAnnouncementsTalkToSalesSignUpDiscoverandenabletheintegrationsyouneedtosolveidentityAuth0MarketplaceDevelopersIdentity&SecurityBusinessLeadershipCultureEngineeringAnnouncementsTryAuth0ForFreeTalkToSalesAuth0DocsImplementAuthenticationinMinutesOAuth2AndOpenIDConnect:TheProfessionalGuideGetthefreeebook!Javaisagreatbutverboselanguage.Youmaybeendingupwritingmanylinesofcodeeventoachievethemostcommongoals.Plus,itdefinitelyinvolvesrepetitivecode,likegettersandsetters.Thisleadstoahugeamountofboilerplateandavoidablecode.Notonlydoesthisaddnothingtothebusinesslogicofyourapplication,butwritingitisanunnecessarilyboringandtime-consumingprocess.Thisiswhyyoushouldstartemployingtoolsandlibrariestomakeyoumoreproductivebyavoidingthis.That’swhereLombokcomesintoplay!ThisJavalibraryprovidesyouwithseveralannotationsaimedatavoidingwritingJavacodeknowntoberepetitiveand/orboilerplate.ProjectLombokworksbypluggingintoyourbuildprocess.Then,itwillauto-generatetheJavabytecodeintoyour.classfilesrequiredtoimplementthedesiredbehavior,basedontheannotationsyouused.Thus,eachannotationofferedbyProjectLombokallowsyoutoskipwritingmethodsandlogicyouwouldliketoavoid,likeconstructors,equals,andhashcodefunctions.Thiswillsaveyoualotoftimeandletyoufocusonthebusinesslogicofyourproject.Plus,youwillbeabletokeepyourcodebasesmaller,cleaner,andeasiertobereadandmaintained.First,wewillseewhatProjectLombokisandhowitworks.Then,wewillstudythemostcommonandrelevantLombok’sannotations,understandingwhatthemostimportantonesare,where,andhowtousethem.Next,itwillbetimetoseehowtointegrateitinyourIDE(IntegratedDevelopmentEnvironment)andwhyyoushouldnotbeafraidofusingit.PrerequisitesThisisthelistofalltheprerequisitestoreplicatetheexamplesthatwillbeshownnext:Java>=1.8Gradle>=4.xorMaven3.6.xProjectLombok>=1.18.20WhatisLombokProjectLombok(fromnowon,Lombok)isanannotation-basedJavalibrarythatallowsyoutoreduceboilerplatecode.LombokoffersvariousannotationsaimedatreplacingJavacodethatiswellknownforbeingboilerplate,repetitive,ortedioustowrite.Forexample,byusingLombok,youcanavoidwritingconstructorswithnoarguments,toString(),equals(),andhashCode()methodsbysimplyaddingafewannotations.Themagichappensduringthecompile-timewhenthelibraryinjectsthebytecoderepresentingthedesiredandboilerplatecodeintoyour.classfiles.Plus,aswewillsee,thelibrarycanbepluggedintoyourIDE,lettingyouhavethesameexperienceasifyouhadwrittenalltheboilerplatecodeyourself.YoucaneasilyinstallLombokbyaddinglomboktoyourdependencies.
IfyouareaGradleuser,addthesetwolinestothedependenciessectionofyourbuild.gradlefile:compileOnly'org.projectlombok:lombok:1.18.20'
annotationProcessor'org.projectlombok:lombok:1.18.20'WhileifyouareaMavenuser,addthefollowingdependencytoyourpom.xmlfile:
org.projectlombok
lombok
1.18.20
provided
Plus,addtheLombokdependencytothemaven-compiler-pluginconfigurationsectionasfollows:
org.apache.maven.plugins
maven-compiler-plugin
3.5.1
11
org.projectlombok
lombok
1.18.20
Now,youhaveallyouneedtostartusingLombok.MostCommonLombokAnnotationsHereyoucanfindthemostcommonandimportantLombokannotations.EachofthemwillbeexplainedandthenseeninusecomparedtotheequivalentJavavanillatranslation.Toseeexamplesandgetmoresupport,clickoneachannotationandvisititspageontheLombokofficialdocumentation.@Getter,@SetterWhenafieldisannotatedwith@Getterand/or@Setter,Lombokwillautomaticallygeneratethedefaultgetterand/orsetter,respectively.Thedefaultimplementationforgetterssimplytakescareofreturningtheannotatedfield.Similarly,thedefaultimplementationforsetterstakesoneparameterofthesametypeastheannotatedfieldandsimplysetsitwiththereceivedvalue.Whenafieldcalledvalueisannotatedwithboth@Getterand@Setter,LombokwilldefineagetValue()(orisValue()ifthefieldisboolean),andasetValue()method.Thegeneratedgetter/settermethodwillbepublic,unlessaparticularAccessLevelisspecified.TheallowedAccessLevelvaluesarePUBLIC,PROTECTED,PACKAGE,andPRIVATE.Please,notethatyoucanalsoannotatetheentireclass.Inthiscase,thislogicwillbeappliedtoeachfield.WithLombok@Getter
@Setter
publicclassAuthor{
privateintid;
privateStringname;
@Setter(AccessLevel.PROTECTED)
privateStringsurname;
}JavaVanillapublicclassUser{
privateintid;
privateStringname;
privateStringsurname;
publicintgetId(){
returnid;
}
publicvoidsetId(intid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetSurname(){
returnsurname;
}
protectedvoidsetSurname(Stringsurname){
this.surname=surname;
}
}@NoArgsConstructor,@RequiredArgsConstructor,@AllArgsConstructorWhenaclassisannotatedwith@NoArgsConstructor,Lombokwilltakecareofautomaticallygeneratingaconstructorwithnoparameters.Likewise,whenannotatedwith@AllArgsConstructor,aconstructorwithoneparameterforeachfieldinyourclasswillbegenerated.Similarly,@RequiredArgsConstructorleadstoaconstructorwithaparameterforeachfieldrequiringspecialhandling.Inparticular,thisinvolvesnon-initializedfinalfields,aswellasanyfieldsmarkedas@NonNullthatarenotinitializedwheredeclared.Please,donotforgetthatstaticfieldswillbeignoredbytheseannotations.WithLombok@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
publicclassAuthor{
privateintid;
privateStringname;
privateStringsurname;
privatefinalStringbirthPlace;
}JavaVanillapublicclassAuthor{
privateintid;
privateStringname;
privateStringsurname;
privatefinalStringbirthPlace;
//@NoArgsConstructor
publicAuthor(){}
//@AllArgsConstructor
publicAuthor(intid,Stringname,Stringsurname,StringbirthPlace){
this.id=id
this.name=name
this.surname=surname
this.birthPlace=birthPlace
}
//@RequiredArgsConstructor
publicAuthor(StringbirthPlace){
this.birthPlace=birthPlace
}
}@ToStringWhenaclassisannotatedwith@ToString,LombokwilltakecareofgeneratingaproperimplementationofthetoString()method.Bydefault,aStringcontainingtheclassname,followedbyeachfield'svalueseparatedbyacomma,willbereturned.BysettingtheincludeFieldNamesparametertotrue,thenameofeachfieldwillbeplacedbeforeitsvalue.Bydefault,allnon-staticfieldswillbeconsideredwhengeneratingthetoString()method.Annotateafieldwith@ToString.ExcludetomakeLombokignoreit.Alternatively,youcanspecifywhichfieldsyouwishtobetakenintoaccountbyusing@ToString(onlyExplicitlyIncluded=true).Then,[email protected]@ToString(includeFieldNames=true)
publicclassAuthor{
privateintid;
privateStringname;
privateStringsurname;
}JavaVanillapublicclassAuthor{
privateintid;
privateStringname;
privateStringsurname;
@Override
publicStringtoString(){
return"Author(id="+this.id+",name="+this.name+",surnname="+this.surname+")";
}
}@EqualsAndHashCodeAnnotateaclasswith@EqualsAndHashCode,andLombokwillautomaticallyimplementtheequals()andhashCode()methodsforyou.Bydefault,allnon-static,non-transientfieldswillbetakenintoaccount.Youcanmodifywhichfieldsareusedbyannotatingthemwith@EqualsAndHashCode.Includeor@EqualsAndHashCode.Exclude.Alternatively,youcanannotateyourclasswith@EqualsAndHashCode(onlyExplicitlyIncluded=true)andthenspecifyexactlywhichfieldsormethodsyouwanttobeusedbymarkingthemwith@EqualsAndHashCode.Include.Please,notethattheequals())andhashCode())methodswillbegeneratedbyLombokwithoutbreakingthecontractbetweenthem.FollowthelinkonthetwomethodstotheofficialJavadocumentationtolearnmoreaboutthecontractsthatequals()andhashCode()implementationsshouldfulfill.WithLombok@Getter
@Setter
@EqualsAndHashCode
publicclassAuthor{
privateintid;
privateStringname;
privateStringsurname;
}JavaVanillapublicclassAuthor{
//gettesandsetters...
@Override
publicinthashCode(){
finalintPRIME=31;
intresult=1;
result=prime*result+id;
result=prime*result+((name==null)?0:name.hashCode());
result=prime*result+((surname==null)?0:surname.hashCode());
returnresult;
}
@Override
publicbooleanequals(Objecto){
if(o==this)returntrue;
if(!(oinstanceofAuthor))returnfalse;
Authorother=(Author)o;
if(!other.canEqual((Object)this))returnfalse;
if(this.getId()==null?other.getId()!=null:!this.getId().equals(other.getId()))returnfalse;
if(this.getName()==null?other.getName()!=null:!this.getName().equals(other.getName()))returnfalse;
if(this.getSurname()==null?other.getSurname()!=null:!this.getSurname().equals(other.getSurname()))returnfalse;
returntrue;
}
}@NonNullYoucanannotatewith@NonNullarecordcomponent,aparameterofamethod,oranentireconstructor.Thisway,Lombokwillgeneratenull-checkstatementsforyouaccordingly.WithLombokpublicclassAuthor{
privateintid;
privateStringname;
privateStringsurname;
publicAuthor(
@NonNullintid,
@NonNullStringname,
Stringsurname
){
this.id=id;
this.name=name;
this.surname=surname;
}
}JavaVanillapublicclassAuthor{
privateintid;
privateStringname;
privateStringsurname;
publicAuthor(
intid,
Stringname,
Stringsurname
){
if(id==null){
thrownewNullPointerException("idismarked@NonNullbutisnull");
}
this.id=id;
if(name==null){
thrownewNullPointerException("nameismarked@NonNullbutisnull");
}
this.name=name;
this.surname=surname;
}
}@Data@Dataisashortcutannotationthatcombinesthefeaturesof@ToString,@EqualsAndHashCode,@Getter@Setter,[email protected],@DatageneratesalltheboilerplateinvolvedinPOJOs(PlainOldJavaObjects).Thismeans,inparticular,gettersforallfields,settersforallnon-finalfields,propertoString,equals,andhashCodeimplementationsinvolvingeveryfieldoftheclass,andaconstructorforallfinalfields.WithLombok@Data
publicclassAuthor{
privatefinalintid;
privateStringname;
privateStringsurname;
}JavaVanillapublicclassAuthor{
privatefinalintid;
privateStringname;
privateStringsurname;
publicAuthor(intid){
this.id=id;
}
publicintgetId(){
returnid;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetSurname(){
returnsurname;
}
publicvoidsetSurname(Stringsurname){
this.surname=surname;
}
@Override
publicinthashCode(){
finalintPRIME=31;
intresult=1;
result=prime*result+getId();
result=prime*result+((getName()==null)?0:getName().hashCode());
result=prime*result+((getSurname()==null)?0:getSurname().hashCode());
returnresult;
}
@Override
publicbooleanequals(Objecto){
if(o==this)returntrue;
if(!(oinstanceofAuthor))returnfalse;
Authorother=(Author)o;
if(!other.canEqual((Object)this))returnfalse;
if(this.getId()==null?other.getId()!=null:!this.getId().equals(other.getId()))returnfalse;
if(this.getName()==null?other.getName()!=null:!this.getName().equals(other.getName()))returnfalse;
if(this.getSurname()==null?other.getSurname()!=null:!this.getSurname().equals(other.getSurname()))returnfalse;
returntrue;
}
}@Value@Valueistheimmutablevariantof@Data.ThismeansthatallfieldsaremadeprivateandfinalbyLombokbydefault.Plus,setterswillnotbegenerated,andtheclassitselfwillbemarkedasfinal.Thisway,theclasswillnotbeinheritable.Justlikewhathappenswith@Data,toString(),equals()andhashCode()implementationsarealsocreated.WithLombok@Data
publicclassAuthor{
intid;
Stringname;
Stringsurname;
}JavaVanillapublicfinalclassAuthor{
privatefinalintid;
privatefinalStringname;
privatefinalStringsurname;
publicAuthor(intid,Stringname,Stringsurname){
this.id=id
this.name=name
this.surname=surname
}
publicintgetId(){
returnid;
}
publicStringgetName(){
returnname;
}
publicStringgetSurname(){
returnsurname;
}
@Override
publicinthashCode(){
finalintPRIME=31;
intresult=1;
result=prime*result+getId();
result=prime*result+((getName()==null)?0:getName().hashCode());
result=prime*result+((getSurname()==null)?0:getSurname().hashCode());
returnresult;
}
@Override
publicbooleanequals(Objecto){
if(o==this)returntrue;
if(!(oinstanceofAuthor))returnfalse;
Authorother=(Author)o;
if(!other.canEqual((Object)this))returnfalse;
if(this.getId()==null?other.getId()!=null:!this.getId().equals(other.getId()))returnfalse;
if(this.getName()==null?other.getName()!=null:!this.getName().equals(other.getName()))returnfalse;
if(this.getSurname()==null?other.getSurname()!=null:!this.getSurname().equals(other.getSurname()))returnfalse;
returntrue;
}
}AdvancedLombokAnnotationsHereyoucanfindthemostcomplexLombokannotations.EachofthemwillbeexplainedandthenseeninusecomparedtotheequivalentJavavanillatranslation.Toseeexamplesandgetmoresupport,clickoneachannotationandvisititspageontheLombokofficialdocumentation.@Cleanup@Cleanupcanbeusedtoensureagivenresourceisautomaticallycleanedupbeforeleavingthecurrentscope.Bydefault,thecleanupmethodoftheannotatedresourceisassumedtobeclose(),butyoucanspecifythenameofthedesiredmethodtobecalledinstead.Notethatthisannotationworksbyharnessingthetry-with-resourcesstatement.WithLombokpublicclassCleanupDemo{
publicstaticvoidmain(String[]args)throwsIOException{
@Cleanup
InputStreaminput=newFileInputStream(args[0]);
@Cleanup
OutputStreamoutput=newFileOutputStream(args[1]);
byte[]b=newbyte[10000];
while(true){
intr=input.read(b);
if(r==-1)
break;
output.write(b,0,r);
}
}
}JavaVanillapublicclassCleanupDemo{
publicstaticvoidmain(String[]args)throwsIOException{
try(OutputStreamoutput=newFileOutputStream(args[1])){
try(InputStreaminput=newFileInputStream(args[0])){
byte[]b=newbyte[10000];
while(true){
intr=input.read(b);
if(r==-1)
break;
output.write(b,0,r);
}
}
}
}
}@Synchronized@Synchronizedallowsyoutoachievesomethingsimilartothesynchronizedkeyword,butlockingondifferentobjects.Thekeywordlocksonthis,whiletheannotationlocksonaspecialprivatefieldnamed$lock.Ifthisfielddoesnotexist,itwillbecreatedbyLombok.Thisisthedefaultbehavior,butyoucanalsospecifylockobjectsyourself.Whendealingwithstaticmethods,theannotationwilllockonastaticfieldnamed$LOCK.Please,considerthatjustlikesynchronized,theannotationcanonlybeusedonstaticandinstancemethods.WithLombokpublicclassSynchronizedDemo{
privatefinalObjectobjectToLock=newObject();
@Synchronized
publicstaticvoidsayHello(){
System.out.println("Hello!");
}
@Synchronized
publicintgetOne(){
return1;
}
@Synchronized("objectToLock")
publicvoidprintObject(){
System.out.println(objectToLock);
}
}JavaVanillapublicclassSynchronizedDemo{
privatestaticfinalObject$LOCK=newObject[0];
privatefinalObject$lock=newObject[0];
privatefinalObjectreadLock=newObject();
publicstaticvoidsayHello(){
synchronized($LOCK){
System.out.println("Hello");
}
}
publicintgetOne(){
synchronized($lock){
return1;
}
}
publicvoidprintObject(){
synchronized(readLock){
System.out.println(objectToLock);
}
}
}@SneakyThrows@SneakyThrowscanbeusedtosneakilythrowcheckedexceptionswithoutactuallydeclaringtheminyourmethod'sthrowsclause,asyounormallywould.So,thisannotationallowsyoutoavoidtherequiredtry-catchblockscompletelybyhandlingallthecheckedexceptionsquietly.Lombokwillnotignore,wrap,replace,ormodifythethrowncheckedexception.Onthecontrary,itwillmisleadthecompiler.Infact,attheJVM(JavaVirtualMachine)classfilelevel,allexceptionscanbethrownregardlessofthethrowsclauseofyourmethods,whichiswhythisworks.Thisannotationcanbedangerousandshouldbeusedcarefully.ThisiswhyyoushouldreadthispagefromtheLombokofficialdocumentationtolearnmoreaboutwhenandhowtouseit.@BuilderYoumayneedtodevelopabuilderobjectallowingyoutocreateobjectsbyfollowingastep-by-stepconstructionpattern,suchasAuthor.builder().id("1").name("Maria").surname("Williams").build();.Thisisparticularlyusefulwhendealingwithlargeclasseswithseveralfields.Insteadofusingaconstructorwithmanyparameters,youcanusethismorereadableapproach.
Byusingthe@Builderannotation,youletLombokgeneratethebuildersforyou.Byannotatingaclasswith@Builder,Lombokwillproduceaclassimplementingtheaforementionedbuilderpattern.Forexample,byannotatingtheAuthorclass,anAuthorBuilderclasswillbeautomaticallygenerated.Sincethebehaviorofyourbuildermaybecomplexorhighly-tailored,Lombokoffersmanyparameterstoachievethedesiredresult.Youcanfindoutthemallhere.@LogThemajorityofloggersrequireyoutosetupaloggerinstanceineveryclasswhereyouwanttolog.Thisdefinitelyinvolvesboilerplatecode.Byannotatingaclasswith@Log,Lombokwillautomaticallyaddastaticfinallogfield,initializedasrequiredbyyourlogginglibrary.ThisiswhyLombokprovidesdeveloperswithanannotationpereachofthemostpopularloggingframeworks.Youcanfindtheentirelisthere.TheLombokPluginThemostpopularandwidelyusedIDEscomewithanofficialLombokplugindesignedtohelpdevelopersuseLombok.Inparticular,itsupportsyoubyofferingshortcutstothemostcommonLombokannotation.Plus,itsuggeststoyoutheannotationsyoumayrequireorbelookingforbasedonwhereyouclicked.AtthetimeofwritingIntelliJIDEA,Eclipse,SpringToolSuite,(RedHat)JBossDeveloperStudio,MyEclipse,MicrosoftVisualStudioCode,andNetbeansareofficiallysupported.FollowthelinkrelatedtoyourIDEtogetsupportonhowtoinstallit.
VisittheLombokwebsiteforthecompletelistofallsupportedIDEs.IsUsingLombokARisk?YoumaybeconcernedaboutspreadingLombokannotationsthroughoutyourcodebase.Infact,whatwouldhappenifyoudecidedtoavoidusingit?Youmightbefindingyourselfstuck.Well,thisisnotarealproblembecauseLombokcomeswithadelomboktool.
Asstatedintheofficialdocumentation,althoughnotcoveringallpossibleIDEsandcases,itmakestheprocessoffreeingyourcodefromLombokeasier.Whatthistooldoesisauto-generateJavasourcecodecontainingthesamefeaturescontainedinthebytecodeLombokwouldhaveinjected.Thisway,yourLombokannotatedcodebasewillbesimplyreplacedwithastandard,non-LombokJavaone.
Asaresult,yourentireprojectwillnolongerdependonLombok.So,toanswertheoriginalquestion,no,notatall.UsingLombokdoesnotrepresentariskforthefutureoryourproject.ConclusionInthisarticle,welookedathowtouseProjectLombok,aJavalibrarythatautomaticallyplugsintoyoureditorandbuildstools,toavoidwritingboilerplate,boring,andrepetitivecodeJavaiswellknownfor.Asshown,thisisaneasywaytomakeyouamoreproductivedeveloperanddonotwasteyourtimeoncumbersomeactivities.Bystartingtotakeadvantageofitsmostrelevantannotations,youcanavoidwritingthousandoflinesofcodewithnorealvaluefromthebusinesslogicpointofviewofyourproject.Plus,thereisalwaysthepossibilitytomakeyourprojectnolongerdependonProjectLombokeasily.So,itusingitdoesnotrepresentariskoffindingyourselflockedin.Inconclusion,everyJavadevelopershoulduseProjectLombok,andexplainingeverythingyouneedtostartusingitiswhatthisarticlewasaimedat.Thanksforreading!Ihopethatyoufoundthisarticlehelpful.Feelfreetoreachouttomewithanyquestions,comments,orsuggestions.AntonelloZaniniSoftwareEngineerI'masoftwareengineer,butIprefertocallmyselfTechnologyBishop.Spreadingknowledgethroughwritingismymission.ViewProfileAntonelloZaniniSoftwareEngineerI'masoftwareengineer,butIprefertocallmyselfTechnologyBishop.Spreadingknowledgethroughwritingismymission.ViewProfileMorelikethisJavaFullStackJavawithReact,SpringBoot,andJHipsterSpringBootGetStartedwithCustomErrorHandlinginSpringBoot(Java)SpringBootSpringBootCaching101FollowtheconversationPoweredbytheAuth0Community.Signupnowtojointhediscussion.Communitylinkswillopeninanewwindow.