Programiranje

BeanLint: Orodje za odpravljanje težav JavaBeans, 1. del

Vsakih nekaj mesecev prejmem panično ali zmedeno e-pošto od neofita JavaBeans, ki poskuša ustvariti JavaBean, ki vsebuje Slika in kdo ne more ugotoviti, zakaj BeanBox ne bo naložil fižola. Težava je v tem java.awt.Image ni Serializabilno, zato tudi nič ne vsebuje a java.awt.Image, vsaj brez serializacije po meri.

Sama sem porabila nešteto ur postavljanja println () izjave v kodo BeanBox, nato pa jo ponovno prevede, da bi ugotovil, zakaj se moj fižol ne bo naložil. Včasih je to posledica neke preproste, neumne stvari - na primer pozabe, da bi konstruktor ničelnega argumenta ali celo razred opredelili kot javnosti. Včasih se izkaže, da gre za nekaj bolj nejasnega.

Primer pogrešanega fižola

Medtem ko so zahteve za pisanje razreda Java kot JavaBean enostavne in enostavne, obstaja nekaj skritih posledic, ki jih številna orodja graditelja fižolov ne obravnavajo. Ti mali imam lahko pojeste popoldan, ko lovite svojo kodo, iščete razlog, zakaj orodje za gradnjo ne najde vašega fižola. Če imate srečo, se prikaže pojavno pogovorno okno s skrivnostnim sporočilom o napaki - nekaj podobnega "NoSuchMethodException je ujet v FoolTool Introspection"Če imate srečo, se JavaBean, v katerega ste vlili toliko znoja, noče prikazati v vašem orodju za gradnjo, popoldne pa boste vadili za besediščem, od katerega vas je mati tako močno poskušala ozdraviti. BeanBox je že dolgo močan kršitelj v zvezi s tem, in čeprav se je izboljševal, bo vseeno opuščal lastnosti in celo cel fižol, ne da bi razvijalcu dal en sam namig, zakaj.

Ta mesec vas bom izpeljal iz "dežele pogrešanega fižola" z uvedbo novega orodja, čudno, BeanLint, ki analizira razrede znotraj datotek jar in išče možne težave, zaradi katerih bi razredi postali neuporabni kot fižol. Čeprav to orodje ne zajema vseh možnih težav z fižolom, ugotavlja nekatere glavne pogoste težave, zaradi katerih fižol ni naložljiv.

Da bi razumeli kako BeanLint deluje čarobno, ta mesec in naslednji se bomo poglobili v nekatere manj znane kotičke standardnega API-ja Java:

  • Ustvarili bomo po meri razred nakladalnik, ki naloži nove razrede Java iz datoteke jar

  • Uporabili bomo refleksija mehanizem, ki omogoča programom Java, da analizirajo razrede Java, da ugotovijo, kaj je v datotekah naših razredov

  • Uporabili bomo Introspector pripraviti poročilo o vseh lastnostih razreda podobnih zrnom za kateri koli razred v datoteki jar, ki opravi vse teste (in je zato potencialni zrn)

Ko bomo končali, boste imeli koristno orodje za odpravljanje napak v fižolu, bolje boste razumeli zahteve glede fižola in hkrati spoznali nekatere kul nove funkcije Java.

Osnove fižola

Da je datoteka razreda JavaBean, obstajata dve preprosti zahtevi:

  1. Razred mora imeti javni konstruktor brez argumentov (a konstruktor nič arg)

  2. Razred mora implementirati prazen vmesnik oznake java.io.Serializable

To je to. Upoštevajte ta dva preprosta pravila in vaš razred bo JavaBean. Najpreprostejši JavaBean je torej videti nekako takole:

uvoz java.io. *; javni razred TinyBean izvaja Serializable {public TinyBean () {}} 

Seveda zgornji fižol ni dober za veliko, potem pa nismo vložili veliko dela. Samo poskusite pisanje osnovne komponente, kot je ta, v drugem okviru komponente. (In ni poštene uporabe "čarovnikov" ali drugih generatorjev kode za ustvarjanje razredov ovojev ali privzetih izvedb. To ni poštena primerjava elegance JavaBeans in druge tehnologije.)

The TinyBean class nima lastnosti (razen, morda, "name"), nobenih dogodkov in nobenih metod. Na žalost je še vedno lahko po naključju ustvariti razrede, za katere se zdi, da upoštevajo pravila, vendar ne delujejo pravilno v vsebniku JavaBeans, kot je BeanBox ali vaš najljubši IDE (integrirano razvojno okolje).

Na primer, BeanBox ne bi naložil našega TinyBean zgoraj, če smo pozabili vključiti ključno besedo javnosti na definicijo razreda. javac bi ustvaril datoteko razreda za razred, vendar ga BeanBox ne bi hotel naložiti in (do nedavnega vseeno) ne bi navedel, zakaj bi zavrnil. Če želite ljudem Sun-ove Java priznati, BeanBox zdaj običajno sporoči razlog, zakaj se fiž ne naloži, ali razlog, da se lastnost ne prikaže na listu lastnosti itd. Ali ne bi bilo lepo, če bi imeli orodje za preverjanje čim več stvari o takih razredih - in nas opozorilo na tiste, ki bi lahko povzročili težave, če jih uporabljamo v okolju JavaBeans? To je cilj BeanLint: da vam kot programerju JavaBeans pomaga analizirati fižol znotraj njihovih datotek kozarcev in poiskati morebitne težave, da jih boste lahko odpravili, preden boste naleteli nanje v postopku testiranja ali - še huje - na terenu.

Potencialne težave s fižolom

Ko sem razvil JavaBeans za ta stolpec, sem verjetno naredil večino napak, ki jih lahko naredimo pri pisanju JavaBean. Na nek način me je tiha narava BeanBox-a prisilila, da se o fižolu - in o Javi - naučim več, kot bi se sicer. Večina razvijalcev JavaBeans pa bi raje preprosto ustvarila delujoče JavaBeans, ki delujejo pravilno, in prihranila "izkušnje rasti" za svoje osebno življenje. Zbral sem seznam možnih težav z datoteko razreda, ki lahko povzroči opustošenje z JavaBean. Te težave se pojavijo med postopkom nalaganja fižola v posodo ali pri uporabi fižola v aplikaciji. Pri serializaciji je enostavno zamuditi podrobnosti, zato posebno pozornost namenjamo zahtevam serializacije.

Tu je nekaj pogostih težav, ki ne povzročajo napak pri prevajanju, lahko pa povzročijo, da datoteka razreda ne biti JavaBean ali če ne deluje pravilno, ko je naložen v vsebnik:

  • Razred nima konstruktorja nič argumenta. To je preprosto kršitev prve zahteve, naštete zgoraj, in gre za napako, na katero pogosto ne naletijo začetniki.

  • Razred se ne izvaja Serializabilno. To je kršitev zgoraj navedene druge zahteve in jo je enostavno opaziti. Razred lahko terjatev za izvajanje Serializabilnoin še vedno ne upošteva pogodbe. V nekaterih primerih lahko samodejno zaznamo, kdaj se je to zgodilo.

  • Razred sam ni prijavljen javnosti.

  • Razreda iz nekega razloga ni mogoče naložiti. Razredi včasih vrnejo izjeme, ko se nalagajo. Pogosto je to zato, ker drugi razredi, od katerih so odvisni, niso na voljo pri ClassLoader objekt, ki se uporablja za nalaganje razreda. V tem članku bomo napisali nalagalnik razredov po meri (glej spodaj).

  • Predavanje je abstraktno. Medtem ko bi bil razred komponent v teoriji lahko abstrakten, je dejanski delujoči primerek JavaBean vedno primerek nekega konkretnega (torej ne abstraktnega) razreda. Po definiciji abstraktnih razredov ni mogoče ustvariti instanca, zato abstraktnih razredov kot kandidate ne bomo obravnavali kot fižol.

  • Razred izvaja Serializable, vendar ta ali eden od njegovih osnovnih razredov vsebuje polja, ki jih ni mogoče serirati. Privzeta zasnova mehanizma serializacije Java omogoča, da se razred opredeli kot izvaja Serializable, vendar dovoli, da ne uspe, ko se dejansko poskuša serializacija. Naše BeanLint razred zagotavlja, da so vsa ustrezna polja a Serializabilno razred dejansko so Serializabilno.

Razred, ki ne uspe pri nobeni od zgornjih težav, je lahko precej prepričan, da ne deluje pravilno kot JavaBean, tudi če sta izpolnjeni dve osnovni zahtevi za grah, navedeni že na začetku. Za vsako od teh težav bomo določili test, ki zazna določeno težavo in jo sporoči. V BeanLint class, katero koli datoteko razreda v datoteki jar, ki jo analiziramo naredi opraviti vse te teste introspected (analizirano s pomočjo razreda java.beans.Introspector) za izdelavo poročila o atributih fižola (lastnosti, nabori dogodkov, prilagoditelj itd.). java.beans.Introspector je razred v paket java.beans ki uporablja odsevni mehanizem Java 1.1 za iskanje (ali ustvarjanje) a java.beans.BeanInfo objekt za JavaBean. Razmislek in samoogled bomo pokrili naslednji mesec.

Zdaj pa si oglejmo izvorno kodo za BeanLint da vidim, kako analizirati potencialne razrede fižola.

Predstavljamo vam BeanLint

V "dobrih starih časih" (kar običajno pomeni "takrat, ko sem še mislil, da vem vse") bi programerji C v operacijskem sistemu Unix uporabljali program, imenovan lint poiskati morebitne težave med izvajanjem v njihovih programih C. V čast tega častitljivega in uporabnega orodja sem poklical svoj skromni tečaj za analizo fižola BeanLint.

Namesto da predstavimo celotno izvorno kodo z enim ogromnim neprebavljivim delom, si jo bomo ogledali po delih in med potjo bom razložil različne idiome o tem, kako Java ravna z datotekami razredov. Ko bomo končali, bomo napisali nalagalnik razredov, v katerem bomo uporabili ugledno število razredov java.lang.reflect, in so se z razredom spoznali s prikimavanjem java.beans.Introspector. Najprej si oglejmo BeanLint v akciji, da vidimo, kaj počne, nato pa se bomo poglobili v podrobnosti njegove izvedbe.

Slab fižol

V tem razdelku boste videli nekaj datotek predavanj z različnimi težavami, pri čemer je težava navedena pod kodo. Ustvarili bomo datoteko jar, ki vsebuje te razrede, in videli bomo kaj BeanLint počne z njimi.


uvoz java.io. *;

javni razred w izvaja Serializable {w () {}}

Težava:

Konstruktor ničelnih argumentov ne

javnosti


javni razred x {javni x () {}} 

Težava:

Ne

Serializabilno.


uvoz java.io. *;

javni razred y izvaja Serializable {public y (String y_) {}}

Težava:

Brez konstruktorja ničelnega argumenta.


uvoz java.io. *;

razred z izvaja Serializable {public z () {}}

Težava:

Predavanje ni javno.


uvoz java.io. *; uvoz java.awt. *;

razred u0 izvaja Serializable {private Image i; javno u0 () {}}

javni razred u razširja u0 izvaja Serializable {public u () {}}

Težava:

Vsebuje predmet ali sklic, ki ga ni mogoče serirati.


uvoz java.io. *;

javni razred v razširja java.awt.Button izvaja Serializable {public v () {} public v (String s) {super (s); }}

Težava:

Nič - dobro bi moralo delovati!


Vsak od teh ambicioznih fižolov, razen zadnjega, ima potencialne težave. Zadnji je ne samo fižol, ampak deluje kot en. Po prevajanju vseh teh razredov ustvarimo datoteko jar, kot je ta:

$ jar cvf BadBeans.jar * .class dodajanje: u.class (v = 288) (out = 218) (deflacionirano 24%) dodajanje: u0.class (v = 727) (out = 392) (deflacionirano 46% dodajanje: w.class (v = 302) (out = 229) (deflacionirano 24%) dodajanje: x.class (v = 274) (out = 206) (deflacionirano 24%) dodajanje: y.class (v = 362) (out = 257) (deflacionirano 29%) dodajanje: z.class (v = 302) (out = 228) (deflacionirano 24%) dodajanje: v.class (v = 436) (out = 285) (deflacionirano 34%) 

Datoteke manifesta (ki je datoteka znotraj datoteke jar, ki opisuje vsebino datoteke jar - glejte "Odpiranje kozarca" spodaj) ne bomo vključili v datoteko jar, ker BeanLint se ne ukvarja z manifestnimi datotekami. Razčlenjevanje datoteke manifesta in primerjava z vsebino kozarca bi bila zanimiva vaja, če želite kaj razširiti BeanLint lahko.

Tečimo BeanLint na datoteki jar in poglejte, kaj se bo zgodilo:

=== Analiziranje razreda u0 === razred u0 ni JavaBean, ker: razred ni javen

=== Analiziranje razreda z === razred z ni JavaBean, ker: razred ni javen

=== Analiziranje razreda y === razred y ni JavaBean, ker: nima konstruktorja nič argumentov

=== Analiziranje razreda x === razred x ni JavaBean, ker: razreda ni mogoče serializirati

=== Analiziranje razreda w === razred w ni JavaBean, ker: njegov konstruktor ničelnega argumenta ni javen

=== Analiziranje razreda v === Opomba: java.awt.Button definira serializacijo po meri Opomba: java.awt.Component definira serializacijo po meri v opravi vse teste JavaBean

Poročilo o introspekciji -------------------- Razred: v Razred po meri: noben

Lastnosti: logična vrednost omogočena {isEnabled, setEnabled} (... veliko več lastnosti)

Nabori dogodkov: miška java.awt.event.MouseListener (... veliko več naborov dogodkov)

Metode: javna logična java.awt.Component.isVisible () (... veliko, veliko več metod - sheesh!)

=== Konec razreda v ===

=== Analiziranje razreda u === razred u ni JavaBean, ker: naslednja polja razreda niso serializirana: razred java.awt.Image i (definiran v u0) === Konec razreda u ===

Rezultat je bil nekoliko skrajšan, ker so seznami nizov in metod dogodkov zelo dolgi, kar ne prispeva k naši razpravi tukaj. Celoten izhod si lahko ogledate v datoteki output.html, če želite predstavo o količini stvari BeanLint daje ven.

Opazite to BeanLint pravilno ugotovil težave z datotekami slabega razreda:

razred u0 ni JavaBean, ker: razred ni javni razred z ni JavaBean, ker: razred ni javni razred y ni JavaBean, ker: nima konstruktorja ničelnega argumenta, razred x ni JavaBean, ker: class ni Serializable class w ni JavaBean, ker: njegov konstruktor ničelnih argumentov ni javni razred u ni JavaBean, ker: naslednja polja razreda niso Serializable: class java.awt.Image i (definirano v u0) 
$config[zx-auto] not found$config[zx-overlay] not found