Programmēšana

BeanLint: JavaBeans problēmu novēršanas rīks, 1. daļa

Ik pēc pāris mēnešiem es saņemu panisku vai apmulsušu e-pastu no JavaBeans neofīta, kurš mēģina izveidot JavaBean, kas satur Attēls un kurš nespēj saprast, kāpēc BeanBox neielādēs pupu. Problēma ir tā java.awt.Image nav Serializējams, tāpēc arī nekas nav tāds, kas satur a java.awt.Image, vismaz bez pielāgotas sērijas.

Pats esmu pavadījis neskaitāmas stundas, liekot println () paziņojumus BeanBox kodā, pēc tam to atkārtoti apkopojot, mēģinot saprast, kāpēc manas pupiņas netiks ielādētas. Dažreiz tas ir saistīts ar kādu vienkāršu, stulbu lietu - piemēram, aizmirstot definēt nulles argumenta konstruktoru vai pat klasi kā publiski. Citreiz tas izrādās kaut kas neskaidrāks.

Pazudušās pupas gadījums

Kaut arī prasības rakstīt Java klasi kā JavaBean ir vienkāršas un vienkāršas, ir dažas slēptas sekas, kuras daudzi pupiņu veidošanas rīki nenovērš. Šie mazie gotchas var viegli apēst pēcpusdienu, meklējot kodu, meklējot iemeslu, kāpēc jūsu celtnieka rīks nevar atrast jūsu pupiņu. Ja paveicas, jūs saņemsiet uznirstošo dialoglodziņu ar kriptisku kļūdas ziņojumu - kaut ko līdzīgu "NoSuchMethodException nozvejotas FoolTool Introspection. "Ja jums nav paveicies, JavaBean, kurā esat ielējis tik daudz sviedru, atteiksies parādīties jūsu celtnieka rīkā, un jūs pavadīsit pēcpusdienu, mēģinot vārdu krājumu, kuru māte tik ļoti centās jūs izārstēt. BeanBox ir šajā ziņā jau sen ir bijis rupjš likumpārkāpējs, un, lai arī tas ir uzlabojies, tas tomēr pazeminās īpašības un pat veselas pupiņas, nesniedzot izstrādātājam vienu pavedienu, kāpēc.

Šomēnes es jūs vedīšu ārā no “pazudušo pupiņu zemes”, ieviešot jaunu rīku, ko dīvainā kārtā BeanLint, kas analizē klases burku failos, meklējot iespējamās problēmas, kas padarītu klases neizmantojamas kā pupas. Kaut arī šis rīks neaptver visas iespējamās pupiņu problēmas, tas identificē dažas no galvenajām izplatītākajām problēmām, kas padara pupiņas neizkraujamas.

Lai saprastu, kā BeanLint darbojas savā burvībā, šajā un nākamajā mēnesī mēs iedziļināsimies nedaudz mazāk zināmos standarta Java API stūros:

  • Mēs izveidosim pielāgotu klases iekrāvējs, kas no jar faila ielādē jaunas Java klases

  • Mēs izmantosim pārdomas mehānisms, kas ļauj Java programmām analizēt Java klases, lai noteiktu, kas atrodas mūsu klases failos

  • Mēs izmantosim Introspektors sagatavot pārskatu par visām klases pupiņu īpašībām jebkurai burka faila klasei, kura iztur visus testus (un tāpēc ir potenciālā pupiņa)

Līdz brīdim, kad mēs esam pabeiguši, jums būs noderīgs rīks pupiņu atkļūdošanai, jūs labāk sapratīsit pupiņu prasības un vienlaikus uzzināsiet par dažām jaukajām Java jaunajām funkcijām.

Pupiņu pamati

Lai klases fails būtu JavaBean, ir divas vienkāršas prasības:

  1. Klasei ir jābūt publiskam konstruktoram bez argumentiem (a nulles arg konstruktors)

  2. Klasei jāievieš tukšā taga saskarne java.io.Serializējams

Tieši tā. Ievērojiet šos divus vienkāršus noteikumus, un jūsu klase būs JavaBean. Tad vienkāršākais JavaBean izskatās apmēram šādi:

importēt java.io. *; publiskā klase TinyBean ievieš Serializable {public TinyBean () {}} 

Protams, iepriekšminētā pupiņa nav daudz noderīga, bet tad mēs tajā neuzlikām daudz darba. Tikko mēģiniet šāda pamata komponenta rakstīšana citā komponentu ietvarā. (Un nav taisnīgi, izmantojot burvjus vai citus kodu ģeneratorus, lai izveidotu iesaiņošanas klases vai noklusējuma ieviešanu. Tas nav taisnīgs JavaBeans elegances salīdzinājums ar citu tehnoloģiju.)

The TinyBean klasei nav īpašību (izņemot, iespējams, "nosaukums"), nav notikumu un metožu. Diemžēl joprojām ir viegli nejauši izveidot klases, kas, šķiet, ievēro noteikumus, tomēr nedarbojas pareizi JavaBeans konteinerā, piemēram, BeanBox vai jūsu iecienītākajā IDE (integrētā izstrādes vide).

Piemēram, BeanBox neielādētu mūs TinyBean iepriekš, ja mēs būtu aizmirsuši iekļaut atslēgvārdu publiski klases definīcijai. javac radītu klases failu šai klasei, bet BeanBox atteiktos to ielādēt un (līdz šim laikam vēl nesen) nedos nekādu norādi, kāpēc tā atteiksies. Lai piešķirtu Sun Java cilvēkiem kredītus, BeanBox tagad parasti ziņo par iemeslu, kādēļ pupiņa netiks ielādēta, vai iemeslu, kāpēc īpašums neparādās rekvizītu lapā utt. Vai tomēr nebūtu jauki, ja mums būtu rīks, lai pārbaudītu pēc iespējas vairāk lietu par šādām nodarbībām - un brīdinātu mūs par tiem, kas, lietojot JavaBeans vidē, varētu radīt problēmas? Tas ir mērķis BeanLint: lai palīdzētu jums kā JavaBeans programmētājam analizēt pupiņas to burku failos, meklējot iespējamās problēmas, lai jūs tās varētu novērst, pirms saskaras ar tām testēšanas procesā vai - vēl sliktāk - laukā.

Iespējamās pupiņu problēmas

Kad esmu izstrādājis JavaBeans šai slejai, iespējams, esmu pieļāvis lielāko daļu kļūdu, kuras var pieļaut, rakstot JavaBean. Savā ziņā BeanBox klusums ir spiests mani uzzināt vairāk par pupiņām - un par Java - nekā es citādi. Lielākā daļa JavaBeans izstrādātāju tomēr vēlētos vienkārši ražot strādājošus JavaBeans, kas darbojas pareizi un saglabātu "izaugsmes pieredzi" viņu personīgajai dzīvei. Esmu apkopojis sarakstu ar iespējamām problēmām ar klases failu, kas var izraisīt postījumus ar JavaBean. Šīs problēmas rodas pupiņu iekraušanas procesā konteinerā vai pupiņu izmantošanas laikā. Sērijveidā ir viegli palaist garām detaļas, tāpēc īpašu uzmanību pievēršam serializācijas prasībām.

Šeit ir dažas izplatītas problēmas, kas neizraisa kompilēšanas laika kļūdas, bet var izraisīt arī klases failu būt JavaBean vai nedarbojas pareizi, kad tas ir ielādēts konteinerā:

  • Klasei nav nulles argumentu konstruktora. Tas ir vienkārši iepriekš uzskaitīto prasību pārkāpums, un tā ir kļūda, ar kuru bieži nesastopas iesācēji.

  • Klase netiek ieviesta Serializējams. Tas ir iepriekšminētās otrās prasības pārkāpums, un to ir viegli pamanīt. Klase var prasību īstenot Serializējams, un tomēr neievēro līgumu. Dažos gadījumos mēs varam automātiski noteikt, kad tas ir noticis.

  • Pati klase nav deklarēta publiski.

  • Nodarbību kādu iemeslu dēļ neizdodas ielādēt. Nodarbības dažreiz izmet izņēmumus, kad tās tiek ielādētas. Bieži tas notiek tāpēc, ka citas klases, no kurām tās ir atkarīgas, nav pieejamas ClassLoader objekts, ko izmanto klases ielādēšanai. Šajā rakstā mēs rakstīsim pielāgotu klases iekrāvēju (skat. Zemāk).

  • Klase ir abstrakta. Kaut arī komponentu klase teorētiski varētu būt abstrakta, JavaBean faktiskais darbības gadījums vienmēr ir kādas konkrētas (tas ir, ne abstrakts) klases eksemplārs. Abstraktās klases pēc definīcijas nevar instantizēt, un tāpēc abstraktās klases par kandidātiem neuzskatīsim par pupiņām.

  • Klase ievieš Serializējams, tomēr tajā vai kādā no tā pamatklasēm ir nerserializējami lauki. Noklusētais Java serializācijas mehānisma dizains ļauj klasi definēt kā ievieš Serializējams, bet ļauj tai neizdoties, kad tiek mēģināts serializēt. Mūsu BeanLint klase nodrošina, ka visi atbilstošie a Serializējams klases faktiski ir Serializējams.

Klase, kurai neizdodas kāda no iepriekšminētajām problēmām, var būt diezgan droša, ka tā nedarbosies pareizi kā JavaBean, pat ja ir izpildītas divas sākumā norādītās pupiņu pamatprasības. Pēc tam katrai no šīm problēmām mēs definēsim testu, kas nosaka konkrēto problēmu un ziņo par to. Iekš BeanLint klase, jebkurš klases fails burku failā tiek analizēts dara nokārtot visus šos testus ir pašpārbaudīts (analizēts, izmantojot klasi java.beans.Introspektors), lai izveidotu ziņojumu par pupiņu atribūtiem (rekvizīti, notikumu kopas, pielāgotājs utt.). java.beans.Introspektors ir klase pakete java.beans kas izmanto Java 1.1 refleksijas mehānismu, lai atrastu (vai izveidotu) a java.beans.BeanInfo JavaBean objekts. Mēs atspoguļosim pārdomas un pašpārbaudi nākamajā mēnesī.

Tagad apskatīsim vietnes avota kodu BeanLint lai uzzinātu, kā analizēt potenciālās pupiņu klases.

Iepazīstinām ar BeanLint

"Vecajos labajos laikos" (kas parasti nozīmē "toreiz, kad es vēl domāju, ka es visu zinu") C programmētāji Unix operētājsistēmā izmantos programmu ar nosaukumu savārstījums meklēt iespējamās izpildlaika problēmu vietas viņu C programmās. Par godu šim godājamajam un noderīgajam rīkam es esmu aicinājis savu pazemīgo pupu analīzes klasi BeanLint.

Tā vietā, lai parādītu visu pirmkodu vienā milzīgā, nesagremojamā gabalā, mēs to aplūkosim pa vienam gabalam, un es pa ceļam paskaidrošu dažādas idiomas par to, kā Java rīkojas ar klases failiem. Līdz brīdim, kad būsim cauri, mēs būsim uzrakstījuši klases iekrāvēju, izmantojuši ievērojamu skaitu klašu java.lang.reflect, un ir ieguvuši pamājušu paziņu ar klasi java.beans.Introspektors. Vispirms apskatīsim BeanLint darbībā, lai redzētu, ko tā dara, un tad mēs iedziļināsimies tā ieviešanas detaļās.

Sliktas pupiņas

Šajā sadaļā jūs redzēsiet dažus klases failus ar dažādām problēmām, ar problēmu, kas norādīta zem koda. Mēs izveidosim jar failu, kurā būs šīs klases, un redzēsim, kas BeanLint dara ar viņiem.


importēt java.io. *;

publiskā klase w ievieš Serializējamo {w () {}}

Problēma:

Nulles argumentu konstruktors nav

publiski


publiskā klase x {public x () {}} 

Problēma:

Serializējams.


importēt java.io. *;

publiskā klase y ievieš Serializējamo {publisko y (virkne y_) {}}

Problēma:

Nav nulles argumentu konstruktora.


importēt java.io. *;

z klase ievieš Serializējamu {public z () {}}

Problēma:

Klase nav publiska.


importēt java.io. *; importēt java.awt. *;

u0 klase ievieš Serializējamo {privāto attēlu i; publiskais u0 () {}}

u klase u paplašina u0 ieviešanu Serializējama {public u () {}}

Problēma:

Satur nerserializējamu objektu vai atsauci.


importēt java.io. *;

publiskā klase v paplašina java.awt.Button ievieš Serializable {public v () {} public v (String s) {super (s); }}

Problēma:

Nekas - vajadzētu strādāt labi!


Katrai no šīm topošajām pupiņām, izņemot pēdējo, ir potenciālas problēmas. Pēdējais ir ne tikai pupas, bet darbojas kā viens. Pēc visu šo klašu apkopošanas mēs izveidojam šādu burkas failu:

$ jar cvf BadBeans.jar * .class pievienošana: u.class (in = 288) (out = 218) (deflācija par 24%) pievienošana: u0.class (in = 727) (out = 392) (deflācija 46%, pievienojot: w.class (in = 302) (out = 229) (iztukšots par 24%), pievienojot: x.class (in = 274) (out = 206) (deflated 24%) pievienojot: y.class (in = 362) (out = 257) (deflācija par 29%), pievienojot: z.klase (in = 302) (out = 228) (deflēta 24%), pievienojot: v.class (in = 436) (out = 285) (deflēta 34%) 

Mēs neiekļausim manifesta failu (kas ir fails burkas faila iekšpusē, kas apraksta burka faila saturu - skatiet sadaļu "Burka atvēršana" zemāk) burkas failā, jo BeanLint nenodarbojas ar manifestu failiem. Parsējot manifesta failu un salīdzinot to ar burkas saturu, tas būtu interesants vingrinājums, ja vēlaties ko pagarināt BeanLint var darīt.

Skrienam BeanLint uz burkas faila un skatiet, kas notiek:

=== Klases u0 analizēšana === klase u0 nav JavaBean, jo: klase nav publiska

=== Z z klases analīze === z z nav JavaBean, jo: klase nav publiska

=== Klases y analīze === y klase nav JavaBean, jo: tai nav nulles argumentu konstruktora

=== Klases x analizēšana === klase x nav JavaBean, jo: klase nav seriālizējama

=== Klases w analīze === klase w nav JavaBean, jo: tā nulles argumentu konstruktors nav publisks

=== Analizējot v klasi === Piezīme: java.awt.Button definē pielāgoto serializāciju Piezīme: java.awt.Component definē pielāgoto serializāciju v iztur visus JavaBean testus

Introspekcijas pārskats -------------------- Klase: v Pielāgotāja klase: nav

Rekvizīti: Būla iespējota {isEnabled, setEnabled} (... vēl daudz īpašību)

Pasākumu kopas: java.awt.event.MouseListener pele (... vēl daudz pasākumu kopu)

Metodes: publiskā būla java.awt.Component.isVisible () (... daudzi, daudzi vairāk metožu - shesh!)

=== v klases beigas ===

=== Klases u analīze === klase u nav JavaBean, jo: šādus klases laukus nevar serizēt: klase java.awt.I attēls (definēts u0) === klases u beigas ===

Izeja ir nedaudz saīsināta, jo notikumu kopu un metožu saraksts ir ļoti garš, mūsu diskusijai šeit neko daudz nepievieno. Failā output.html varat redzēt visu izvadi, ja vēlaties iegūt priekšstatu par daudzumiem BeanLint izliek.

Ievērojiet to BeanLint pareizi identificēja problēmas ar sliktās klases failiem:

u0 klase nav JavaBean, jo: klase nav publiska klase z nav JavaBean, jo: klase nav publiska klase y nav JavaBean, jo: tai nav nulles argumenta konstruktora klase x nav JavaBean, jo: klase nav serializējama klase w nav JavaBean, jo: tās nulles argumentu konstruktors nav publisks. klase u nav JavaBean, jo: šādi klases lauki nav seriālizējami: klase java.awt.Image i (definēts u0) 
$config[zx-auto] not found$config[zx-overlay] not found