Co sa tyka zmeny tychto pristupovych prav - kedy je to dobre vyuzit? Tym sa pytam nielen na to "kedy sa to hodi", ale aj na kvalitu kodu a opravnenu kritizovatelnost ostatnymi.
Ja som to raz pouzil na zmenu fungovania nejakej final triedy poskytovanej Javou a dostalo sa mi za to len niekolko nepeknych slov od veduceho. Pritom stacilo zavolat privatnu metodu a moja zmena potom fungovala dobre, co som preveril aj citanim zdrojakov.
Tak to nakoniec skoncilo vykopirovanim zdrojaku triedy von a malou zmenou - aj tak to ale nie je presne to, co by som si predstavoval ako riesenie.
pouzil som raz, ked vo Velmi Rozsiahlom Projekte(tm) bola trieda, kde som musel nainjectovat vlastnu instanciu triedy kvoli testovaniu a prapovodny autor 10 rokov dozadu nemohol uvazovat, ze take nieco sa stane: a modul kvoli politickym rozhodnutiam (zavislosti, release management) sa nemohol zmenit. veduci odsuhlasil.
toto je ale nudzove riesenie: ako hovori clanok, stavane na okrajove pripady, ked nie su zdrojaky, treba testovat/mockovat a nie je ako a podobne pripady, ked ten, kto reflektuje a javassistuje naozaj vie, preco to robi a niet inej cesty.
Mam jeden priklad ze zivota, ktery se asi podoba Vasemu problemu:
- programatori napsali testy, v nichz vyplnovali tabulky na zaklade hodnoty ziskane volanim Math.random(). Ty testy mely puvodne jen ukazat, ze se na GUI "neco" zobrazuje, ale ve chvili, kdy se zacalo testovat i to, "co" se skutecne zobrazuje, to zpusobilo problemy. Jenze Math.random() nelze pretizit, protoze java.lang.Math je finalni. Takze tri zpusoby reseni:
1) prepsat testy (byly ovsem dodany externisty, moc prace)
2) zkopirovat knihovnu java.lang.Math jinam, prepsat random() aby vracel nenahodne hodnoty a pouzit -Xbootclasspath (problem pri nasazeni na aplikacni server)
3) Javassistem si trosku pohrat s tridou java.lang.Math, coz je nejjednodussi reseni, nikde se nemusely delat zmeny v testech ani jinde ve zdrojacich
Jinak je skutecne dobre upozornit, ze zmeny pomoci Javassistu jsou, stejne jako pouziti Reflection API, trosku problematicke, uz jen proto, ze se tezko dohledava kdo napriklad vola nejakou metodu (IDE dobre najdou prime volani a to i ve slozite hierarchii trid, ale volani neprime je horsi). Takze: Javassist je silny nastroj, ale opatrne :)
reflexia je o tom, ze za behu sa mozno dopytovat na vlastnosti (= instancne premenne + metody) lubovolnej triedy
alebo viem zobrat lubovolnu premennu, zistit pocas behu jej typ (typicky triedu) a opat sa dopytovat na jej premenne a metody.
ta trieda za behu je reprezentovana objektom typu java.lang.Class
Nevim jestli odpovim presne na otazku, ale zkusim:
Trida ve smyslu semantiky Javy neni objekt, na rozdil od nekterych jinych jazyku, ktere maji koncept metatrid (metaclass) - asi nejznamejsi dnes bude Objective-C a Python.
Kdyz zavolate nejaka_trida.class nebo nejaka_instance.getClass(), tak dostanete objekty typu (=instance tridy) java.lang.Class, coz je objekt popisujici vlastnosti tridy, ovsem tezko se v Jave vytvari uplne nova trida mimo prekladac - jsou nejake moznosti (Javassist, ClassLoader.defineClass, JVM TI ...).