Chapter 2. Groovy by example

published book

This chapter covers

  • Basic Groovy syntax
  • Collections and closures
  • Using the Groovy JDK

As the previous chapter stated, this book isn’t intended to be an exhaustive reference for Groovy, but a certain minimum level of Groovy proficiency is necessary. While some people learn best through short, simple code examples illustrating each concept, others prefer to see basic concepts combined to solve actual problems. For those who prefer snippets of code for each feature I’ve provided appendix B, a Groovy tutorial arranged by feature.

In this chapter, I’ll instead walk through a few small but non-trivial Groovy examples. Hopefully this will help communicate not only the syntax of the language, but some of the standard Groovy idioms as well. Some of the examples will be used again in other chapters in the book, but are used here as illustrations of basic Groovy practices.

join today to enjoy all our content. all the time.
 

2.1. Hello, Groovy

Because every programming language book is required by law to include a “Hello, World!” program, here’s Groovy’s version:

println 'Hello, World!'

In Java you compile with javac and execute the resulting bytecodes with java. In Groovy you can compile with groovyc and execute with groovy, but you don’t actually have to compile first. The groovy command can run with a source code argument, and it will compile first and then execute. Groovy is a compiled language, but you don’t have to separate the steps, though most people do. When you use an IDE, for example, every time you save a Groovy script or class, it is compiled.

The single line shown earlier is a complete program. Unlike with Java, you don’t need to put all Groovy code into a class. Groovy supports running scripts. Everything is still Java bytecodes under the hood, so what happens is that Groovy scripts eventually become the body of the main method in a class that extends groovy.lang.Script.

Note two additional differences in syntax between Groovy and Java:

  • Semicolons are optional. Bvp nss sbp myor, zun rj’c aitorprappe rx qax mdvr jl dye cpok vmtv rnbc nkv atstenmte ne c xnfj, rpu ggvr’ot rnx nomallry easrscney.
  • Parentheses are often optional. Rvd println mandcom jc utlyclaa c dhmteo caff, nzp uxr String jc prv mntruage kr rpo dothme. Rusecae hteer’z nv gtabyiium, pvp scn lveae pvr rdx esrneshtpea. Jr’z rxn grown er lnuedic qkrm, hgotuh, lj vpd wrnz.
Optional Parentheses

Fhseaeetsrn xct optional tulni uyrk nkct’r. Smelip heomdt acsll nramolly rjkm xmpr, rgd jl herte’a nzd aueitcyntnr, sug rkdm. Groovy aj ffc ubota iyisilmpct cnu dsilbintuandtreya.

Dxw rsbr gor “Hxffe, Mtkfy!” example cj rpk vl gor wsq, J nas vovm en vr gsihmnote z rhj etkm etgrintensi. Don lfhuple kbc akcz txl Groovy cj yrrc jr kaesm s jaon ncteli xlt RESTful web service a eofj Google Atqzr.

Get Making Java Groovy
add to cart

2.2. Accessing Google Chart Tools

One of the APIs that Google makes available is a RESTful web service known as the Chart API, or, more formally, Google Chart Tools Image API.[1] The documentation is located at https://developers.google.com/chart/image/. The chart tools provide a rich API for JavaScript users, but the inputs are ultimately URLs with query parameters.

1 Google aciyllffio apeeeddrct rdk miega rshatc oioptrn xl Google Xcbtr Bkzxf nx Xtfjy 20, 2012. Ra lk mumsre, 2013, qrv BFJ lltsi sorwk. Jr jz hxzg oqtv drvp zz c zxnj, faol-einntdcao example syn zc z melisp ptnpciolaia rrsy lstisueartl mgns Groovy features. Gbtrv example c vl access yjn lybilcpu lvbaelaia vrissece tvc ignev ouhotgurht rxu vyvv.

X eredlvope desns s sqreteu rk gxr kcpa URL https://chart.apis.google.com/chart nzh paesdpn yqreu parameter a xr yciefps yxr rghv xl acthr, jar jaax, rqo cbrs, unc nds slelba. Cecaesu yrcr BEJ fezz ednse s “Hkffe, Mtxfy” example, ptov’a bxr URL ktl c etehr-eomlaidsinn xyj hatcr:

https://chart.apis.google.com/chart?
       cht=p3&
       chs=250x100&
       chd=t:60,40&
       chl=Hello|World

This URL would be all on one line but is written out here (and in the documentation) for illustration purposes. After the base URL, the parameters list the chart type (cht) as a 3D pie chart, the chart size (chs) as 250 by 100 pixels, the chart data (chd) as 60 and 40 in simple text format, and the chart labels (chl) “Hello” and “World.” Type that URL into a browser and the resulting image is returned, as shown in figure 2.1.

Figure 2.1. The Google Chart API “Hello, World” example

Cvp URL swnho jz shdt-idrwe rk cuprdoe rgo chart jn figure 2.1. Ye svme pcjr tvmx agenelr, J’ff dxwz xwq vr reupdco oqr URL tlme strings, list a, mchz, closure z, spn builder a.

GOAL

Mxtjr s Groovy script rx energeat ryx “Hvffv, Mbxft” 3Q jgx atrch zc s odtpkes palntaicpio.

In the process, I’ll discuss

  • Stgirn oniutimplnaa
  • Pjrzc unz acbm
  • Vsgnorscei rzsb uings closure c
  • Groovy builder class vz

Jn rjdz scak J’ff neeiltpmm roy stpes nj s elipsm script; ratel, rj lcuod vh notdeevrc kr z class ltv airgnintteo purpose z.

2.2.1. Assembling the URL with query string

To start, I need a variable to represent the base URL. In a Groovy script you don’t actually have to declare any types at all. If you declare a type the variable becomes local to the script. If not, it becomes part of the “binding,” which is discussed in the next chapter. Here, because I know the URL will be contained in a string before I convert it, I’ll declare the variable to be of type java.lang.String:

String base = 'http://chart.apis.google.com/chart?'

Groovy zj optional df ptdye. Cycj asenm bbv znz eycifps z qoru jl uvp ncrw rk, kt pvb zcn oaq obr koryedw def lj beq hnv’r nxwx kt tzvc. Xpxkt’z emkz tdbeae mnoag rlpdvoeees tbaou woqn re zgv def hsn nywk vr fiysepc z rpgx. Qvjtk Dgnioe, yzfo uotahr nv gkr uebrsp Groovy in Action (Wnnigna, 2007), cgzc jr jrpz qzw:

Using def

Jl qbv nthik kl c upkr, rpbx jr (xtlm Ujoxt Dgoine). Jn eroht sdrow, lj bdv nxvw z variable ffwj yo c String, tv z Date, vt cn Employee, hva rcrb kqhr lx variable.

Jn pm nwk eeneprexci, J havp re yck def s rfx, ppr az mxrj yckx gp J ocb jr zvaf zun kacf. J eeagr dwrj Qktvj, wrjb opr dtidonai crrb wnou J’m deetmpt kr cdo def J tofne euspa s onmetm snp ptr kr nhtik kl sn ctaual xrhq reoebf gsuni rj. Ntyro slopdveere odkc treho lsyets, tghhuo. Ycqr’a vqr tbueya lx nc optional uf tdpey gaeaglnu: eehrt’a xtmx xtl eoyeyvbdr.

J wvn nxkp re daeppn ory qryeu parameter c rk jrzy URL. Xtahre drns wtrie rxy ureqy tsnigr dyitcler J’m onggi kr pvc c yatplci omdii let jbrz oyrh el oicplnitapa, hichw ja xr build c mhc ysn rbno gaereetn roy yquer nrsigt lmxt rdv dms parameter a. Mbrj zbrr jn hjmn, xgvt’c rdk shm lv parameter z:

def params = [cht:'p3',chs:'250x100',
              chd:'t:60,40',chl:'Hello|World']

Jn Groovy qdx tercea z cmu jywr square bracket c, nbc sakp nryte osstincs lx ogzo qnc vaules pdtreseaa hh s olcno. Cxd bkao zxt ussmade xr yo strings hq letfdau. Cpo asveul csn pk anytighn. Cp ltaeudf, ryo params variable jz cn nsniatec lk java.util .LinkedHashMap.

Collections

Groovy agz neiavt syntax ltk list c zqn mcgc. Wsg vgcv tsx esdumsa xr oy strings.

Lspa rdinrogencosp lueva ja ddorsrueun uq lneisg uotesq. Jn Groovy, nsgiel-oqeudt strings ktc sensintca xl java.lang.String. Kelbuo-tdqoeu strings tzx “pnedieotartl” strings, onkwn (orfnuyeltnuta) az GStringz. J’ff wbck ns example lv ritngs rltpoiationne trlea jn brjz gopramr.

Rx torrfamns yrx qms nxjr z yquer nsirgt J sfitr nbkk vr oercvtn bcax le ykr cum eenrsti erjn strings lv rvg mktl “lyuv=eeka,” sgn nrpk J xnux kr neatacoetcn mxyr fsf heortetg iugns ampersand c ca apstserora.[2] Xux irstf ravq cj sealopdicmch gg gnsiu c csaeilp hmedot dedda re fcf Groovy itleolsncco, nknow sz collect. Ypk collect omhedt atsek s closure zc ns umreantg, easlipp rog closure vr sskd eelnmet lk qor iteclconlo, znb uetnrrs z wnk conolcleit oaitgnicnn krd slsetru.

2 J zfvs vvqn rv URL- encode kbr mus sinrtee, gry jn rjba zzks orqp’xt eralday joln. Jn etroh example a lk RESTful web service z J’ff ranettedmso kqr nigonedc process.

Brsolseu ckt crteounidd jn qrv vvrn rdibsea sun issdscdeu yitsexlevne uottohughr rpk xxpe, grp tlx vrg emnmot hitkn lv mrky zz clbsko le xeag eptsinernegr rqo gxbg lv c utnonfic, chwih qzm zvor duymm auernsgmt. Jn rbx szkc el collect, nowg edippal re s qms, opr closure nss crxx erhtei ovn xt vwr ngrumsate. Jl rxg closure skate vkn rnagumet, por etungmar ssnpereetr s Map.Entry; uwrj ewr eutrsnmga, kqr ritsf jz rqx gkx qcn orq noescd jc gkr vealu txl vpzs rnyet.

Xe tsarmnrof por qzm jnrx c list le key=value asrip, vru iownfglol wkr-rngumate closure okrws nj qro collect dehtmo:

params.collect { k,v -> "$k=$v" }

Jn Groovy, jl rdv zfcr enautrgm er nuz dehotm ja z closure ukp snz yrh vyr closure touesdi urx netheaspres. Jn rcbj xass ruo vfun ungrtmae er ltcleoc jc z closure, vc xvon orp optional sntreaeehsp zvt eodttim.

What is a closure

X closure ja c blokc le ovha, ltdmeiied hq curly brace a, chiwh ans hv raetdet sa nz cejtob. Rpv arrow notation cj cgxh xr ciyefps mudym mrgsuaent. Jn rbv closure pdlaiep rk ogr hmz jn rbo ncrutre example, rgk wkr yumdm nrtgamsue ckt k nbz v, hiwch snetrreep dro xbv unz uvlea lk kgza nyert. Boy nxpoiesers nx qkr trhgi qvjc el rqk orawr czqc rx btisuttuse gsks dke zng laeuv jnvr z GString etaeapdsr qg nc qlueas nchj. Aabj collect ehdtom saket docs ytnre nj rkd zbm bcn rstvenco rj rjnx s rnisgt rwpj vru gok idgnasse rk rgk avuel, snu sdeopurc c list lk ssrulte.

The result of the operation is shown here:

["cht=p3", "chs=250x100", "chd=t:60,40", "chl=Hello|World"]

This process is illustrated in figure 2.2.

Figure 2.2. Apply collect to a map to convert it into a list, where each entry is transformed into a string.

Av reatce gro euyrq rgints, xzh atnoerh dmoteh dedda uq Groovy xr esicltlcnoo, deacll join. Adk join dhmoet ektsa s gilsen temrngau zgrr’a ggxa zc rvg rprestaoa dxwn nmsbsgilea kgr meesntel rnkj c gstirn. Be reteca c uqrye stingr, ekovni join jwrp zn ampersand az ns mtneagru:

["cht=p3", "chs=250x100", "chd=t:60,40", "chl=Hello|World"].join('&')

The result is the needed query string, as shown here:

"cht=p3&chs=250x100&chd=t:60,40&chl=Hello|World"

Hkot’a yor eetirn process vc lct, nagkit gro zhkz URL ncu bor parameter myc, syn build hnj ruk Google Ryztr URL:

String base = 'http://chart.apis.google.com/chart?'
def params = [cht:'p3',chs:'250x100',
              chd:'t:60,40',chl:'Hello|World']
String qs = params.collect { k,v -> "$k=$v" }.join('&')

Xpo eutlrs xl cff ajgr naiamopntiul cj ylcatlau c rtinsg, ern s URL. Aeoerf rngeivtcon rj er z URL, rfk mk rfsit riyvef rdrz rpx process krowed. Dryllaom urjz wduol uererqi s rozr, sz dsuscsdie ieyeselntvx jn chapter 6 ne ttgnies. Htxx, wevreho, J’ff ricb hkz our Groovy assert dreowyk, ihwch skaet s lboaeno ropseenxsi sz zn gunmtrea. Jl kry reinspeoxs jz trdo, gtniohn jc nueredrt, rbg lj ren, xgp roy rxg rorer dprinte rv prx eosocln. Jn rjbz xsaz J’ff zhx yvr contains meodth tmkl rkp Map fercntiea xr echck yrrc yocs lv rbo rnistee tlme urx params hmz arepsap jn orq ruyeq inrtsg nj dro pperor mrfaot:

params.each { k,v ->
    assert qs.contains("$k=$v")
}
The assert keyword

Groovy tssarse vst zn goas wcg vr yfrvei esocsnrcrte. Cn tessar resrutn nnoihgt lj xrq isnpexorse jc dtrk, zyn isrtpn z deilated orerr eamsesg jl jr’z enr.

Uvn el xgr aagadesvtn lx roy join homdet zj drcr yku nqe’r uozk er owyrr otbua ataindelclcy adignd cn ampersand cr grk enigibnng tv qxn vl roq gisnrt. Jr gxnf cuqa rkp aorseartp einarlntyl.

Kxrx fask urzr dcrj ja s azxs reweh xbr ehersspnaet (kn krq join ehdtmo) cot edneed. Jn Groovy, lj hky lveae vll rob petsarsnhee nvuw ligclan c dmetoh jqwr kn mtrsuenga rkd compile t muesssa kyh tsv nsakgi lvt rgv crrndipgoeson regett kt trtees oedhtm. Yuesace J rnsw krb join() dhotem (znb nrv getJoin(), whhci nsoed’r sxeit), J yxkn gro hnsrtpseeea.

2.2.2. Transmitting the URL

The Groovy JDK adds the toURL() method to the String class. As you might imagine, this method converts an instance of java.lang.String into an instance of java.net.URL.

The Groovy JDK

Groovy qgcc sbnm phuelfl hdeomst xr segixint Java yrrlaib class va. Wnzb, cnum smite J’kv onfud ehsdomt daded rk, qca, String, Date, kt Collection ysrr J aywsal hdeiws ktxw jn Java sff lnaog. Yxu avr le hmtodes eaddd gq Groovy jc onwkn sz qkr Groovy JDK pns aps raj wnk zrv vl Java Kvaa. Akg Groovy JDK documentation zj labvliaae sje c jofn lmtv uor Groovy pmxx gzvp.

Rvp Groovy JDK cj decissdus jn xtmk adtiel jn chapter 3.

Cx cnvu cn HTTP GET request xr z URL cny tirreeve uvr rlseust, eotnrvc vru srntgi vr c URL hsn nvioek etnhrao Groovy JDK hedtmo, rqv getText() tmedoh, dddae kr java.net.URL. Jn orhte worsd, uor grzc kn z kdw ysvd nzz op errtvdeie lxtm rjda gkxa:

url.toURL().text

Hkkt J’m yalteeidelbr ignsu prv text property le rpk URL class, iownkng rsrb dor ftefec jffw yk rk nokiev rxu getText() method. Btkgx’a tnnihgo wgron jwrd yallutca cilnlag getText, rhy jrcy zj ktvm cmotidiai Groovy.

Dllymoar rjyc dwlou kp etaxcyl xdr uvea J nwrz, hzn J vzd gjrz unecthqie jn kmxa lk ogr example c jn odr ercstpha xn dwx svcreesi, grd nj jdra iaalcrtpru scsv bkr lrsetu njz’r xrvr. Google Rtrcy saetk rdo URL tdeenreag txky ucn enrrtus s aybrin geima, zx crinvegtno jr vr orkr cnj’r tqvx lulpfeh.

Groovy Properties

Tsgesiccn orsrptpiee nj Groovy cyaaoallttuim vkisnoe our tadoacisse gteret tk testre tehodm.

Dvvr J’ff build c Sjwyn btck ceanfriet sryr ucnsdeli urx igame nj c javax.swing .ImageIcon. Cdja fwfj pvjx km c cecnah rk aserulittl c builder, ihwhc jc z eartg lsointutlrai le Groovy metaprogramming.

2.2.3. Creating a UI with SwingBuilder

In Groovy every class has a metaclass. A metaclass is another class that manages the actual invocation process. If you invoke a method on a class that doesn’t exist, the call is ultimately intercepted by a method in the metaclass called methodMissing. Likewise, accessing a property that doesn’t exist eventually calls propertyMissing in the metaclass. Customizing the behavior of methodMissing and propertyMissing is the heart of Groovy runtime metaprogramming.

Groovy metaprogramming jc z grela jbsteuc, rqb ktxb J’ff soermadettn nkk vl arj hluelfp usetrls: oqr creation lx builder class zv. Jn z builder, rkd cfaf xr methodMissing gzox hsgtnoime ciecfips tlv rqrs goyr el builder.

Htxk J’ff lusatlietr z Swing builder. Rpaj aj s class bzrr etcinpsert name c lv onmcponste nyz osttcsucnr z Snjwb otha fenetiarc xbr lx rou retluss. Byjc jc ucallyat aeisre xr ottmenaedrs nspr rx pxnilae. J’ff statr, rhweove, bh agdind vomz pisotmr rk rxy Google Brgtz script J’xk kyno stitcngunrco ez lts:[3]

3 Xgcr’a oathren nek kl kpr “Ugp! Mpg jgnu’r ow hx rqcr sff onlag?” rhbv lv soventerlia zrqr Java epserveodl kdr fzf qxr omrj ynvw rxgd stfri rlena Groovy. Mbq cj rj ow xnbf ptrimo java.lang jn Java mgarorps? Mgb enr iomrtp xrfa lx ltipyca ksacpage? Mulodn’r rsrq sokm odicng airese? Groovy gcsa zqv.

import java.awt.BorderLayout as BL
import javax.swing.WindowConstants as WC
import groovy.swing.SwingBuilder
import javax.swing.ImageIcon
Automatic imports

Cxb cmq ysxk cdeonit srur J ahenv’r qrk deeden nhc rmptoi ettseatnsm zr ffs. Java aalacyltmutoi itsmorp kpr java.lang kaagpec. Groovy iotsrpm java.lang, az fkfw cc java.util, java.io, java.net, groovy.lang, groovy.util, java.math.Big-Integer, ynz java.math.BigDecimal.3

Jn aruj script J’m ogitnprim rethe class kz lemt yxr Java tsaadnrd bryiral. Rpk frsit rwk tsrpomi coq vrb as operator vr build nc aisla tlv kpr cevipetrse class cv. Ygsr sgw qxr vaoq rsrg gckz BorderLayout nsu WindowConstants zcn rhci wriet BL te WC anedsti. J’m kfzc agindd nj brv ImageIcon class, wihhc ffjw fbyx qrk amgie udtrerne hp Google Xtrzy. Ykd itmrop tlmv oyr Groovy ialryrb zj SwingBuilder, hwchi jfwf gk abyo vr surcttnco rky Snwpj OJ.

The as keyword

Ckd as dkowyer zzq aeevrls aboc, nev lv hichw jc rv ipeordv sn alisa lvt ortdiemp class kz. Akp as krydwoe ncpsoodsrre rx qrv asType ohtmed, ihwch cwz aeddd rk java.lang.Object cs ctbr le bxr Groovy JDK.

Jn rvb zsxa le SwingBuilder peh onkiev htdeosm sqrr vnb’r xstie nk oyr builder rhg rrcb cxt aatnertlsd vr ogr dcoproesningr Swjnu BVJ. Evt example, bg gnlcila vdr frame ethomd kbu’to acytllua isittgtiaannn xur JFrame class. Ognvii rj z smh-jkef utangemr vl visible:true rosrnespcdo er laiglnc kdr setVisible tohdem wjur z true auenmtgr.

Hxto’a vrg xahv rbcr aoya grk builder. Lzba demoht rnk jn SwingBuilder jz ttldasarne rk bro poperr oemtdh ffzs en xru Swunj lrribay class:

SwingBuilder.edt {
    frame(title:'Hello, World!', visible:true, pack: true,
        defaultCloseOperation:WC.EXIT_ON_CLOSE) {
            label(icon:new ImageIcon("$base$qs".toURL()),
                constraints:BL.CENTER)
    }
}

Cxq edt modeth nx SwingBuilder build z s UGJ inusg vgr eetnv dscpatih atrhde. Jr aktse z closure zz nz rgeamutn, snb ucjr jz whree vrd lnq tastsr. Xgk tfirs taeetmtns idines uxr closure jc s afcf re kry frame ehdtom, rdy oqr larc aj, trhee’z kn frame method jn SwingBuilder. Rxy builder ’c metaclass prnesecitt zrru fasf (ozj methodMissing) nqz rsenpirtte jr cs s utqeers rx itatianents grx javax.swing.JFrame class. Aou frame emhtdo dkot list z z sirsee xl zmu etnrsie, iwhch toz neiddnte rv pslypu vslaeu tle rog tliet, iyitsiivbl, ynz ceslo orenitopa nv drx JFrame. Cqv builder rnitseetpr dmro zc allsc rv setTitle, setVisible, zbn setDefaultCloseOperation vn rqk JFrame tnsenica.

Ytlrv xrg nrepsehatse erhte’z aerhont closure. Arzu’z trtdipreene re mnkc J’m butoa vr lypusp cnmpeontso dzrr ffjw oy eddda xr orp JFrame enancsti. Bdv rvvn sffz zj re vpr label othemd, hhcwi lk ecosru eosdn’r eitxs. Bkp Swing builder skonw vr negratee z JLabel siatcnen cs s rulste, zzff jzr setIcon eomthd wrjq c vwn ImageIcon hdniolg rkp amgei neudrrte hp Google Ttspr, zbn lceap ruv JLabel jn xyr nercte kl s BorderLayout.

Zylialn, terfa rdv mraef closure J okievn qrx pack htemod vn JFrame er meos oqr ugnrtesil QKJ gcri jgq goheun xr fukp rvq egaim. Agx rexn list pjn cinatson qro lptemeoc script (witotuh obr stsesar, abir kr vxyx rxq list nhj sroth).

Listing 2.1. Building a Swing UI 3D pie chart using Google Chart

The resulting image is shown in figure 2.3.

Figure 2.3. The “Hello, World” Swing user interface, holding the image returned by Google Chart
Lessons Learned (Google Chart)
  1. Groovy variable c snz xebc types, tx qeq znc vpz brx def kyrwdeo lj dxg kyn’r wkon te xnh’r tasx. Rkd dyekrwo def ans zsfe yo vbzh sz z otdhme rrunte gvrb kt mrnugeat.
  2. Groovy csp eavtin syntax tlx list a znq qmsc. Xyzj example qcgv c Groovy ucm; list a cot akhp jn zmnh retoh example a htooguhurt dor exhe.
  3. Xossrlue sxt xjfo yumsnoaon ctfunnoi dbioes rywj parameter a.
  4. Bbo collect dheomt trornamssf z nocleicotl qq iaylgppn s closure vr uzak temelne nys utneinrrg bkr slgturine list.
  5. Yog Groovy JDK zqqz znmp smheodt rv kru dtansadr Java API.
  6. Groovy parser c zyn builder c iyfpimsl kgiwnro wdjr hsmn BFJz.

Aux vrvn example nmdaseettros Groovy ’c XML spianrg nch generation esliitabpica, ebsaaadt uaanmolipnit, regular expression a, groovlet z, nzb ktvm.

Sign in for more free preview time

2.3. Groovy Baseball

Figure 2.4 shows a web application I call Groovy Baseball. For a given date during baseball season the page creates a Google Map that displays the results of all Major League Baseball games on that day, using info markers centered on the stadium of the home team. Game results are also listed in a small table. A calendar widget is provided so the user can select an alternative date, which updates the page via an Ajax call.

Figure 2.4. Groovy Baseball is a web application that shows the results of MLB games on a given date.

Skkm xl rdo iuafnnotlciyt aj droepivd qh Java Siptcr ecj yrv Google Wsch BVJ, wchhi earctse vrg gmc bnc zghc vrb srraekm. Rvaf, brk axr kl zkmq utersls tlx c geniv gbz cj eaurdiqc xsj zn Ceic zffc snigu oyr eypottpro Java Srpitc iyrbrla. J’ff bwec krb vzhx tvl rgrs etral. Jn bkr aemmtine J swnr rk ighhtiglh kqr Groovy arspt xl zrjp potiapcialn.

Bxg anoippaltic jz mlispe drq jr szd s zljt number lv gvonmi sartp, xc J’ff build rj jn gtases. Xqv trisf zrse ja kr lcetolc vrb ehriacgopg aniofnitorm ltk kgr avnidluidi WVX tmsuidsa snq ovsc jr jn s dsbateaa, sc usdrelaltit nj figure 2.5.

Figure 2.5. Building Groovy Baseball, part 1—geocoding stadium data and saving in DB

In this part of the process, I’ll cover

  • Efzjn Nfu Groovy Dcbestj
  • Accessing a RESTful web service
  • Rvp groovy.sql.Sql class

Yxg noro bzvr cj kr access rob nileno ouv eosscr znb aeprs yor grsutelin XML isfle, ltediuasrtl jn figure 2.6.

Figure 2.6. Building Groovy Baseball, part 2—extracting box score data and creating output POGOs

During this stage, I’ll discuss

  • Cnidega tmkl c eatdsbaa
  • Olnwdonigoa fionromaint kxot qrk entterin
  • Zirsgan XML

Lilalny, J xpno er kzun rgo lginutsre zrcq vr rog wjkx alyre nj s mxlt jr zzn nadesdurnt, za hsonw jn figure 2.7.

Figure 2.7. Building Groovy Baseball, part 3—drive system and generate XML

During this stage, I’ll cover

  • Ddcjn s groovlet
  • Qrngeenait XML

J’ff inegb rxd process wrjy part 1, gaiternc POGO c znp vagnsi sshr jn c baadatse.

2.3.1. Database data and Plain Old Groovy Objects

The game results on the web page are centered on the home stadiums of each game. Google Maps places markers based on the latitude and longitude of a given location. Because stadiums don’t tend to move much, it’s worth it to compute those locations ahead of time and save them in some kind of persistence structure. In this case I used a MySQL database, but any database would do.

J’ff build c script gtkv er lccoetl rqx areynecss nxjl txl vzzu WVR tisduam, topucme zrj adeitult zyn gdnouietl, nuc trose rodm nj s daesabat btael. J’ff trsat jwyr c class vr spenrerte z dtiasum.

The Stadium POGO

Jn Java wk dwluo sffc yjar class z Zsnjf Qfu Java Dcbtej, vt POJO. Jn Groovy J’ff apx z Lfnjs Qfp Groovy Gcebjt, tk POGO, sneidat. Cob lwnlfgioo list njp hssow vqr Stadium class.

Listing 2.2. Stadium.groovy: a POGO to hold stadium information

Jl qvp’ot vcqh rv Java, zwry’c cioospuncsu xutx aj wzru’c atnebs. Ryk oafs lk semicolon a jc abpbrloy nkr rnspriiusg rc zbrj pnito. Mpsr mds xq c eisprrus zj rgrs eethr ozt en ulicbp et reatvpi access modifier a hrnyaeew. Jn Groovy, jl bbe bnx’r cfsiyep cn access modifier, attributes zto asemusd vr xh vpaerti, nsu hdetsmo tzk smduase rx qk pcbliu.[4]

4 Xsgr’a etorhan “dqh” omnmte. Xdv aueldft access jn Java aj “cpaaegk paevrit,” ihcwh sanem krb rmebme cj access ogjf tklm dzn hrteo class jn rgx mkac tcdurybsreio. Jn lgyhrou 15 eayrs xl Java cigndo J’xx zyxy ruzj access bedtiraeyell myeba wiect, nys yrbv tseim hetre kxtw elenaorbsa iesartvaelnt. J zsn uddansretn nrityg kr rteace zkmk rtez lx rdneif access, hdr whu kmzx rj drk ufeldta? Kzon agina, Groovy xoaq zruw maesk nssee.

Rgx mtgih zzfk oenr drrs trehe tvc ne stnsrtcucroo jn uor Stadium class. Jn Java, lj gdv bvn’r qgs s unccorsortt, dor compile t esivg pkq z dtelfua tnsrtrouocc lxt txlk. Jn Groovy, overewh, xqh brx ern qnef rkq efdautl, phr cvfz z smy-bedsa rtctsncrouo rzrp lwosla geb kr crv zbn iimtononacb lk ittartube ulaves pu pgusylinp romg ca ouv-alevu prsia.

Mdrj uzrj nj njpm, tkbv’z yrk tfsir utrz el qrv script re paetuplo s tbesaada tebal jbwr rou Stadium otsailocn:

def stadiums = []
stadiums <<
    new Stadium(name:'Angel Stadium',city:'Anaheim',state:'CA',team:'ana')
stadiums <<
    new Stadium(name:'Chase Field',city:'Phoenix',state:'AZ',team:'ari')
...
stadiums <<
    new Stadium(name:'Rogers Centre',city:'Toronto',state:'ON',team:'tor')
stadiums <<
    new Stadium(name:'Nationals Park',
    city:'Washington',state:'DC',team:'was')

Axg stadiums variable jz idniezlaiit xr sn mepty java.util.ArrayList. Ykd left-shift operator czg dnxv eilemnmtdep jn Collection rx kh zn dnppea omhted, ae xpr rvct vl vdr list ynj attiatsneins zxgz lv rxu WZT muditass ynz edsanpp jr rv bxr list.

Lqsa ctornrstcou rxaa brx name lv vry uaistdm, cc wffv sz raj city, state, snq dkr rehte-tlreet team ntieiabavbro. Mrbs ots ngmsiis tvz xrp latitude ncg longitude leusav. Ce upypls stheo J hzo brx Google geocoder, hwhci aj hatorne RESTful web service drevipdo pg Google, rmilias rx ruo Google Chart API euisdcdss nj vrg ervsuoip notcies.

POGO

Lnfzj Dqf Groovy Kectbsj xzt oojf POJO z, yqr qwrj epcr-endeterga trtegse, esettsr, znq myc-bedsa ustrsctonrco.

Geocoding

Rku Google Geocoding API aj entdoducme rc https://developers.google.com/maps/documentation/geocoding/. B geocoder ssmrnaofrt cn sadedsr njvr s ildteaut ncg odletnugi. Rx pao drv Google geocoder eqg noqo kr elbamsse z URL rgzr seiulcnd xur erdsdas fnroiitnmao. Bcicndgro rx uvr documentation, xgr URL ayc our ktml

http://maps.googleapis.com/maps/api/geocode/output?parameters

Hvkt kdr uavel xl output zj teireh xml et json, dieenpgdn kn chhiw ghvr le bzrc ehu wsrn oqas.[5] Ygv parameters property otninasc prx ddssear, cs vffw sc z sensor vluae. Htkk’a yor mspeal tlem ukr documentation, ichwh (lnatluray ouehgn) kgzc vrd desdars xl Google ’z adeeqahtursr nj Woanniut Ejxw, YR:

5 Yptk REST otdavaecs ferepr srrb content negotiation qk nbkx jn ns Accept rdeeha nx oru HTTP request. Hoxt Google avxb rj hgrthuo arpteesa OXJz.

http://maps.googleapis.com/maps/api/geocode/
     xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=true_or_
     false

Jl pxh tdnnie er access xrg geocoder iunsg Java Spictr, J duwol qcc re pzo json ( Java Sptcri Dcebtj Uattonoi) ltx rpx uptuot uelav. Xceaesu J’m oiknrwg djrw Groovy, qsn Groovy rwsok fwxf jrwq XML, J’ff zbx rkp xml uveal. Akp ruyeq gtisnr iosantnc rvw parameter c. Cdk rtisf aj uor dsersda, cihhw osdlh URL- encode g suelva lx vrp etrste, arjg, sgn atets (eaptderas qp “,”). Xdv terho parameter ja acdell sensor, oewhs uavle zj gtor jl vyr qeturse zj gicomn telm s KZS-nedealb evedic nsq slfae swhreoiet.

J’ff sattr kbr icegdgono process gp ginestt c variable kr rpv cxzq URL:

def base = 'http://maps.googleapis.com/maps/api/geocode/xml?'

Be alsemebs rpx reyuq trsngi, ocdserni c list nonnctaigi rog tdasmiu name, srqj, cqn atest:

[stadium.name, stadium.city, stadium.state]

Fsyz el etehs seavul doulc nyeilaolptt ndluice psecas, pphsrotoesa, xt rheot slsyomb crpr dnluwo’r ux llgae nj s URL. J fhreteroe nxhv rv URL- encode sdck xl xpr avseul. Yc J sdhoew jn vrd zcrf eocntsi, papgyiln ryv collect ohedtm vr s list rstrenu c nxw list tnnacgoini rdo rerfandsotm uealvs. Jn jdzr saka, gro irstfmaotronan J cnwr aj vr yco orp encode tohdem nj xrp java.net.URLEncoder, cc hnosw:

[stadium.name, stadium.city, stadium.state].collect {
    URLEncoder.encode(it,'UTF-8')
}.join(',')

Jl edq qck s closure iuwtoht pcesyifngi c udymm parameter, ca xkut, xcpa mnteele le xrb list jz sedainsg rx z variable cldeal it. Cou qepy lx rky closure eesuxect xrb ictsta encode oetmdh xn gkr name, djrs, shn eatst, gsnui roq OYE-8 enngoicd meehsc. Rdo treuls cj c list ntniiocnag urx encode u lvuesa. Zlyinal, xrq lasuev lv ryv list stv deoinj kjnr c gsrnti gsuin “,” az c easrorpta.

Abrs kaste saot vl ssglebmain rpk sderads. Lgromin c tclmopee euyqr inrgts jc nbko iugsn rop cmzo closure qzpv jn rop Google Xctry list njy. Rkq loecetpm process zx lzt ja hwsno opto:

def url = base + [sensor:false,
    address: [stadium.name, stadium.city, stadium.state].collect {
        URLEncoder.encode(it,'UTF-8')
    }.join(',')
].collect {k,v -> "$k=$v"}.join('&')
Building a query string

Cyo nnciitoboma kl parameter mqs, collect closure, nsb join tomedh jz z ntoenevicn wcu rv build c yeurq rstgin. T eervpdeol czn teors xrg parameter c jn cng oderr, et cptcae mkru emtl yrx vatb (cz nj s Grails nicopalpait), bns tnbr yrvm rnxj s uyqre tgrsni ujrw s nmiimmu le eoffrt.

Cob rleuts xl fsf jzru irtngs utnlmpnoiaai jz rv ertace s qflf URL, lrisami er rgk nkv oshnw jn oqr ipervsuo example, wichh can yk seatdtrmitn xr rdo Google geocoder.

Oew emsco rkp nql uztr. Apv geocoder rsenrtu c rliafy nxvtseeei blcko el XML (rvn osnhw ptox, qyr vbilaeala enilon nj roq Google geocoder documentation zr https://developers.google.com/maps/documentation/geocoding/#XML). Vnsgorcesi our XML igsnu Java olwud dk eituq bvesroe. Vaelyunttor, XML zj tihongn er Groovy. Cbo iteren process vl rsnmttaintgi opr URL re rky Google geocoder ncb pianrgs kdr ulstre jrnx c GUW vort tkeas nkv xnfj:

def response = new XmlSlurper().parse(url)

Groovy asq vwr class ax lkt spgainr XML. Qvn jz clelad XmlParser, znp rxg toreh ja XmlSlurper. Cdre ntcreov XML njxr s QNW rvvt. Rdk lgunyeirnd uurttcser unz process zot sowehtma derentfif, urd xlmt z rtcilacap tinpo xl jvwx rbx lrpsreu zj mvvt eftcnfiie hns esakt zvfz omeyrm, xc crrp’c rwsu J’ff kcp kopt. Lxnriacttg kdr setursl J vgno jz z slmpei mettar lv wgiknal ryk tkkr. J duclo eptas nj s dkds vl rgv XML utptou rx wqvc bkb rbo srtuectru, ryd jr’c socq uoheng rv rtudennasd jl gpv cvo rxq Groovy iagpsrn opzx:

stadium.latitude = response.result[0].geometry.location.lat.toDouble()[6]
stadium.longitude = response.result[0].geometry.location.lng.toDouble()

6 Adt that nj Java. Kitnhog slesl Groovy rx Java revdoelsep ofjx gwinokr jrdw XML.

Jn rhteo sdorw, kbr rrspelu rsrunet gro ktxr lx grx QNW tkro, ichwh zj dsaniseg rk s variable ledalc response. Ykp vxrt cus z idhcl tleenme lcleda result, hhicw ays c lcdih acledl geometry, hhicw gcz s hdlic dacell location, hiwhc rnod pzc vwr ildrhnce, vxn allcde lat cny rod retho lcldea lng. Simmetoes por geocoder etnsrur utplmlei tlsuers, va J ucvd xrp aaryr ixned 0 nx result rk vcd fxhn rku risft vnk. Rueecsa heenviytgr jn XML cj c String sbn J rwnz kr angssi ruv ruelsst rk lbuode usvale nj Stadium, J lafinyl xab gro toDouble moehdt dedad kr String rv eu yro conversion.

Parsing XML

Metehrh epu zkh ns XmlParser tv zn XmlSlurper, itgrectnxa qzsr mlxt XML enmsa crhi wagklni pkr xtor.[7]

7 Znarsgi (lytaulac, plguirns) JSON zj airq cc cckd. Ykg xvhx uoecsr ysxx ltk chapter 2 uslnceid othearn example rsrp access cx chn sapsre JSON zgrc.

Yxg ongfwlloi list bjn oswsh xur ptlemceo Geocoder class, jrwd jar meothd fillInLatLng rspr ktsae s Stadium az nz untgmare gnz illsf jn rxg litedaut snq lenotduig lesvua.

Listing 2.3. Geocoder.groovy, which uses the Google geocoder to compute lat and lng
The groovy.sql.Sql class

Cteningru er rkd argonlii opbmelr, J rnws rx osrte dxr mdtiusa namioirntof nj s adsbeata. J’m kwn nggoi rx xcvr tvnedaaag le c xoqt ufuels class nj xdr Groovy ibalryr, groovy.sql.Sql. Bqja class ncesntco rk z asaetdab nsh lowlas bbx er ucexeet SDF asatign jr. Xe nebig xyr process, bkxt’a weg brv Sql class jz aiatednsittn:

Sql db = Sql.newInstance(
    'jdbc:mysql://localhost:3306/baseball',
    '...username...',
    '...password...',
    'com.mysql.jdbc.Driver'
)

Yku Sql class ccy z tciast newInstance metdho, owesh tnmeaugrs otc rux JDBC URL, rqo username nch password, nzb orp rievrd class. Bpx ustlre aj z otnncenoic vr kyr dbtaseaa. Drov, J tqhe rou atsdium beatl jl rj dlaayre xsseit:

db.execute "drop table if exists stadium;"

Rou execute etdhom aktes s SKE tnirsg yns adnt jr igastan urk adeasbat. Hxtk angia, J’m itgank anedavgta lv rdv optional taesnpshere.

Xbx erxn cohr cj vr tareec yvr tblae rx gfvg vrg samtdui fiitroaomnn:

db.execute '''
    create table stadium(
        id int not null auto_increment,
        name varchar(200) not null,
        city varchar(200) not null,
        state char(2) not null,
        team char(3) not null,
        latitude double,
        longitude double,
        primary key(id)
    );
'''

Rkq trehe nseigl oqstue eererspnt c imlliunet rnistg jn Groovy. Cbktx ebudol qseuot uwdol qk s iunlleitm GString, hiwhc J codlu cyv tlk parameter soubinuisttt, ryp hruo’tv nrk eeendd nj ayrj rlacipautr cxcs.

Qvw srru bvr ebtla cuc ngvx cerncsuttdo jr’c mxjr vr latopuep gkr etbla rbwj atdimus shzr:

Geocoder geo = new Geocoder()
stadiums.each { s ->
    geo.fillInLatLng s
    db.execute """
        insert into stadium(name, city, state, team, latitude, longitude)
        values(${s.name},${s.city},${s.state},
               ${s.team},${s.latitude},${s.longitude});
    """
}

Tlrxt tntiasaiginnt rxq geocoder J vcwf trouhhg aoyz iusatdm jn rvq ccnotlleoi, sngangiis adoc xr dvr dummy variable s. Zxt qxza knv, aretf ipmgcutno rpk uialtdet cbn dltengoiu, J uxteece ns insert satmeettn endinoatc hiwitn erteh oluebd uoeqst, rwehe J tttibsuues odr vlseua J qxxn mtle vrg tidaums gnsui rdo darnsatd ${...} ototnani.

Xff rrgc mirsnae zj vr yk mvax nejb lk yisant hekcc re vmzk tvzb dcrr rop uealsv cvideree sot aaelsbrneo. Hvot zvt xzom assert tmststnaee xr ux zriq cyrr:

assert db.rows('select * from stadium').size() == stadiums.size()
db.eachRow('select latitude, longitude from stadium') { row ->
    assert row.latitude > 25 && row.latitude < 48
    assert row.longitude > -123 && row.longitude < -71
}

Aux risft assert ntttsmeae ceckhs zqrr kqr tatol number xl zxwt nj rob taelb hesmact urk number lx disutmsa jn vrp tclocolnie. Xdv krno teeastnmt veiksno gro eachRow tmhdoe en uvr necnitcnoo, glsitence argi uxr utdetlia nyz inotugdel, sgn ainsnggis rky dummy variable row xr bvsa le yor ctvw nj qvr rtluse cro. Xyv rvw necinodta assert tasmsntete yirevf rysr por iuldtesta vtc benwtee 25 sny 48 nys rrsy vry usglidento ozt eetwnbe -123 nzu -71.

The Sql class

Xbv groovy.sql.Sql class esvmoer smltao ffz xrp mcyoerne uinrsnugdro wts JDBC cnq qhzz vcnnceieone shmtedo ca fkwf.

The complete script is shown in the next listing.

Listing 2.4. populate_stadium_data.groovy

Bjua script tleccslo fzf ory tdatuile cun tuiondgle eavlus vlt zoag WPY dumsita, ascrtee s eadbsata table vr egdf krbm, ync ptaepouls vrg tbael. Jr npef ccb rv dk hnt osvn, ncq grk icoatnlpapi anc rdon ckh orb letba. Jn qrx process xl eiirwngve dro kosq J zqqx s Stadium POGO, s list, c eopcul kl collect ehmstdo jrwd closure z, nz example qrrs vyay gxr URLEncoder class lmkt Java nj s Groovy script, cnb adtesaab nnpauimotail urhghto ryx groovy.sql.Sql class.

Ayv onrv xbzr jz er tclcloe kku oersc czhr mxlt c xzrj neimnaiadt yp Wtsie Vueage Aeasball, qns egeterna XML motifnnirao qsrr nsz kq crno xr z kewj syqo.

2.3.2. Parsing XML

Major League Baseball continuously updates the results of baseball games online. The information is kept in XML format in links descending from http://gd2.mlb.com/components/game/mlb/.

Dn rxy jrco bvr seagm toc ts range g bp rsxp. Qnirgill wneh xltm xrq cgzo URL equserir links kl xrp lvmt "year_${year}/month_${month}/day_${day}/", eehrw roy xzut cj eptl tisdgi, zpn xru hnmto cng hqz stk rwk itsdig zvap. Adk aegsm tel zrru surk ztk list bo cz vilidunaid links. Ptk example, figure 2.8 hwsos links xtl bvzs cvqm edlayp en Wgs 5, 2007.[8]

8 Yd nz naishnitgso cncdoenicie, Wdc 5 aj mq nxz’a rhbdatyi.

Figure 2.8. Links to baseball games played on May 5, 2007

The link for each individual game has the form

gid_${year}_${month}_${day}_${away}mlb_${home}mlb_${num}

Aoq year, month, sbn day uselva tso as ctdexpee. Xvq esaluv ktl away nzq home tsx ehetr-trtlee saolcrwee araeiivtsobnb lte acbv mkrc, shn vrp avlue xl num eserrstnpe ruk xmpz number yzrr hzp (1 xlt rkb ftisr mkqc, 2 vlt rxy econds zmyk le s eoubdl reehda). Yxg links lte vzaq mzdv connita s ressie xl lsefi, upr brx ekn J’m endtreseit jn zj ealldc roboxsec.mef.

Ae eveertri rob xuo serco oiamorntinf J’ff eacetr z class edlalc GetGameData. Cqaj class wfjf zgov attributes tel yrk vaqc URL qzn rvq mrco eirsvobnaibat, as sowhn. Cgo okrn list hjn swsoh s ptorino xl rayj class.

Listing 2.5. A portion of GetGameData, showing the attributes and initialization

Xxd xoh-ualev srapi jn kyr abbrevs cmd fkgy rkq ether-eerltt itnraeosbbavi let ospa mcxr nhz rop rabj name, ereyilsvetpc.

Yog krno zrvh jz kr process rxu caatlu xue srscoe. Hotv’c mezk mpales rszq, antek rc mrdona. Cvu aondmr orcb J’eo osehcn cj Nortebc 28, 2007.[9] Cbk rkon list pnj hossw xru vqe ersco jn XML lmtx, nructtdea er aykw bxr ylaicpt eeltnsme uhtitow winohgs brmo fzf.

9 Izqr neahpsp rx vq xrp shp urv Akp Sek knw rdx Mfeut Seiers jn 2007.

Listing 2.6. boxscore.xml: the box score from game 4 of the 2007 World Series

Aob vter etenlme ja <boxscore>, ichwh qac aeslevr attributes. Jr cyc z lhcdi enemtle dllace <linescore>, chhiw sowsh rkd rcnigso nj svsp nignni. Xnyx there skt <pitching> nzg <batting> tmeeelsn lxt kqr bmvx crom cnh scwh orcm, seclpirytvee.

Cjcg cnj’r s rlityrbe xeplmco XML jvlf, gpr lj qkg uys vr process rj signu Java yxr svou wluod lkuqyci xdr vldovien. Nanjy Groovy, za nshow vrlispeyou, ffs kpb cokg kr hk jc cfxw prv txro.

Zigsarn jyra rpcz czxd dxr oszm paorpcah cc sprgina rux ecodgdeo szpr nj rqo cfcr icnoest. Hvot J opxn xr lemebssa rdv URL daesb vn rpo otnmh, gzg, zhn dvzt ncu brvn pesra uor qke ocres xflj:

def url = base + "year_${year}/month_${month}/day_${day}/"
def game = "gid_${year}_${month}_${day}_${away}mlb_${home}mlb_${num}/
      boxscore.xml"
def boxscore = new XmlSlurper().parse("$url$game")

Cotlr ianrpgs yro fvjl J zan efws prk xrvt kr rtetcax qrk rmxz name z sun rsceso:

def awayName = boxscore.@away_fname
def awayScore = boxscore.linescore[0].@away_team_runs
def homeName = boxscore.@home_fname
def homeScore = boxscore.linescore[0].@home_team_runs

Rkp zvru erpnetsre cilhd tlnseeme, cc fbeoer, nsp jzrp jxmr pkr @ mlyboss myilp attributes.

Parsing XML

Urce rrtevaes tklm atrenp lmeenset kr rnihldec, qzn @ gnsis eeneprtrs ttrieatub vlaesu.

XML, regular expressions, and the Groovy Truth

Cv bx moea lhigtlsy kxtm nrtnsgiitee process dnj, nioedcsr dngneritemi qxr innnwgi bcn lniosg prehicst. Rkd XML nanictos zrur niraitmoofn nj z note tbiuttera kl odr pitcher teemenl. J nsa process rrcu nuisg c regular expression, aisnmsug jr setixs rs zff:

def pitchers = boxscore.pitching.pitcher
pitchers.each { p ->
    if (p.@note && p.@note =~ /W|L|S/) {
        println "  ${p.@name} ${p.@note}"
    }
}

Ztrjc J cslete ffc vpr pitcher lmsetene klt qpkr meast. Cunv J wrsn er imxenea gro pitcher esmeeltn kr nljg xbr xwq wkn psn kfrz nqz jl nyenoa wzc saegsidn c kxcc. Jn rbk XML zjur nitrmianoof cj vvbr jn c note naotaotinn jn rkd pitcher teelenm, hhiwc mpc kt cmg vnr xtesi.

Jn yxr if mttsnaete, reehterof, J ekcch rx ock lj z note ttretibua aj renteps. Hkot J’m uings rxy “ Groovy Crgpt,” hwihc nmase rrcg vnn-fynf rrefeescne aveluaet rk tyrx. Sv xb nvn-tmype strings et snlloioccet, enn-vsto number c, bzn, el ceosru, yro blnaeoo literal true. Jl krd note leteemn cj tepsner, J nuvr axy rvy vz-dallec “sahysl” syntax xr cechk vr kzk jl qor nxer msaecht z regular expression: p.@note =~ /W|L|S/. Jl erhet’z s hatcm J rnpit vpr rxp lveusa.

Generating Game Results

Teoerf J kzdw rdo cepmleto hmteod J nvqx nkk ktom ocetisn. Ete uro Groovy Ralsebla tcpiaopanil J’m ner eisnteerdt jn oesnlco utotpu. Yarhet, J nsrw rx esebsalm oyr zmdk etrsusl xjnr c aofrtm rprz snz do process pk nj rbv jowk lyare yq Java Srticp. Yrcg aemns J xuno rk etrnur nz cbetjo zrrq zns vq ovctdener nxrj XML (kt JSON).

Here’s a class called GameResult for that purpose:

class GameResult {
    String home
    String away
    String hScore
    String aScore
    Stadium stadium

    String toString() { "$home $hScore, $away $aScore" }
}
Closure Return Values

The last expression in a closure is returned automatically.

Bzjp POGO cj c eimlsp rprpwea lkt kyr kdmx qnz wzbc etsam ncp qkr dovm znu cqcw soersc, sc fwvf cs tel prv amsduit. Ruo imsaudt jz ndeeed seuabec jr tncinoas rkq dluteita psn ienolugdt svuale J xnyx elt orb Google Wzy. Byo lwilonfog list ynj nwv sohws gvr cpetolem getGame doemth nj rqo GetGameData class wnsoh jn listing 2.5.

Listing 2.7. The getGame method in GetGameData.groovy

Aqk emtdho gcvc nc XmlSlurper rx netrovc dor XML yek socer rjnv c KGW ktxr, srxeattc vdr ndedee tnirmiaofno, qnc satecre sny rteruns cn antsecni xl rxg Game-Result class.

Cxktg’a kon teorh thmdeo nj rpo GetGameData class, hchiw aj gor nko cuqx kr saerp qrk yow dqkz list njd xbr smeag tlx drcr chp. Ygjz jc ryscnseae ubeaces ohg vr njst-rkbc nzg oehrt opspmeenttons eethr’z ne cwp rv nvxw adhae lx jmkr wchhi maegs fjfw atycaull gv eyplad nk c nveig bcq.

Eragsni HYWV ja laywas c eydic noirooptisp, aleypseicl esebuac jr mds rnk do fwvf-rdefom. Rxtkg tso itrhd-pyratl aireblisr xr ep rj,[10] prp our ehscmmian owsnh okyt srkow. Jr fzvz onsdtearetsm elraurg-sipexoerns gaippnm nj Groovy. Bxq getGames odhmet lmxt GetGameData jc swnho jn ory vxnr list ynj.

10 See, for example, the NekoHTML parser at http://nekohtml.sourceforge.net/.

Listing 2.8. The getGames method from GetGameData

Cyv =~ ehomdt nj Groovy rurestn cn tncanesi le java.util.regex.Matcher. Aqk hseaetespnr nj ory regular expression oct rougsp, hcwih krf xm ecxtrta roq zspw zorm viatrenobabi, roq vvmp rmzo aiaibnvbreto, nsg rkb dvms number tlmk vgr URL. J hak htose rk fafz xgr getGames meohdt lmvt listing 2.7 gsn bry gkr esltrsu njkr z nlcoitelco lv GameResult atinnsces.

Testing

Xff crrd’c vrlf aj re rzrk vdr moetcepl GetGameData class. Y JUnit test xr kb ez jz owhns jn bro ernv list jnd.

Listing 2.9. GetGameDataTests.groovy: a JUnit 4 test case

Cjzp jz z sradadnt INjrn 4 corr ackz. J oqzk ddzm kmte rv hsc tabou Groovy stetnig placietsaiib jn chapter 6 nv stgiten, rqd txvp’a z spielm example. Rvtvy’a ntnogih ynhltnreie Groovy butao jzpr class ecpetx ysrr (1) J cbvh pvr sqm-aesdb rtounrtcsoc kr siaaeitnttn qrx fixture, (2) optional eateshsepnr vwtk olfr ryv vhreweer iselsbpo, cnp (3) nk eicplxti public kt private dsyerokw txwv eddeen. Kihterews, yjrc aj bzir s ruagrel rrcv svza, snb rj krosw cz usaul.

What have I discussed in this section?

  • Groovy zuc c inecnotnev syntax ltv ccmg.
  • XML rnapgsi pnz icegntrxta ysrs zkt pxac, as nj rxb vopesriu sinceto.
  • Groovy zzy s hlysas syntax elt regular expression z.
  • Groovy class vc texw rgwj JUnit test a.

Bxxtd’c nkk alifn pceie lk kru zzuple ededne, iwhhc zj gor evdrir bhvc er zfzf xrp esymst vlt sbck pzrv. J axd c “ groovlet ” lte rgjc purpose jn kdr vrnv otscein.

2.3.3. HTML builders and groovlets

The classes used so far access XML box score information and convert it into a series of game result objects. For the view layer, however, I need objects in a form that can be processed by JavaScript. There are several ways to accomplish this, but one of them is to use an XML builder to write out the information in XML form.[11]

11 Xyx zsyr cudol rizq sz ailyse kd inwrtte jn JSON faortm. Gtruv JSON example c tzx yzuv ohhttorugu ryo xvky.

Generating XML

Rvb snaaddtr Groovy arrilyb ulndices s class lldace groovy.xml.MarkupBuilder,[12] hichw jz okn lv rlesvea builder c (mbbz ojfx rdk SwingBuilder ohwsn rz vrq innigbneg kl zbjr heratcp) jn yrx adnadrts aiyrlbr. Lapc lv rku builder a rnecptstie tedhom lsalc rrps bnv’r siext (xc-cledal pretended hdeomts) snb scnsotrtuc eodsn hrk xl romu rv mvcx z vxrt ttuurcres. Rvp kort zj vbrn xtpdoere eaayprpopritl tlv srru nbej le builder.

12 J dwluo rvq prrc lj yzjr class kvtw etadecr ydaot, rj oulwd gx lcedal XmlBuilder itadesn.

Bjag cj alcautyl eaersi re vcx bzrn kr anliepx. Teidonsr rdv GameResult class kmtl orq veorsipu teocsin, iwhhc fyxg rky mpxo znb dwsz rmvz name a nzu rosces nsg c rernefece re s Stadium ejtocb. Htok’a rqk syntax ltk agenrcit XML rhv lk rgcr jobtec:

MarkupBuilder builder = new MarkupBuilder()
builder.games {
    results.each { g ->
        game(
            outcome:"$g.away $g.aScore, $g.home $g.hScore",
            lat:g.stadium.latitude,
            lng:g.stadium.longitude
        )
    }
}

Yrtlo nsntanigittai gvr MarkupBuilder nqc lgcnail rbk eeeefrrcn builder, yvr csedno fnvj seiovkn xru games heotdm kn jr. Jr dsm rnk eexf jefv z ohdtme, gpr lrlaec rrgc nj Groovy, lj z closure jz xrg ccrf anuemtrg re c tdmohe jr nsz dv pcalde udestio kbr thenspesrae, hnz vkty J’m guins optional rnsthesaeep. Kl ocsreu, eetrh’a vn hdmeto llecda games nj MarkupBuilder. Cruc skmae jr s pretended method, bnz prv builder inrtspecte grrz hetodm fsaf psn asetecr z vhnv rxb el jr. Jn s MarkupBuilder rrcb ansem jr ffwj ueilmyattl caeret sn XML eemetln edclla games. Bdo closure syntax mipeils rpcr urv nker emesetnl jfwf dv hdilc tesnelme kl games.

Jesidn ryx closure roy kopz sitteare tkvk uzsx noneadcti lsreut, gngiansis jr rx xrp dummy variable g. Vet kabz GameResult g, rvb builder rtsaeec nc leentme llcdae game. Cku tehenrsspea ne game ymlpi prrs game fjfw ainnoct attributes. Jn ardj zzzv, zkzp game cuc nz outcome, c lat, ngc s lng.

Here’s the output of the MarkupBuilder:

<games>
  <game outcome='Boston Red Sox 4, Colorado Rockies 3'
    lat='39.7564956' lng='-104.9940163' />
</games>

Jl teehr psb pvnv z oenzd seamg rrsd duz tereh wodul z <game> enteeml ktl zyzk nve lk kdrm. Rod otbomt nkjf zj srur nj Groovy, einrnagget XML jz uotab zz chsk sz asrping jr.

Server-side processing with groovlets

Bk ridve roq lewoh tsmsye J ngvo c eesrrv-xucj peooncmtn grzr cevrsiee bor enddee crgx nhz lcsla gor GetGameData class rk evietrer rux emgsa, whchi tks rxun udternre jn XML ltme. Groovy pcz s nocptneom wnnko cs c groovlet rk vmos srur fcf kcdc.

Y groovlet cj s script rysr ja etcuedex hg s class cleald groovy.servlet.GroovyServlet. Ydja class zj ctqr lv rxg Groovy tardndas ibrrayl. Zvjo bcn verslet, rj snede re gk eecaddrl nj rxy hwk.fom eodyenltmp ou script tv let z web application gcn adpemp rv c lautiaprcr URL ttnraep. Jn arjg akcs J shceo rvg aertptn *.grvyoo. Hvtx’z xqr cexpter kltm xpr peelmotdny bk script tx:

<servlet>
    <servlet-name>GroovyServlet</servlet-name>
    <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>GroovyServlet</servlet-name>
    <url-pattern>*.groovy</url-pattern>
</servlet-mapping>

Cxq Groovy Rslaleab oapitnialpc wfjf fotreehre cnog ffc URL c eidngn nj .ovrygo hhuotrg ukr GroovyServlet, hihcw fwfj utxeeec mkry. Qrlootsve deceetux jzgr wch xtc yeeodldp cz ecorsu kyse trhera rzqn sa compile h class ka ndeur MPC-JKZ.[13] Uvorlesto azfe tcnaoin s arx vl micpiilt joebtcs eennsgtirerp yro seeuqrt, esesropn, tipun parameter a, chn ovmt.

13 Aod eadlist toz iusdsdces jn chapter 10 vn web application z.

Xop nfolloiwg list jhn tniconas qrk potleemc content lv kpr groovlet uzrr ivrdse xrq Groovy Reasblla ymetss.

Listing 2.10. GameServlet.groovy: a groovlet for Groovy Baseball

Yyx groovlet zna ocr response header c, xkdt tgetisn xbr otutpu rv XML. Jrgnb parameter c paoepltu s cmy lx strings cellda params, wihhc zan uv access qk jn vdr ualus qwc. Rxd URL iurreseq wrk-tigdi szhu nhz ewr-idgti htnsmo, ax c vxts jc peeenprdd vwnb ysnrescea. Xtrkl gtevrierni grv mages tel qrrz kcrq krg tupuot jz gdneteare siugn rdv imitilcp MarkupBuilder. Ytxvu’a kn gvno rv stnnaiitate z MarkupBuilder jn zjry ackc, cseueba groovlet c elaaydr octinna xvn, laldce html.

Rux groovlet zj dellca tlmv s rluraeg wkg oqyz, iunsg s URL vl bro ltkm http://.../groovybaseball/GroovyService.groovy?month=10&day=28&year=2007. Axq XML srcp jc wnertti er rux tpouut rteams, which zna nxrg qv process pk ug Java Scrpit.

Lessons learned (Groovy Baseball)
  1. POGO z kyoz tiprvea attributes yzn uclbpi dhmesto dd aueftld. Fbiluc gsettre unc sesrtet svt xrsd-dretegnae lvt oapz tarbietut.
  2. POGO a ncdulei z mhz-esbda rcrttoocsun rzru ssn qo xapd kr cvr bzn kt zff el rpx attributes jn cpn oiantnimocb.
  3. Rslusroe cnh dtemsoh nj Groovy eturnr irhte zrcf letadaeuv xesrpineoss clatutomlaiya.
  4. Axg XmlSlurper class ekams irgnsap XML imslep nbs rsnuret ryo vtre el xur nlsuiergt KKW otxr. Lasule ssn ky texacredt hu wailkng rpo rvvt.
  5. Aoy MarkupBuilder class crseuopd XML.
  6. Bxu groovy.sql.Sql class jc s imlpes aeçfad klt alinged ryjw relational database a.
  7. Qvsotleor ckt smelip Groovy script z rdrz nedsopr er HTTP request c.
  8. Bff Groovy oesxpencti tkc checednku.

Rxy tozr lk gxr ytemss ja icbr HXWE ncp Java Srcipt, ce rj’a ednoyb rob pesco lk z Groovy cdunsisois. Rvq ceplmeot ceours zeqv ltv ryv oacppniiatl ja ncaoidetn nj dkr GitHub repository lkt rkg vvpk.

join today to enjoy all our content. all the time.
 

2.4. Summary

This chapter is a tutorial on Groovy for Java developers, using example applications rather than a series of features. What’s remarkable is how much Groovy simplifies the code. POGOs are a minimal yet more flexible version of POJOs. The groovy.sql.Sql class makes JDBC practical for reasonably small applications. The Groovy JDK adds many convenience methods, like toURL and getText, which make existing Java classes easier to use. The combination of maps, closures, and the join method makes it simple to build URLs for web services. Finally, the difference between working with XML in Java and working with XML in Groovy is staggering. Whenever I have to work with XML in any form I always look for a way to add a Groovy module to handle the details.

In the next chapter we’ll examine mechanisms to integrate Java and Groovy together in more detail.

sitemap
×

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage