javax:javaee-api – NEM HASZNÁLATRA

Posted by | · · · · | Szoftverfejlesztés | Nincs hozzászólás a(z) javax:javaee-api – NEM HASZNÁLATRA bejegyzéshez

A JAVA EE specifikációnak az API-ját definiáló jar (javax:javaee-api:6.0 maven artifact, és a javaee-web-api is) meglepően viselkedik. Elég csak ennyit beírni a keresőbe: ‘Absent Code javaee‘, és látszik, hogy elég sokan belefutottak már ebbe a problémába, szerintem gyakorlatilag mindenki, aki hello world-nél összetettebb dolgot írt már JAVA EE-ben, és azt tesztelni is akarta.
Egységtesztek futtatásakor egy JAVA EE projektben egzotikus kivételbe futhatunk. “java.lang.ClassFormatError: Absent Code”.

Írják az okot is több helyen. A jar-ban lefordított osztályokból hiányoznak a metódusok kódjai. Azaz a metódusok teste.
A deklaráció megvan, ezért fordítani lehet vele, de amint betöltené a JVM futáskor, hibát fog generálni. Az alkalmazásszerveren pedig, mivel ott minden megvan egyben, jól megy minden.

Gyors megoldás

A gyors megoldás pofon egyszerű. Legalábbis Maven oldalon tudom biztosan. Olyan sorrendben kell felvenni a pom.xml-ben a függőségeket, hogy az api-t megelőzze egy másik test scope-os függőség, amiben megvannak ezek a hiányzó kódok. Így a classpath betöltési sorrendben az kerül előrébb, tehát onnan töltődnek be az osztályok a teszt során. Például ha az embedded glassfish megelőzi, akkor minden jóra fordul. És általában még jól is jön, mert sanszos, hogy integrációs teszteket is akar az ember futtatni. Ha több alkalmazásszerverre is kell integrációs teszt, akkor már ez összetettebb ügy, ott már jobban kell érteni mi folyik itt.

Értetlenség

jackie-chan-meme

Valami sárga fény villog a műszerfalon. Mit jelent az, hogy hiányzik a metódus teste? A forráskódban még tuti megvolt nekik, különben le sem fordult volna.
Ilyen állat pedig nincs.
Azzal magyaráztam magamnak, hogy függ az api az implementációtól. Csak így fordulhatott le. Részletkérdés hogy ez lehetetlen, és a hibát sem magyarázza, de magának sok mindent elhisz az ember…
Amíg egyik munkatársam meg nem kérdezte, hogy akkor ez nem körkörös függőség? A válaszom frappánsan kb. annyi volt, hogy ‘ izé… ‘

A jó válasz talán itt van meg a legrészletesebben: https://community.jboss.org/wiki/WhatsTheCauseOfThisExceptionJavalangClassFormatErrorAbsentCode

Felismerés

Az akkori Sun-nál jól lefordították az api-t, majd manipulálták (nem tudom mivel) az előállt byte kódot úgy, hogy minden metódus kódját törölték. Aztán ezt a kiherélt verziót publikálták. Az előbb belinkelt oldalon található idézet szerint mindezt csupa jó szándékból. Nehogy már figyelmetlenségből az api-val futtassa az egyszeri programozó a cuccát.

Ilyen van? Nehéz elhinni, ezért visszafordítottam a jar-t. És van!

Minden osztályban üres metódusokat tudott csak adni a decompiler. Tele van olyan konkrét osztállyal, mi egy absztrakt osztályból származik, és az absztrakt metódusok-nak csak a deklarációja van meg. Komolyan gondolták, hogy semmi implementáció. Ez egy api.

Más elképzelés szerint egy ilyen húzásnak politikai, illetve jogi okai lehetnek. http://www.adam-bien.com/roller/abien/entry/trouble_with_crippled_java_ee

Nekem az első magyarázat jobban bejön. Ez biztos jó okkal van így. Igazából énértem van. Egyébként is, milyen jó mikor megérti az ember, hogy miért szívott órákat.

Az is jó, hogy megértettem mit különcködik mindegyik alkalmazásszerver. Mindegyik saját JAVA EE API-t csinál. Nem volt más választásuk, minthogy megcsinálják a JAVA EE API használható, azaz nem kiherélt változatát is.
Az oracle-nél (anno sun) nem csináltak használható verziót a glassfish-hez. Gondolom, hogy magukkal ne keveredjenek ellentmondásba.

Megoldás

Szerencsére több nyílt forrású projekt is kiadta ezeket az API-kat. Például:

jboss – org.jboss.spec:javaee-api
Minden arquillian-os leírás ezt ajánlja. A pom.xml-ben ezzel jövünk ki a legrövidebben. De mivel ez csak egy pom függőség, valójában nem egy függőséget adunk a projektez, hanem minden jsr-hez egyet. Az IDE-ben zavaró lehet, hogy elárasztjuk a dependency listát, de lehet vele élni. A JAVA EE ilyen.

geronimo – org.apache.geronimo.specs:*
Náluk minden jsr külön artifact, nem listáznám be. Viszont lehet válogatni pontosan melyik kell.

tomee/openejb – org.apache.openejb:javaee-api
Gyakorlatilag egybeszedték a geronimo-s artifactokat. Ez egy jar függőség, tehát összemásolták. Így csak egy plusz függőségünk lesz. Valami okból a mail-t nem tették bele. De a ‘org.apache.geronimo.specs:geronimo-javamail_1.4_spec’ -t be lehet húzni pluszban.

Elnézést, ha valamelyiket kihagytam, ennél többen vannak, de ezekhez volt szerencsém.

Tanulság

Elértünk a bejegyzésem egyetlen tanulságához, amit egyébként máshol is leírnak. Csak már el is hiszem, ezért én is leírhatom.

Ne használd a javax:javaee-api -t.

Az csak egy etalon. Olyan mint a méterrúd, nem használatra van. Colstokot kell használni. Viszont bármelyik másik JAVA EE-API-t használhatod. Még akkor is, ha a projektednek semmi köze ahhoz az alkalmazásszerverhez, aminek a JAVA EE API-ját használod. Csak a specifikációt testesíti meg.

Biztos ami biztos alapon arra azért ügyelj, hogy az api a legutolsó legyen a classpath betöltési sorrendben. Több  profil, és szülő projekt esetén jól kell ismerni a maven-t, de ez már más téma.


No Comments

Leave a comment