OSGi und die ClassNotFound-Exception

Stolperstein beim Experimentieren mit Gradle uns OSGi

I had a pro­blem ma­na­ging n mo­du­les, so I thought “I just use OSGi”. Now I have n² pro­blems…

Für ein Ex­pe­ri­ment woll­te ich mein Ja­va­pro­gramm in „echte“ Mo­du­le ein­tei­len. OSGi ist da als Ge­dan­ke na­he­lie­gend, und da es in Grad­le OS­Gi-Sup­port gibt, klang das nach einem viel­ver­spre­chen­den An­satz: Im­mer­hin deckt das Build­sys­tem Grad­le be­reits das ganze De­pen­den­cy-Ma­nage­ment ab, und das OS­Gi-Mo­dul ver­sprach eine ma­nu­el­le Pfle­ge der De­pen­den­cies (nichts an­de­res steht ja in einem Bund­le-Ma­ni­fest) über­flüs­sig zu ma­chen. Also flugs ein Mul­ti-Pro­ject-Build auf­ge­setzt:

  • main für das ei­gent­li­che Haupt­pro­gramm, wel­ches die Mo­du­le läd
  • in­ter­face für die ge­mein­sam ver­wen­de­ten In­ter­face-Klas­sen
  • ser­vice1 und ser­vice2 als zwei Test-Bund­les

Das OS­Gi-Plu­gin kennt zwar die OS­Gi-An­no­ta­tio­nen nicht, aber der Old-School-Weg mit der Ac­tiva­tor-Klas­se ist kein so gro­ßer Ab­strich.

Grad­le und OSGi: Schon nicht schlecht…

Lei­der mach­te das OS­Gi-Plu­gin von Grad­le nicht ganz so viel, wie ich mir ge­wünscht hätte: Es trägt zwar die Ab­hän­gig­kei­ten, die als OS­Gi-Bund­le er­kannt wer­den, in das OS­Gi-Ma­ni­fest ein, aber die rest­li­chen (nicht-OS­Gi) JARs wer­den lei­der nicht wei­ter be­han­delt. Ich habe lei­der keine Mög­lich­keit ge­fun­den, diese au­to­ma­tisch mit in das JAR des Mo­duls hin­ein­zu­pa­cken.

Dies führ­te im ers­ten An­lauf zu dem Pro­blem, daß beim Laden des Bund­les die In­ter­face-Klas­sen nicht ge­fun­den wur­den. Aber da die In­ter­faces ja oh­ne­hin ge­zwun­ge­ner­ma­ßen iden­tisch sein müs­sen, kann man die nicht ge­mein­sam nut­zen?

Ein fie­ses De­tail…

In der Tat, man kann: Mit Hilfe des Kon­fi­gu­ra­ti­ons­pa­ra­me­ters org.osgi.framework.system.packages.extra kann man beim In­itia­li­sie­ren des OS­Gi-Frame­works be­stimm­te Pa­cka­ges aus der „Wirts­um­ge­bung“ in die Bund­les ex­po­nie­ren. Das klang nach einer Lö­sung mei­nes Pro­blems, die Bund­les wur­den an­stands­los ge­la­den – und stol­per­ten dann über eine ClassNotFoundException: An­geb­lich wäre die Klas­se mei­nes Bund­le Ac­tiva­tors nicht auf­find­bar. Mehr­fa­ches Prü­fen der Namen ergab keine Ver­bes­se­rung.

Ei­ni­ge ver­zwei­fel­te Zeit spä­ter dann die Ent­de­ckung: Mit Hilfe der obi­gen Kon­fi­gu­ra­ti­on wer­den nicht (wie von mir ver­mu­tet) die Klas­sen den Bund­les zu­sätz­lich zur Ver­fü­gung ge­stellt, das Pa­cka­ge über­la­gert mög­li­cher­wei­se vor­han­de­ne Klas­sen im sel­ben Pa­cka­ge im Bund­le. Ich hatte ver­se­hent­lich den glei­chen Pa­cka­ge-Na­men für die Ac­tiva­tor-Klas­se ver­wen­det.

Merke also: Bei einem sol­chen Stunt Un­be­dingt un­ter­schied­li­che Pa­cka­ge-Na­men ver­wen­den (was ja ei­gent­lich oh­ne­hin guter Ton ist).

Di­ver­se OS­Gi-Im­ple­men­tie­run­gen und Java 8

Ich habe das Pro­jekt­se­t­up und das Pro­blem in etwas Bei­spiel­code fi­xiert. Das Pro­jekt kann man ent­we­der bei git­hub an­se­hen oder sich als zip her­un­ter­la­den. In den Build-Da­tei­en sieht man noch aus­kom­men­tiert den Eclip­se-OS­Gi-Con­tai­ner. Bei mei­nen Ex­pe­ri­men­ten hatte ich zwi­schen Apa­che Felix und em Eclip­se-Con­tai­ner hin- und her­ge­wech­selt. Dabei stell­te sich her­aus, daß der Eclip­se-Con­tai­ner of­fen­bar ein Pro­blem mit Ja­va-8-Class­files hat.

Fazit

Bleibt fest­zu­hal­ten:

  • In den Mo­du­len an­de­re Pa­cka­gena­men ver­wen­den (der Mo­dul­na­me in den Pa­cka­ge-Pfad auf­zu­neh­men macht ja auch Sinn)
  • Grad­le und OSGi ist schon recht kom­for­ta­bel, aber man könn­te sich noch das ein oder an­de­re Fea­ture wün­schen
  • Die von mir ge­tes­te­ten al­ter­na­ti­ven OS­Gi-Plug­ins für Grad­le, wel­che die OS­Gi-An­no­ta­tio­nen par­sen wür­den, kom­men noch nicht mit Java 8 klar
  • Apa­che Felix funk­tio­niert mit Java 8
  • Not­hing is ever easy :-)