[slf4j-dev] [JIRA] Updates for SLF4J-586: MANIFEST.MF exports a package with a former version number
slf4j developers list
slf4j-dev at qos.ch
Wed Mar 29 20:27:00 CEST 2023
SLF4J / SLF4J-586 [Open]
MANIFEST.MF exports a package with a former version number
==============================
Here's what changed in this issue in the last few minutes.
There is 1 comment.
View or comment on issue using this link
https://jira.qos.ch/browse/SLF4J-586
==============================
1 comment
------------------------------
Hannes Wellmann on 29/Mar/23 20:15
TL;DR: It looks like org.ops4j.pax.logging.pax-logging-api is to blame for the problems you encountered because they have incorrect OSGi metadata.
> >... it depends how 'greedy' the resolver of your OSGi runtime
> To my knowledge, there are only two OSGi runtimes implementation: Apache Felix and Eclipse Equinox, so it should be tested in both environments.
According to Wikipedia there are more, but the ones you mentioned are probably the most relevant ones (AFAIK). Nevertheless even in Equinox we use the Felix Resolver: https://github.com/eclipse-equinox/equinox/tree/master/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver
Thank you @frederic.fays for the details.
In order to verify that from slf4j side everything works as expected I created a little Eclipse application (using the Equinox OSGi framework) which, besides the basics for the Eclipse Platform and lockback 1.2 and 1.3 bindings/providers, has mainly two Bundles A and B with the following MANIFEST.MF files:
{code:java}
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: bundle.a
Bundle-Version: 1.0.0.qualifier
Import-Package: org.slf4j;version="[1.7.0,2.0.0)"{code}
{code:java}
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: bundle.b
Bundle-Version: 1.0.0.qualifier
Import-Package:
org.slf4j;version="[1.7.0,2.0.0)",
org.slf4j.spi;version="[1.7.0,2.0.0)" {code}
Within the launched application I used the Felix GoGo Shell to analyse the resulting wiring within the Framework:
{code:java}
g! p org.slf4j
osgi.wiring.package; bundle-symbolic-name="slf4j.api"; bundle-version:Version="2.0.7"; version:Version="1.7.36"; osgi.wiring.package="org.slf4j"; uses:="org.slf4j.event,org.slf4j.helpers,org.slf4j.spi"<slf4j.api_2.0.7 [319]>
bundle.a_1.0.0.qualifier [4] imports
osgi.wiring.package; bundle-symbolic-name="slf4j.api"; bundle-version:Version="1.7.36"; version:Version="1.7.36"; osgi.wiring.package="org.slf4j"<slf4j.api_1.7.36 [320]>
bundle.b_1.0.0.qualifier [5] imports
ch.qos.logback.classic_1.2.12 [7] imports
osgi.wiring.package; bundle-symbolic-name="slf4j.api"; bundle-version:Version="2.0.7"; version:Version="2.0.7"; osgi.wiring.package="org.slf4j"; uses:="org.slf4j.event,org.slf4j.helpers,org.slf4j.spi"<slf4j.api_2.0.7 [319]>
ch.qos.logback.classic_1.3.6 [6] imports
org.apache.httpcomponents.client5.httpclient5_5.1.3.v20221013-1742 [45] imports
org.eclipse.jetty.util_10.0.13 [206] imports
...
{code}
This shows that Bundle A, which only imports the package {{org.slf4j}} below 2, is wired to the {{org.slf4j}} package from bundle {{slf4j.api}} version 2, while Bundle B, which imports {{org.slf4j}} and {{org.slf4j.spi}} below version 2, is wired to the {{org.slf4j}} package from the {{slf4j.api}} bundle in version 1.7.
So in this case, when only the official {{slf4j.api}} bundle is used, everything works fine as expected and intended.
Good for me, but the question remains why it does not work for you and after looking into the Manifest.MF in the jar of pax-logging-api:2.2.2 I noticed the following Export-Package entry:
{code:java}
Export-Package:
org.slf4j;version="2.0.6";provider=paxlogging;uses:="org.slf4j.event,org.slf4j.helpers,org.slf4j.spi",
org.slf4j;version="1.7.36";provider=paxlogging,
org.slf4j;version="1.6.6";provider=paxlogging,
org.slf4j;version="1.5.11";provider=paxlogging,
org.slf4j;version="1.4.3";provider=paxlogging,
org.slf4j.event;version="1.7.36";provider=paxlogging,
org.slf4j.event;version="2.0.6";provider=paxlogging;uses:="org.slf4j,org.slf4j.helpers",
org.slf4j.helpers;version="1.7.36";provider=paxlogging,
org.slf4j.helpers;version="1.6.6";provider=paxlogging,
org.slf4j.helpers;version="1.5.11";provider=paxlogging,
org.slf4j.helpers;version="1.4.3";provider=paxlogging,
org.slf4j.helpers;version="2.0.6";provider=paxlogging;uses:="org.slf4j,org.slf4j.event,org.slf4j.spi",
org.slf4j.spi;version="1.7.36";provider=paxlogging,
org.slf4j.spi;version="1.6.6";provider=paxlogging,
org.slf4j.spi;version="1.5.11";provider=paxlogging,
org.slf4j.spi;version="1.4.3";provider=paxlogging,
org.slf4j.spi;version="2.0.6";provider=paxlogging;uses:="org.slf4j,org.slf4j.event,org.slf4j.helpers",
...{code}
It looks like pax-logging-api is doing something similar like slf4j-api, but the metadata are incorrect respectively insufficient. First of all as we have discussed in SLF4J-579 only the package org.slf4j is backwards compatible. So given that the embedded class files are shaded/copied from slf4j.api 2.0.6, exporting org.slf4j.event/helpers/event in any version below 2 is wrong, since some classes/methods are binary incompatible. This is the reason, why the slf4j.api bundles does not export them and I think that is the root of the problem here.
In general it is not a problem in OSGi to re-bundle packages from other Bundles/Plugins as long as all packages are versioned correctly (following SemVer rules) have uses-constriaints and consumers only use Import-Package and not Require-Bundle. Then the actual bundle is just an exchangeable hull (which is even one design-goal of the Import/Export-Package mechanism if not OSGi). To quote a stackoverflow answer ([https://stackoverflow.com/a/7476016):|https://stackoverflow.com/a/7476016)]
{code:java}
An OSGi application will not throw ClassNotFoundExceptions and NoClassDefFoundErrors if your manifest is correct. That is, you need to tell OSGi which packages your bundle uses; if you don't do this correctly or honestly, then OSGi cannot help you. In other words: GIGO (Garbage In, Garbage Out).{code}
And in my opinion at least the metadata of pax-logging-api are wrong.
However after skimming over your linked issue, [https://github.com/ops4j/org.ops4j.pax.logging/issues/518] respectively [https://github.com/ops4j/org.ops4j.pax.logging/issues/519] it looks like the pax-logging devs are aware of what they are doing and they are doing it on purpose and since I believe they are reasonable people they probably do it for a reason. I'm not familiar with the exact Karaf/Pax/Container environment and did read the discussion in detail and therefore cannot assess their decision. But my naive first attempt would be, instead of shading/repacking the api classes from all supported facades into a own bundle, use the original (multiple) api bundles and provide a custom logging implementation/binding/provider that is wired to all the facades and does the redirection magic to whatever target or other logging-backend is intended. Basically just like all the other logging-backends and bridges work. But probably the pax-logging devs have considered that as well and had a reason to not do that.
So to solve your issue I suggest you do what was suggested in [https://github.com/ops4j/org.ops4j.pax.logging/issues/518#issuecomment-1488132088] and simply not include the slf4j.api in your application. As far as I understand it, in your scenario it is not wanted any way and the pax-logging-api is intended as replacement for the slf4j.api bundle.
Nevertheless I'm still not sure if that would change something for you, because with the latest pax-logging-api:2.2.2 you have a bundle that exports the {{org.slf4j}} package in multiple versions above and below two too and even the other {{org.slf4j.X}} packages in multiple versions. So even without slf4j.api, you would be in a similar scenario. Sorry, that is probably frustrating for you.
Can you try the pax-logging 2.2.2 api and logback with slf4j.api 2.0.5? Version 2.0.5 export the package org.slf4j package only in version 2.0.x.
If you have a Felix GoGo shell in your app, it would probably also be interesting to see the OSGi wires of the org.slf4j package. You can use the command I used above ({{{}g! p org.slf4j{}}}). Maybe the karaf runtime has something similar built in.
But again, I'm convinced that the slf4j.api metadata are correct and work as intended as shown above and that you face the problems because of the specialities of pax-logging.
==============================
This message was sent by Atlassian Jira (v9.6.0#960000-sha1:a3ee8af)
More information about the slf4j-dev
mailing list