Ohjelmointi

BeanLint: JavaBeansin vianmääritystyökalu, osa 1

Muutaman kuukauden välein saan paniikkia tai hämmentynyttä sähköpostia JavaBeans-neofitilta, joka yrittää luoda JavaBeanin, joka sisältää Kuva kuka ei pysty selvittämään, miksi BeanBox ei lataa papua. Ongelma on siinä java.awt.Image ei ole Sarjattavissa, joten ei myöskään ole mitään, joka sisältää a java.awt.Image, ainakin ilman mukautettua sarjoitusta.

Itse olen viettänyt lukemattomia tunteja laittamalla println () lauseet BeanBox-koodiin ja kääntävät sen sitten uudelleen yrittäen selvittää, miksi pavut eivät lataudu. Joskus se johtuu jostakin yksinkertaisesta, tyhmyydestä - kuten unohdetaan määritellä nollagumenttirakentaja tai jopa luokka julkinen. Toisinaan se osoittautuu jotain hämärämmäksi.

Kadonneen pavun tapaus

Vaikka vaatimukset kirjoittaa Java-luokka JavaBeaniksi ovat yksinkertaisia ​​ja suoraviivaisia, on joitain piilotettuja seurauksia, joita monet pavunrakennustyökalut eivät käsittele. Nämä pienet gotchas voi helposti syödä iltapäivän, kun etsit koodiasi, etsimällä syytä, miksi rakennustyökalusi ei löydä papuasi. Jos olet onnekas, saat ponnahdusikkunan, jossa on salattu virheilmoitus - jotain "NoSuchMethodException on kiinni FoolTool-introspektiossa"" Jos sinulla ei ole onnea, JavaBean, johon olet kaatanut niin paljon hikiä, kieltäytyy näkymästä rakennustyökalussa, ja vietät iltapäivän harjoitellessasi sanastoa, josta äitisi yritti kovasti parantaa sinua. BeanBox on se on jo kauan ollut törkeä rikoksentekijä tässä suhteessa, ja vaikka se onkin parantunut, se silti pudottaa ominaisuuksia ja jopa kokonaisia ​​papuja antamatta kehittäjälle yhtä ainoaa vihjeitä miksi.

Tässä kuussa johdatan sinut pois "kadonneen pavun maasta" tuomalla uuden työkalun nimeltä outo, PapuLint, joka analysoi purkkitiedostojen luokkia etsimällä mahdollisia ongelmia, jotka tekisivät luokista käyttökelvottomat pavuina. Vaikka tämä työkalu ei kata kaikkia mahdollisia papuongelmia, se tunnistaa joitain tärkeimpiä yleisiä ongelmia, jotka tekevät pavut purettaviksi.

Ymmärtääkseen miten PapuLint toimii sen taikuudessa, tässä kuussa ja seuraavassa tarkastellaan joitain vähemmän tunnettuja Java-sovellusliittymän kulmia:

  • Luomme mukautetun luokan kuormaaja, joka lataa uudet Java-luokat jar-tiedostosta

  • Käytämme pohdintaa mekanismi, jonka avulla Java-ohjelmat voivat analysoida Java-luokkia tunnistamaan luokkatiedostojemme sisällön

  • Käytämme Itsetarkastaja tuottaa raportti kaikista luokan papuista ominaisuuksista mille tahansa purkitiedostossa olevalle luokalle, joka läpäisee kaikki testit (ja on siten potentiaalinen papu)

Siihen mennessä, kun olemme valmiit, sinulla on hyödyllinen työkalu papujen virheenkorjaukseen, ymmärrät paremmin pavun vaatimukset ja opit joistakin Javan hienoista ominaisuuksista samanaikaisesti.

Pavun perusteet

Jotta luokkatiedosto olisi JavaBean, on kaksi yksinkertaista vaatimusta:

  1. Luokalla on oltava julkinen konstruktori ilman argumentteja (a nolla-arg konstruktori)

  2. Luokan on toteutettava tyhjä tag-käyttöliittymä java.io.Serialisoitavissa

Se siitä. Noudata näitä kahta yksinkertaista sääntöä, ja luokastasi tulee JavaBean. Yksinkertaisin JavaBean näyttää siis tältä:

tuo java.io. *; public class TinyBean toteuttaa Serializable {public TinyBean () {}} 

Tietenkin yllä oleva papu ei ole hyvä paljon, mutta sitten emme tehneet siihen paljon työtä. Vain yrittää tällaisen peruskomponentin kirjoittaminen toiseen komponenttikehykseen. (Ja ei oikeudenmukaista käyttää "velhoja" tai muita koodigeneraattoreita käärintäluokkien tai oletustoteutusten luomiseen. Se ei ole oikeudenmukainen vertailu JavaBeanin eleganssista toiseen tekniikkaan.)

TinyBean luokassa ei ole ominaisuuksia (paitsi "nimi"), ei tapahtumia eikä menetelmiä. Valitettavasti on silti helppo luoda vahingossa luokkia, jotka näyttävät noudattavan sääntöjä, mutta eivät toimi oikein JavaBeans-kontissa, kuten BeanBoxissa tai suosikkisi IDE: ssä (integroitu kehitysympäristö).

Esimerkiksi BeanBox ei lataudu TinyBean yllä, jos olisimme unohtaneet sisällyttää avainsanan julkinen luokan määritelmään. javac loisi luokkatiedoston luokalle, mutta BeanBox kieltäytyisi lataamasta sitä eikä (viime aikoihin saakka) antanut mitään tietoa siitä, miksi se kieltäytyi. Antaakseen Sunin Java-ihmisille luottoluokituksen BeanBox ilmoittaa nyt yleensä syyn, miksi papua ei ladata, tai syystä, miksi ominaisuus ei näy ominaisuusarkissa, ja niin edelleen. Eikö olisikaan mukavaa, jos meillä olisi työkalu tarkistaa mahdollisimman monta asiaa tällaisista luokista - ja varoittaisi meitä niistä, jotka todennäköisesti aiheuttavat ongelmia, kun niitä käytetään JavaBeans-ympäristössä? Se on tavoite PapuLint: auttaa sinua JavaBeans-ohjelmoijana analysoimaan pavut purkitiedostojensa sisällä etsimällä mahdollisia ongelmia, jotta voit korjata ne ennen kuin törmäät niihin testausprosessissa tai - mikä vielä pahempaa - kentällä.

Mahdolliset papu-ongelmat

Kun olen kehittänyt JavaBeansia tähän sarakkeeseen, olen todennäköisesti tehnyt suurimman osan virheistä, joita voi tehdä kirjoittaessani JavaBeania. Tavallaan BeanBoxin hiljainen luonne on pakottanut minut oppimaan enemmän papuista - ja Javasta - kuin minulla olisi muuten. Suurin osa JavaBeans-kehittäjistä haluaisi kuitenkin yksinkertaisesti tuottaa toimivia JavaBean-laitteita, jotka toimivat oikein ja säästävät "kasvukokemukset" henkilökohtaiseen elämäänsä. Olen kerännyt luettelon mahdollisista ongelmista luokkatiedostossa, joka voi aiheuttaa tuhoja JavaBeanin kanssa. Nämä ongelmat ilmenevät, kun papu ladataan astiaan, tai kun papua käytetään sovelluksessa. Sarjauksessa on helppo hukata yksityiskohtia, joten kiinnitämme erityistä huomiota sarjoitettavuusvaatimuksiin.

Tässä on joitain yleisiä ongelmia, jotka eivät aiheuta kääntöaikaa koskevia virheitä, mutta voivat myös aiheuttaa luokan tiedoston olla JavaBean tai ettei se toimi oikein, kun se on ladattu säilöön:

  • Luokalla ei ole nolla-argumenttirakentajaa. Tämä on yksinkertaisesti edellä lueteltujen ensimmäisten vaatimusten rikkominen, ja se on virhe, jota muut kuin aloittelijat eivät usein kohta.

  • Luokka ei toteuta Sarjattavissa. Tämä rikkoo edellä mainittua toista vaatimusta ja on helppo havaita. Luokka voi vaatimus toteuttaa Sarjattavissa, mutta silti ei noudata sopimusta. Joissakin tapauksissa voimme havaita sen automaattisesti.

  • Itse luokkaa ei ilmoiteta julkinen.

  • Luokkaa ei ladata jostain syystä. Luokat heittävät joskus poikkeuksia ladattaessa. Usein tämä johtuu siitä, että muita luokkia, joista he ovat riippuvaisia, ei ole saatavana ClassLoader luokan lataamiseen käytetty objekti. Kirjoitamme mukautetun luokan kuormaajan tähän artikkeliin (katso alla).

  • Luokka on abstrakti. Vaikka komponenttiluokka voisi teoriassa olla abstrakti, JavaBeanin todellinen käynnissä oleva instanssi on aina jonkin konkreettisen (eli ei-abstraktin) luokan ilmentymä. Abstrakteja luokkia ei voida määritellä määritelmän mukaan, joten emme pidä abstrakteja luokkia ehdokkaina pavuina.

  • Luokka toteuttaa Serializable, silti se tai yksi sen perusluokista sisältää ei-alustavia kenttiä. Java-sarjallisuusmekanismin oletusarvo mahdollistaa luokan määrittelemisen toteuttaa Serializable, mutta sallii sen epäonnistua, kun sarjoitusta todella yritetään. Meidän PapuLint luokka varmistaa, että kaikki a Sarjattavissa luokka todella ovat Sarjattavissa.

Luokka, joka epäonnistuu jossakin yllä mainituista ongelmista, voi olla melko varma siitä, että se ei toimi oikein JavaBeanina, vaikka kaikki alussa ilmoitetut pavun perusvaatimukset täyttyisivät. Jokaiselle näistä ongelmista määritetään sitten testi, joka tunnistaa ongelman ja raportoi siitä. vuonna PapuLint luokka, mikä tahansa purkitiedoston luokkatiedosto analysoidaan sitä tekee kaikki nämä testit on läpäistävä itsetarkastettu (analysoidaan luokan avulla java.beans.Tarkastaja) tuottaa raportin papun määritteistä (ominaisuudet, tapahtumasarjat, mukautin ja niin edelleen). java.beans.Tarkastaja on luokka luokassa paketti java. pavut joka käyttää Java 1.1 -heijastusmekanismia löytääksesi (tai luo) a java.beans.BeanInfo objekti JavaBeanille. Käsittelemme pohdintaa ja itsetarkastelua ensi kuussa.

Katsotaanpa nyt lähdekoodia PapuLint nähdä kuinka analysoida potentiaalisia papuluokkia.

Esittelyssä BeanLint

"Vanhoina hyvinä aikoina" (mikä tarkoittaa yleensä "silloin, kun luulin vielä tietävän kaiken"), Unix-käyttöjärjestelmän C-ohjelmoijat käyttävät ohjelmaa nimeltä nukka etsiä mahdollisia ajonaikaisia ​​vikoja C-ohjelmistaan. Tämän kunnianarvoisen ja hyödyllisen työkalun kunniaksi olen kutsunut nöyrän pavunanalyysi luokkani PapuLint.

Sen sijaan, että esitämme koko lähdekoodin yhdessä valtavassa, sulamattomassa kappaleessa, tarkastelemme sitä yksi kappale kerrallaan, ja selitän matkan varrella erilaisia ​​idioomeja siitä, kuinka Java käsittelee luokkatiedostoja. Siihen mennessä, kun olemme läpi, olemme kirjoittaneet luokan kuormaajan, käyttäneet huomattavaa määrää luokkia java.lang.reflect, ja he ovat saaneet nyökkäävän tuttavan luokan kanssa java.beans.Tarkastaja. Ensinnäkin katsotaanpa PapuLint toiminnassa nähdäksemme, mitä se tekee, ja sitten syvennämme sen täytäntöönpanon yksityiskohtia.

Huonoja papuja

Tässä osiossa näet joitain luokkatiedostoja, joissa on erilaisia ​​ongelmia, koodin alla olevan ongelman kanssa. Aiomme luoda purkkitiedoston, joka sisältää nämä luokat, ja katsotaan mitä PapuLint tekee heidän kanssaan.


tuo java.io. *;

julkinen luokka w toteuttaa Serializable {w () {}}

Ongelma:

Nollaväitteiden rakentaja ei

julkinen


julkinen luokka x {julkinen x () {}} 

Ongelma:

Ei

Sarjattavissa.


tuo java.io. *;

julkinen luokka y toteuttaa Serializable {public y (String y_) {}}

Ongelma:

Ei nollaväitteiden rakennuttajaa.


tuo java.io. *;

luokka z toteuttaa Serializable {public z () {}}

Ongelma:

Luokka ei ole julkinen.


tuo java.io. *; tuo java.awt. *;

luokka u0 toteuttaa Serializable {private Image i; julkinen u0 () {}}

julkinen luokka u laajentaa u0 työvälineitä Serialisoitavissa {public u () {}}

Ongelma:

Sisältää ei-alustavan objektin tai viitteen.


tuo java.io. *;

public class v laajentaa java.awt.Button toteuttaa Serializable {public v () {} public v (String s) {super (s); }}

Ongelma:

Ei mitään - pitäisi toimia hyvin!


Jokaisella näistä pyrkivistä pavuista, viimeistä lukuun ottamatta, on potentiaalisia ongelmia. Viimeinen ei ole vain papu, vaan toimii yhtenä. Kun kaikki nämä luokat on koottu, luomme tämän tyyppisen purkitiedoston:

$ jar cvf BadBeans.jar * .luokan lisäys: u.luokka (sisään = 288) (ulos = 218) (tyhjennetty 24%) lisäämällä: u0.luokka (sisään = 727) (ulos = 392) (tyhjennetty 46% lisäämällä: w.luokka (sisään = 302) (ulos = 229) (tyhjennetty 24%) lisäämällä: x.luokka (sisään = 274) (ulos = 206) (tyhjennetty 24%) lisäämällä: y.luokka (sisään = 362) (ulos = 257) (tyhjennetty 29%) lisäämällä: z.luokka (sisään = 302) (ulos = 228) (tyhjennetty 24%) lisäämällä: v.luokka (sisään = 436) (ulos = 285) (tyhjennetty 34%) 

Emme aio sisällyttää manifestitiedostoa (joka on purkitiedoston sisällä oleva tiedosto, joka kuvaa purkitiedoston sisältöä - katso alla oleva kohta "Purkin avaaminen"), koska purkkitiedostoon PapuLint ei käsittele luettelotiedostoja. Luettelotiedoston jäsentäminen ja vertaaminen purkin sisältöön olisi mielenkiintoinen harjoitus, jos haluat laajentaa mitä PapuLint onnistuu.

Juostaan PapuLint purkitiedostossa ja katso mitä tapahtuu:

=== Luokan u0 analysointi === luokka u0 ei ole JavaBean, koska: luokka ei ole julkinen

=== Luokan z analysointi === luokka z ei ole JavaBean, koska: luokka ei ole julkinen

=== Luokan y analysointi === luokka y ei ole JavaBean, koska: sillä ei ole nollagumenttirakenninta

=== Luokan x analysointi === luokka x ei ole JavaBean, koska: luokka ei ole sarjoitettavissa

=== Luokan w analysointi === luokka w ei ole JavaBean, koska: sen nollagumenttirakentaja ei ole julkinen

=== Luokan v analysointi === Huomaa: java.awt.Button määrittelee mukautetun sarjallisuuden Huomautus: java.awt.Component määrittelee mukautetun sarjoituksen v läpäisee kaikki JavaBean-testit

Itsetarkastusraportti -------------------- Luokka: v Mukauttimen luokka: ei mitään

Ominaisuudet: totuusarvo käytössä {isEnabled, setEnabled} (... monia muita ominaisuuksia)

Tapahtumasarjat: java.awt.event.MouseListener-hiiri (... monia muita tapahtumasarjoja)

Menetelmät: public boolean java.awt.Component.isVisible () (... many, monet lisää menetelmiä - sheesh!)

=== luokan v loppu ===

=== Luokan u analysointi === luokka u ei ole JavaBean, koska: luokan seuraavat kentät eivät ole sarjoitettavissa: luokka java.awt.Image i (määritelty u0: ssa) === Luokan u ===

Tulosta on lyhennetty jonkin verran, koska tapahtumasarjojen ja -menetelmien luettelo on hyvin pitkä, ei lisää paljon keskusteluun täällä. Voit nähdä koko tuotoksen tiedostossa output.html, jos haluat käsityksen tavaroiden määrästä PapuLint sammuttaa.

Huomaa, että PapuLint tunnistanut virheellisesti huonojen luokkien tiedostojen ongelmat:

luokka u0 ei ole JavaBean, koska: luokka ei ole julkinen luokka z ei ole JavaBean, koska: luokka ei ole julkinen luokka y ei ole JavaBean, koska: sillä ei ole nollagumenttirakentajaa luokka x ei ole JavaBean, koska: luokka ei ole sarjoitettavissa oleva luokka w ei ole JavaBean, koska: sen nollagumenttirakentaja ei ole julkinen luokka u ei ole JavaBean, koska: luokan seuraavat kentät eivät ole sarjoitettavissa: luokka java.awt.Image i (määritelty u0: ssa) 
$config[zx-auto] not found$config[zx-overlay] not found