A Complete Guide to Lombok - Auth0

文章推薦指數: 80 %
投票人數:10人

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 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.



請為這篇文章評分?