1

I'm trying to get the library BioJava to work inside an OSGi context.

To get the JAR into the OSGi context, I'm using the Maven plugin p2-maven-plugin, which generates a file Manifest.MF, and the part relevant to the exception I'm facing is:

Bundle-SymbolicName: org.biojava.core
Bundle-Version: 5.3.0
Import-Package: [snip],
 org.slf4j;resolution:=optional,
 [snap]

Which looks okay to me. However when I access a class that uses slf4j I get the titular exception:

java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
    at org.biojava.nbio.core.sequence.template.AbstractCompoundSet.<clinit>(AbstractCompoundSet.java:40)
    at org.biojava.nbio.core.sequence.io.ABITrace.getSequence(ABITrace.java:179)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory cannot be found by org.biojava.core_5.3.0
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:511)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:422)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:414)

Now it's easy to find this exception everywhere, because a lot of people have tried (and failed) to install slf4j. I checked sites like the documentation or the SO question ClassNotFoundException: org.slf4j.LoggerFactory and hence tried to add the following bundles:

  • slf4j-simple
  • slf4j-log4j12 (plus the log4j dependencies)
  • pax-logging-log4j2

However neither worked. Maybe the OSGi container is having problems, but slf4j JARs have the bundle information with the export packages out of the box, so I'm assuming these work. And the BioJava JAR has an import package, so I have no idea why it wouldn't be able to find the class.

Oh, I checked, the LoggerFactory is present in slf4j-api, so it's not that, either.

I also tried different start levels and autostart for the implementations. And I rebundled the JAR without the optional dependency, but I keep having problems because now the MD5 hash is broken.

Has anybody managed to get slf4j to work in OSGi? Or failing that, is there any way to replace that stupid dependency with some kind of Java proxy so I will not need the broken dependency anymore?

Stefan S.
  • 3,950
  • 5
  • 25
  • 77
  • Instead of Slf4J (and actual logging framework) please install pax-logging-api bundle (and e.g., pax-logging-log4j2). pax-logging-api provides you (exports) all required packages. – Grzegorz Grzybek Feb 04 '20 at 18:31
  • @GrzegorzGrzybek I tried [org.ops4j.pax.logging:pax-logging-api:jar:2.0.2](https://mvnrepository.com/artifact/org.ops4j.pax.logging/pax-logging-api/2.0.2) and the log4j bundle and there's the same exception. – Stefan S. Feb 04 '20 at 21:27

1 Answers1

0

resolution:=optional means that when the bundle resolves, it will either get access to the package or not. The framework is permitted to resolve the bundle without access to the package. If the bundle needs access to the package, why make resolution of the package optional?

BJ Hargrave
  • 9,324
  • 1
  • 19
  • 27
  • [This SO question](https://stackoverflow.com/questions/20352400/difference-between-import-package-resolution-optional-and-no-dependency-at-all) explains it quite well, including _"Normally a need for optional dependencies indicates that your bundle has poor coherency"_ However, this does not explain a) why the bundle cannot access the class even though it *is* present and b) how to fix my problem. – Stefan S. Feb 05 '20 at 08:13
  • @bj-hargrave is right. when you specify `resolution:=optional` it means that you're bundle will get resolved (and started) without active _wire_ to a bundle providing this `org.slf4j` package. Even if (later) such bundle is installed, until you _refresh_, your bundle won't be able to load any class from this package. – Grzegorz Grzybek Feb 05 '20 at 08:32
  • @GrzegorzGrzybek Okay so it should be as easy as starting the bundle with the package `org.slf4j` before the one with the optional dependency? Or won't it get wired then either? – Stefan S. Feb 05 '20 at 08:37
  • If you install your bundle and pax-logging-api at the same start level and then let Felix (or Equinox) progress to this level, OSGi resolution will _wire_ your bundle with pax-logging-api. – Grzegorz Grzybek Feb 05 '20 at 12:08
  • As I said, `resolution:=optional` tells the framework your bundle does not require the package and it is entirely permissible for the framework to resolve your bundle without access to the package, even if the package is exported in the system. If your bundle requires a certain package to properly function, do not use `resolution:=optional` for the package. – BJ Hargrave Feb 05 '20 at 13:24